mirror of https://github.com/portainer/portainer
fix(swarm): fix the Host field when listing images (#369)
Co-authored-by: andres-portainer <andres-portainer@users.noreply.github.com>release/2.27.0-rc3
parent
3c6f61134e
commit
9e04145875
|
@ -3,8 +3,8 @@ package client
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"maps"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -141,7 +141,6 @@ func createAgentClient(endpoint *portainer.Endpoint, endpointURL string, signatu
|
||||||
|
|
||||||
type NodeNameTransport struct {
|
type NodeNameTransport struct {
|
||||||
*http.Transport
|
*http.Transport
|
||||||
nodeNames map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NodeNameTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
func (t *NodeNameTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
@ -176,18 +175,19 @@ func (t *NodeNameTransport) RoundTrip(req *http.Request) (*http.Response, error)
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
t.nodeNames = make(map[string]string)
|
nodeNames, ok := req.Context().Value("nodeNames").(map[string]string)
|
||||||
for _, r := range rs {
|
if ok {
|
||||||
t.nodeNames[r.ID] = r.Portainer.Agent.NodeName
|
for idx, r := range rs {
|
||||||
|
// as there is no way to differentiate the same image available in multiple nodes only by their ID
|
||||||
|
// we append the index of the image in the payload response to match the node name later
|
||||||
|
// from the image.Summary[] list returned by docker's client.ImageList()
|
||||||
|
nodeNames[fmt.Sprintf("%s-%d", r.ID, idx)] = r.Portainer.Agent.NodeName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *NodeNameTransport) NodeNames() map[string]string {
|
|
||||||
return maps.Clone(t.nodeNames)
|
|
||||||
}
|
|
||||||
|
|
||||||
func httpClient(endpoint *portainer.Endpoint, timeout *time.Duration) (*http.Client, error) {
|
func httpClient(endpoint *portainer.Endpoint, timeout *time.Duration) (*http.Client, error) {
|
||||||
transport := &NodeNameTransport{
|
transport := &NodeNameTransport{
|
||||||
Transport: &http.Transport{},
|
Transport: &http.Transport{},
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package images
|
package images
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/portainer/portainer/api/docker/client"
|
|
||||||
"github.com/portainer/portainer/api/http/handler/docker/utils"
|
"github.com/portainer/portainer/api/http/handler/docker/utils"
|
||||||
"github.com/portainer/portainer/api/set"
|
"github.com/portainer/portainer/api/set"
|
||||||
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
httperror "github.com/portainer/portainer/pkg/libhttp/error"
|
||||||
|
@ -46,17 +47,16 @@ func (handler *Handler) imagesList(w http.ResponseWriter, r *http.Request) *http
|
||||||
return httpErr
|
return httpErr
|
||||||
}
|
}
|
||||||
|
|
||||||
images, err := cli.ImageList(r.Context(), image.ListOptions{})
|
nodeNames := make(map[string]string)
|
||||||
|
|
||||||
|
// Pass the node names map to the context so the custom NodeNameTransport can use it
|
||||||
|
ctx := context.WithValue(r.Context(), "nodeNames", nodeNames)
|
||||||
|
|
||||||
|
images, err := cli.ImageList(ctx, image.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httperror.InternalServerError("Unable to retrieve Docker images", err)
|
return httperror.InternalServerError("Unable to retrieve Docker images", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the node name from the custom transport
|
|
||||||
nodeNames := make(map[string]string)
|
|
||||||
if t, ok := cli.HTTPClient().Transport.(*client.NodeNameTransport); ok {
|
|
||||||
nodeNames = t.NodeNames()
|
|
||||||
}
|
|
||||||
|
|
||||||
withUsage, err := request.RetrieveBooleanQueryParameter(r, "withUsage", true)
|
withUsage, err := request.RetrieveBooleanQueryParameter(r, "withUsage", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httperror.BadRequest("Invalid query parameter: withUsage", err)
|
return httperror.BadRequest("Invalid query parameter: withUsage", err)
|
||||||
|
@ -86,7 +86,11 @@ func (handler *Handler) imagesList(w http.ResponseWriter, r *http.Request) *http
|
||||||
|
|
||||||
imagesList[i] = ImageResponse{
|
imagesList[i] = ImageResponse{
|
||||||
Created: image.Created,
|
Created: image.Created,
|
||||||
NodeName: nodeNames[image.ID],
|
// Only works if the order of `images` is not changed between unmarshaling the agent's response
|
||||||
|
// in NodeNameTransport.RoundTrip() (api/docker/client/client.go)
|
||||||
|
// and docker's cli.ImageList()
|
||||||
|
// As both functions unmarshal the same response body, the resulting array will be ordered the same way.
|
||||||
|
NodeName: nodeNames[fmt.Sprintf("%s-%d", image.ID, i)],
|
||||||
ID: image.ID,
|
ID: image.ID,
|
||||||
Size: image.Size,
|
Size: image.Size,
|
||||||
Tags: image.RepoTags,
|
Tags: image.RepoTags,
|
||||||
|
|
Loading…
Reference in New Issue