diff --git a/pkg/image/remote/remote.go b/pkg/image/remote/remote.go index 6fa096b9fd..2baa578b80 100644 --- a/pkg/image/remote/remote.go +++ b/pkg/image/remote/remote.go @@ -52,12 +52,17 @@ func RetrieveRemoteImage(image string, opts config.RegistryOptions, customPlatfo } if newRegURLs, found := opts.RegistryMaps[ref.Context().RegistryStr()]; found { - ref, err := normalizeReference(ref, image) - if err != nil { - return nil, err - } - for _, regToMapTo := range newRegURLs { + + //extract custom path if any in all registry map and clean regToMapTo to only the registry without the path + custompath, regToMapTo := extractPathFromRegistryURL(regToMapTo) + //normalize reference is call in every fallback to ensure that the image is normalized to the new registry include the image prefix + ref, err = normalizeReference(ref, image, custompath) + + if err != nil { + return nil, err + } + var newReg name.Registry if opts.InsecurePull || opts.InsecureRegistries.Contains(regToMapTo) { newReg, err = name.NewRegistry(regToMapTo, name.WeakValidation, name.Insecure) @@ -67,6 +72,7 @@ func RetrieveRemoteImage(image string, opts config.RegistryOptions, customPlatfo if err != nil { return nil, err } + //ref will be already use library/ or the custom path in registry map suffix ref := setNewRegistry(ref, newReg) logrus.Infof("Retrieving image %s from mapped registry %s", ref, regToMapTo) retryFunc := func() (v1.Image, error) { @@ -113,13 +119,16 @@ func RetrieveRemoteImage(image string, opts config.RegistryOptions, customPlatfo return remoteImage, err } -// normalizeReference adds the library/ prefix to images without it. +// normalizeReference adds the library/ or the {path}/ in registry map suffix to images without it. // -// It is mostly useful when using a registry mirror that is not able to perform -// this fix automatically. -func normalizeReference(ref name.Reference, image string) (name.Reference, error) { +// It is mostly useful when using a registry maps that is not able to perform +// this fix automatically add library or the custom path on registry map. +func normalizeReference(ref name.Reference, image string, custompath string) (name.Reference, error) { + if custompath == "" { + custompath = "library" + } if !strings.ContainsRune(image, '/') { - return name.ParseReference("library/"+image, name.WeakValidation) + return name.ParseReference(custompath+"/"+image, name.WeakValidation) } return ref, nil @@ -155,3 +164,17 @@ func remoteOptions(registryName string, opts config.RegistryOptions, customPlatf return []remote.Option{remote.WithTransport(tr), remote.WithAuthFromKeychain(creds.GetKeychain()), remote.WithPlatform(*platform)} } + +// Parse the registry URL +// example: regURL = "registry.example.com/namespace/repo:tag" will return namespace/repo +func extractPathFromRegistryURL(regFullURL string) (string, string) { + // Split the regURL by slashes + // becaues the registry url is write without scheme, we just need to remove the first one + segments := strings.Split(regFullURL, "/") + // Join all segments except the first one (which is typically empty) + path := strings.Join(segments[1:], "/") + // get the fist segment to get the registry url + regURL := segments[0] + + return path, regURL +} diff --git a/pkg/image/remote/remote_test.go b/pkg/image/remote/remote_test.go index e68c1fe524..4d3712a967 100644 --- a/pkg/image/remote/remote_test.go +++ b/pkg/image/remote/remote_test.go @@ -89,7 +89,7 @@ func Test_normalizeReference(t *testing.T) { t.Fatal(err) } - ref2, err := normalizeReference(ref, image) + ref2, err := normalizeReference(ref, image, "library") if err != nil { t.Fatal(err) } @@ -183,3 +183,38 @@ func Test_NoRetryRetrieveRemoteImageFails(t *testing.T) { t.Fatal("Expected call to fail because there is no retry") } } + +func Test_ExtractPathFromRegistryURL(t *testing.T) { + tests := []struct { + name string + regFullURL string + expectedRegistry string + expectedImagePrefix string + }{ + { + name: "Test case 1", + regFullURL: "registry.example.com/namespace", + expectedRegistry: "registry.example.com", + expectedImagePrefix: "namespace", + }, + { + name: "Test case 2", + regFullURL: "registry.example.com", + expectedRegistry: "registry.example.com", + expectedImagePrefix: "", + }, + // Add more test cases here + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + path, registry := extractPathFromRegistryURL(tt.regFullURL) + if registry != tt.expectedRegistry { + t.Errorf("Expected path: %s, but got: %s", tt.expectedRegistry, registry) + } + if path != tt.expectedImagePrefix { + t.Errorf("Expected repo: %s, but got: %s", tt.expectedImagePrefix, path) + } + }) + } +}