diff --git a/pkg/registry/auth/auth.go b/pkg/registry/auth/auth.go index 23aef60..63467e1 100644 --- a/pkg/registry/auth/auth.go +++ b/pkg/registry/auth/auth.go @@ -177,9 +177,7 @@ func GetScopeFromImageName(img, svc string) string { // GetChallengeURL creates a URL object based on the image info func GetChallengeURL(img string) (url.URL, error) { - - normalizedNamed, _ := reference.ParseNormalizedNamed(img) - host, err := helpers.NormalizeRegistry(normalizedNamed.String()) + host, err := helpers.GetRegistryAddress(img) if err != nil { return url.URL{}, err } diff --git a/pkg/registry/helpers/helpers.go b/pkg/registry/helpers/helpers.go index 1469331..8d38f14 100644 --- a/pkg/registry/helpers/helpers.go +++ b/pkg/registry/helpers/helpers.go @@ -1,36 +1,27 @@ package helpers import ( - "fmt" - url2 "net/url" + "github.com/docker/distribution/reference" ) -// ConvertToHostname strips a url from everything but the hostname part -func ConvertToHostname(url string) (string, string, error) { - urlWithSchema := fmt.Sprintf("x://%s", url) - u, err := url2.Parse(urlWithSchema) - if err != nil { - return "", "", err - } - hostName := u.Hostname() - port := u.Port() +const ( + DefaultRegistryDomain = "docker.io" + DefaultRegistryHost = "index.docker.io" + LegacyDefaultRegistryDomain = "index.docker.io" +) - return hostName, port, err -} - -// NormalizeRegistry makes sure variations of DockerHubs registry -func NormalizeRegistry(registry string) (string, error) { - hostName, port, err := ConvertToHostname(registry) +// GetRegistryAddress parses an image name +// and returns the address of the specified registry +func GetRegistryAddress(imageRef string) (string, error) { + normalizedRef, err := reference.ParseNormalizedNamed(imageRef) if err != nil { return "", err } - if hostName == "registry-1.docker.io" || hostName == "docker.io" { - hostName = "index.docker.io" - } + address := reference.Domain(normalizedRef) - if port != "" { - return fmt.Sprintf("%s:%s", hostName, port), nil + if address == DefaultRegistryDomain { + address = DefaultRegistryHost } - return hostName, nil + return address, nil } diff --git a/pkg/registry/helpers/helpers_test.go b/pkg/registry/helpers/helpers_test.go index 92e9116..e114e6a 100644 --- a/pkg/registry/helpers/helpers_test.go +++ b/pkg/registry/helpers/helpers_test.go @@ -1,9 +1,10 @@ package helpers import ( + "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "testing" ) func TestHelpers(t *testing.T) { @@ -12,20 +13,21 @@ func TestHelpers(t *testing.T) { } var _ = Describe("the helpers", func() { - - When("converting an url to a hostname", func() { - It("should return docker.io given docker.io/containrrr/watchtower:latest", func() { - host, port, err := ConvertToHostname("docker.io/containrrr/watchtower:latest") - Expect(err).NotTo(HaveOccurred()) - Expect(host).To(Equal("docker.io")) - Expect(port).To(BeEmpty()) + Describe("GetRegistryAddress", func() { + It("should return error if passed empty string", func() { + _, err := GetRegistryAddress("") + Expect(err).To(HaveOccurred()) }) - }) - When("normalizing the registry information", func() { - It("should return index.docker.io given docker.io", func() { - out, err := NormalizeRegistry("docker.io/containrrr/watchtower:latest") - Expect(err).NotTo(HaveOccurred()) - Expect(out).To(Equal("index.docker.io")) + It("should return index.docker.io if passed an image name with no explicit domain", func() { + Expect(GetRegistryAddress("watchtower")).To(Equal("index.docker.io")) + Expect(GetRegistryAddress("containrrr/watchtower")).To(Equal("index.docker.io")) + }) + It("should return the host if passed an image name containing a local host", func() { + Expect(GetRegistryAddress("henk:80/watchtower")).To(Equal("henk:80")) + Expect(GetRegistryAddress("localhost/watchtower")).To(Equal("localhost")) + }) + It("should return the server name if passed a fully qualified image name", func() { + Expect(GetRegistryAddress("github.com/containrrr/config")).To(Equal("github.com")) }) }) }) diff --git a/pkg/registry/manifest/manifest.go b/pkg/registry/manifest/manifest.go index 2d5730c..41f5b30 100644 --- a/pkg/registry/manifest/manifest.go +++ b/pkg/registry/manifest/manifest.go @@ -13,18 +13,16 @@ import ( // BuildManifestURL from raw image data func BuildManifestURL(container types.Container) (string, error) { - var normalizedTaggedRef ref.NamedTagged - if normalizedRef, err := ref.ParseDockerRef(container.ImageName()); err == nil { - var isTagged bool - normalizedTaggedRef, isTagged = normalizedRef.(ref.NamedTagged) + normalizedRef, err := ref.ParseDockerRef(container.ImageName()) + if err != nil { + return "", err + } + normalizedTaggedRef, isTagged := normalizedRef.(ref.NamedTagged) if !isTagged { return "", errors.New("Parsed container image ref has no tag: " + normalizedRef.String()) } - } else { - return "", err - } - host, err := helpers.NormalizeRegistry(normalizedTaggedRef.Name()) + host, _ := helpers.GetRegistryAddress(normalizedTaggedRef.Name()) img, tag := ExtractImageAndTag(normalizedTaggedRef) logrus.WithFields(logrus.Fields{ diff --git a/pkg/registry/registry.go b/pkg/registry/registry.go index 9edd66f..82fcd87 100644 --- a/pkg/registry/registry.go +++ b/pkg/registry/registry.go @@ -41,17 +41,17 @@ func DefaultAuthHandler() (string, error) { // Will return false if behavior for container is unknown. func WarnOnAPIConsumption(container watchtowerTypes.Container) bool { - normalizedName, err := ref.ParseNormalizedNamed(container.ImageName()) + normalizedRef, err := ref.ParseNormalizedNamed(container.ImageName()) if err != nil { return true } - containerHost, err := helpers.NormalizeRegistry(normalizedName.String()) + containerHost, err := helpers.GetRegistryAddress(normalizedRef.Name()) if err != nil { return true } - if containerHost == "index.docker.io" || containerHost == "ghcr.io" { + if containerHost == helpers.DefaultRegistryHost || containerHost == "ghcr.io" { return true } diff --git a/pkg/registry/registry_test.go b/pkg/registry/registry_test.go index 5f3f57f..481c91d 100644 --- a/pkg/registry/registry_test.go +++ b/pkg/registry/registry_test.go @@ -23,11 +23,9 @@ var _ = Describe("Registry", func() { }) When("Given a container with an image explicitly from dockerhub", func() { It("should want to warn", func() { - Expect(testContainerWithImage("registry-1.docker.io/docker:latest")).To(BeTrue()) Expect(testContainerWithImage("index.docker.io/docker:latest")).To(BeTrue()) Expect(testContainerWithImage("docker.io/docker:latest")).To(BeTrue()) }) - }) When("Given a container with an image from some other registry", func() { It("should not want to warn", func() { diff --git a/pkg/registry/trust.go b/pkg/registry/trust.go index fa17bbc..e72ad73 100644 --- a/pkg/registry/trust.go +++ b/pkg/registry/trust.go @@ -5,13 +5,12 @@ import ( "encoding/json" "errors" "os" - "strings" + "github.com/containrrr/watchtower/pkg/registry/helpers" cliconfig "github.com/docker/cli/cli/config" "github.com/docker/cli/cli/config/configfile" "github.com/docker/cli/cli/config/credentials" "github.com/docker/cli/cli/config/types" - "github.com/docker/distribution/reference" log "github.com/sirupsen/logrus" ) @@ -48,12 +47,13 @@ func EncodedEnvAuth(ref string) (string, error) { // loaded from the docker config // Returns an empty string if credentials cannot be found for the referenced server // The docker config must be mounted on the container -func EncodedConfigAuth(ref string) (string, error) { - server, err := ParseServerAddress(ref) +func EncodedConfigAuth(imageRef string) (string, error) { + server, err := helpers.GetRegistryAddress(imageRef) if err != nil { - log.Errorf("Unable to parse the image ref %s", err) + log.Errorf("Could not get registry from image ref %s", imageRef) return "", err } + configDir := os.Getenv("DOCKER_CONFIG") if configDir == "" { configDir = "/" @@ -70,23 +70,11 @@ func EncodedConfigAuth(ref string) (string, error) { log.WithField("config_file", configFile.Filename).Debugf("No credentials for %s found", server) return "", nil } - log.Debugf("Loaded auth credentials for user %s, on registry %s, from file %s", auth.Username, ref, configFile.Filename) + log.Debugf("Loaded auth credentials for user %s, on registry %s, from file %s", auth.Username, server, configFile.Filename) log.Tracef("Using auth password %s", auth.Password) return EncodeAuth(auth) } -// ParseServerAddress extracts the server part from a container image ref -func ParseServerAddress(ref string) (string, error) { - - parsedRef, err := reference.Parse(ref) - if err != nil { - return ref, err - } - - parts := strings.Split(parsedRef.String(), "/") - return parts[0], nil -} - // CredentialsStore returns a new credentials store based // on the settings provided in the configuration file. func CredentialsStore(configFile configfile.ConfigFile) credentials.Store { diff --git a/pkg/registry/trust_test.go b/pkg/registry/trust_test.go index 3dab6ad..c02989f 100644 --- a/pkg/registry/trust_test.go +++ b/pkg/registry/trust_test.go @@ -36,30 +36,6 @@ var _ = Describe("Testing with Ginkgo", func() { _, err = EncodedConfigAuth("") Expect(err).To(HaveOccurred()) - }) - /* - * TODO: - * This part only confirms that it still works in the same way as it did - * with the old version of the docker api client sdk. I'd say that - * ParseServerAddress likely needs to be elaborated a bit to default to - * dockerhub in case no server address was provided. - * - * ++ @simskij, 2019-04-04 - */ - It("parse server address_ should return error if passed empty string", func() { - - _, err := ParseServerAddress("") - Expect(err).To(HaveOccurred()) - }) - It("parse server address_ should return the organization part if passed an image name missing server name", func() { - - val, _ := ParseServerAddress("containrrr/config") - Expect(val).To(Equal("containrrr")) - }) - It("parse server address_ should return the server name if passed a fully qualified image name", func() { - - val, _ := ParseServerAddress("github.com/containrrrr/config") - Expect(val).To(Equal("github.com")) }) })