mirror of
https://github.com/portainer/portainer.git
synced 2026-08-07 10:54:48 +00:00
fix(swarm): no image error for Docker private registry [BE-13217] (#3191)
This commit is contained in:
@@ -239,10 +239,12 @@ func deployStack(ctx context.Context, dockerCLI *command.DockerCli, filePaths []
|
||||
return err
|
||||
}
|
||||
|
||||
registries := normalizeRegistryServerAddresses(options.Registries)
|
||||
|
||||
return deployServices(
|
||||
ctx,
|
||||
dockerCLI.Client(),
|
||||
options.Registries,
|
||||
registries,
|
||||
services,
|
||||
namespace,
|
||||
options.PullImage,
|
||||
@@ -396,6 +398,23 @@ func createConfigs(ctx context.Context, apiClient client.APIClient, configs []sw
|
||||
return nil
|
||||
}
|
||||
|
||||
// normalizeRegistryServerAddresses returns a copy of registries with each ServerAddress
|
||||
// rewritten so it matches the domain encodeRegistryAuth resolves for docker.io images
|
||||
// (dockerregistry.IndexServer).
|
||||
func normalizeRegistryServerAddresses(registries []configtypes.AuthConfig) []configtypes.AuthConfig {
|
||||
normalized := make([]configtypes.AuthConfig, len(registries))
|
||||
|
||||
for i, r := range registries {
|
||||
if r.ServerAddress == "" || r.ServerAddress == dockerregistry.DefaultNamespace {
|
||||
r.ServerAddress = dockerregistry.IndexServer
|
||||
}
|
||||
|
||||
normalized[i] = r
|
||||
}
|
||||
|
||||
return normalized
|
||||
}
|
||||
|
||||
// encodeRegistryAuth finds the registry credentials for the given image and returns
|
||||
// the base64-encoded auth string expected by the Docker service API.
|
||||
// Returns an empty string (no error) when no matching credentials are found.
|
||||
|
||||
@@ -256,6 +256,63 @@ func Test_encodeRegistryAuth(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_normalizeRegistryServerAddresses(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
registries []configtypes.AuthConfig
|
||||
expectedReturned []configtypes.AuthConfig
|
||||
}{
|
||||
{
|
||||
name: "empty ServerAddress is normalized to IndexServer",
|
||||
registries: []configtypes.AuthConfig{{ServerAddress: "", Username: "user"}},
|
||||
expectedReturned: []configtypes.AuthConfig{{ServerAddress: dockerregistry.IndexServer, Username: "user"}},
|
||||
},
|
||||
{
|
||||
name: "docker.io default namespace is normalized to IndexServer",
|
||||
registries: []configtypes.AuthConfig{{ServerAddress: dockerregistry.DefaultNamespace, Username: "user"}},
|
||||
expectedReturned: []configtypes.AuthConfig{{ServerAddress: dockerregistry.IndexServer, Username: "user"}},
|
||||
},
|
||||
{
|
||||
name: "custom registry address is left untouched",
|
||||
registries: []configtypes.AuthConfig{{ServerAddress: "registry.example.com", Username: "user"}},
|
||||
expectedReturned: []configtypes.AuthConfig{{ServerAddress: "registry.example.com", Username: "user"}},
|
||||
},
|
||||
{
|
||||
name: "IndexServer address is left untouched",
|
||||
registries: []configtypes.AuthConfig{{ServerAddress: dockerregistry.IndexServer, Username: "user"}},
|
||||
expectedReturned: []configtypes.AuthConfig{{ServerAddress: dockerregistry.IndexServer, Username: "user"}},
|
||||
},
|
||||
{
|
||||
name: "mix of registries normalizes only the matching ones",
|
||||
registries: []configtypes.AuthConfig{
|
||||
{ServerAddress: "", Username: "empty"},
|
||||
{ServerAddress: dockerregistry.DefaultNamespace, Username: "default-namespace"},
|
||||
{ServerAddress: "registry.example.com", Username: "custom"},
|
||||
},
|
||||
expectedReturned: []configtypes.AuthConfig{
|
||||
{ServerAddress: dockerregistry.IndexServer, Username: "empty"},
|
||||
{ServerAddress: dockerregistry.IndexServer, Username: "default-namespace"},
|
||||
{ServerAddress: "registry.example.com", Username: "custom"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
original := slices.Clone(tt.registries)
|
||||
|
||||
got := normalizeRegistryServerAddresses(tt.registries)
|
||||
|
||||
require.Equal(t, tt.expectedReturned, got)
|
||||
require.Equal(t, original, tt.registries, "input slice must not be mutated")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getConfig(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user