mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-17 15:40:12 +01:00
unite trust.ParseServerAddress & helpers.NormalizeRegistry
This commit is contained in:
parent
f0e075c390
commit
85f5c1fdb1
8 changed files with 46 additions and 95 deletions
|
|
@ -177,9 +177,7 @@ func GetScopeFromImageName(img, svc string) string {
|
||||||
|
|
||||||
// GetChallengeURL creates a URL object based on the image info
|
// GetChallengeURL creates a URL object based on the image info
|
||||||
func GetChallengeURL(img string) (url.URL, error) {
|
func GetChallengeURL(img string) (url.URL, error) {
|
||||||
|
host, err := helpers.GetRegistryAddress(img)
|
||||||
normalizedNamed, _ := reference.ParseNormalizedNamed(img)
|
|
||||||
host, err := helpers.NormalizeRegistry(normalizedNamed.String())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return url.URL{}, err
|
return url.URL{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,27 @@
|
||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/docker/distribution/reference"
|
||||||
url2 "net/url"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConvertToHostname strips a url from everything but the hostname part
|
const (
|
||||||
func ConvertToHostname(url string) (string, string, error) {
|
DefaultRegistryDomain = "docker.io"
|
||||||
urlWithSchema := fmt.Sprintf("x://%s", url)
|
DefaultRegistryHost = "index.docker.io"
|
||||||
u, err := url2.Parse(urlWithSchema)
|
LegacyDefaultRegistryDomain = "index.docker.io"
|
||||||
if err != nil {
|
)
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
hostName := u.Hostname()
|
|
||||||
port := u.Port()
|
|
||||||
|
|
||||||
return hostName, port, err
|
// GetRegistryAddress parses an image name
|
||||||
}
|
// and returns the address of the specified registry
|
||||||
|
func GetRegistryAddress(imageRef string) (string, error) {
|
||||||
// NormalizeRegistry makes sure variations of DockerHubs registry
|
normalizedRef, err := reference.ParseNormalizedNamed(imageRef)
|
||||||
func NormalizeRegistry(registry string) (string, error) {
|
|
||||||
hostName, port, err := ConvertToHostname(registry)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if hostName == "registry-1.docker.io" || hostName == "docker.io" {
|
address := reference.Domain(normalizedRef)
|
||||||
hostName = "index.docker.io"
|
|
||||||
}
|
|
||||||
|
|
||||||
if port != "" {
|
if address == DefaultRegistryDomain {
|
||||||
return fmt.Sprintf("%s:%s", hostName, port), nil
|
address = DefaultRegistryHost
|
||||||
}
|
}
|
||||||
return hostName, nil
|
return address, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHelpers(t *testing.T) {
|
func TestHelpers(t *testing.T) {
|
||||||
|
|
@ -12,20 +13,21 @@ func TestHelpers(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Describe("the helpers", func() {
|
var _ = Describe("the helpers", func() {
|
||||||
|
Describe("GetRegistryAddress", func() {
|
||||||
When("converting an url to a hostname", func() {
|
It("should return error if passed empty string", func() {
|
||||||
It("should return docker.io given docker.io/containrrr/watchtower:latest", func() {
|
_, err := GetRegistryAddress("")
|
||||||
host, port, err := ConvertToHostname("docker.io/containrrr/watchtower:latest")
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err).NotTo(HaveOccurred())
|
|
||||||
Expect(host).To(Equal("docker.io"))
|
|
||||||
Expect(port).To(BeEmpty())
|
|
||||||
})
|
})
|
||||||
|
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"))
|
||||||
})
|
})
|
||||||
When("normalizing the registry information", func() {
|
It("should return the host if passed an image name containing a local host", func() {
|
||||||
It("should return index.docker.io given docker.io", func() {
|
Expect(GetRegistryAddress("henk:80/watchtower")).To(Equal("henk:80"))
|
||||||
out, err := NormalizeRegistry("docker.io/containrrr/watchtower:latest")
|
Expect(GetRegistryAddress("localhost/watchtower")).To(Equal("localhost"))
|
||||||
Expect(err).NotTo(HaveOccurred())
|
})
|
||||||
Expect(out).To(Equal("index.docker.io"))
|
It("should return the server name if passed a fully qualified image name", func() {
|
||||||
|
Expect(GetRegistryAddress("github.com/containrrr/config")).To(Equal("github.com"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,16 @@ import (
|
||||||
|
|
||||||
// BuildManifestURL from raw image data
|
// BuildManifestURL from raw image data
|
||||||
func BuildManifestURL(container types.Container) (string, error) {
|
func BuildManifestURL(container types.Container) (string, error) {
|
||||||
var normalizedTaggedRef ref.NamedTagged
|
normalizedRef, err := ref.ParseDockerRef(container.ImageName())
|
||||||
if normalizedRef, err := ref.ParseDockerRef(container.ImageName()); err == nil {
|
if err != nil {
|
||||||
var isTagged bool
|
return "", err
|
||||||
normalizedTaggedRef, isTagged = normalizedRef.(ref.NamedTagged)
|
}
|
||||||
|
normalizedTaggedRef, isTagged := normalizedRef.(ref.NamedTagged)
|
||||||
if !isTagged {
|
if !isTagged {
|
||||||
return "", errors.New("Parsed container image ref has no tag: " + normalizedRef.String())
|
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)
|
img, tag := ExtractImageAndTag(normalizedTaggedRef)
|
||||||
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
|
|
|
||||||
|
|
@ -41,17 +41,17 @@ func DefaultAuthHandler() (string, error) {
|
||||||
// Will return false if behavior for container is unknown.
|
// Will return false if behavior for container is unknown.
|
||||||
func WarnOnAPIConsumption(container watchtowerTypes.Container) bool {
|
func WarnOnAPIConsumption(container watchtowerTypes.Container) bool {
|
||||||
|
|
||||||
normalizedName, err := ref.ParseNormalizedNamed(container.ImageName())
|
normalizedRef, err := ref.ParseNormalizedNamed(container.ImageName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
containerHost, err := helpers.NormalizeRegistry(normalizedName.String())
|
containerHost, err := helpers.GetRegistryAddress(normalizedRef.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if containerHost == "index.docker.io" || containerHost == "ghcr.io" {
|
if containerHost == helpers.DefaultRegistryHost || containerHost == "ghcr.io" {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,9 @@ var _ = Describe("Registry", func() {
|
||||||
})
|
})
|
||||||
When("Given a container with an image explicitly from dockerhub", func() {
|
When("Given a container with an image explicitly from dockerhub", func() {
|
||||||
It("should want to warn", 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("index.docker.io/docker:latest")).To(BeTrue())
|
||||||
Expect(testContainerWithImage("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() {
|
When("Given a container with an image from some other registry", func() {
|
||||||
It("should not want to warn", func() {
|
It("should not want to warn", func() {
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
"github.com/containrrr/watchtower/pkg/registry/helpers"
|
||||||
cliconfig "github.com/docker/cli/cli/config"
|
cliconfig "github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/cli/cli/config/configfile"
|
"github.com/docker/cli/cli/config/configfile"
|
||||||
"github.com/docker/cli/cli/config/credentials"
|
"github.com/docker/cli/cli/config/credentials"
|
||||||
"github.com/docker/cli/cli/config/types"
|
"github.com/docker/cli/cli/config/types"
|
||||||
"github.com/docker/distribution/reference"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,12 +47,13 @@ func EncodedEnvAuth(ref string) (string, error) {
|
||||||
// loaded from the docker config
|
// loaded from the docker config
|
||||||
// Returns an empty string if credentials cannot be found for the referenced server
|
// Returns an empty string if credentials cannot be found for the referenced server
|
||||||
// The docker config must be mounted on the container
|
// The docker config must be mounted on the container
|
||||||
func EncodedConfigAuth(ref string) (string, error) {
|
func EncodedConfigAuth(imageRef string) (string, error) {
|
||||||
server, err := ParseServerAddress(ref)
|
server, err := helpers.GetRegistryAddress(imageRef)
|
||||||
if err != nil {
|
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
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
configDir := os.Getenv("DOCKER_CONFIG")
|
configDir := os.Getenv("DOCKER_CONFIG")
|
||||||
if configDir == "" {
|
if configDir == "" {
|
||||||
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)
|
log.WithField("config_file", configFile.Filename).Debugf("No credentials for %s found", server)
|
||||||
return "", nil
|
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)
|
log.Tracef("Using auth password %s", auth.Password)
|
||||||
return EncodeAuth(auth)
|
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
|
// CredentialsStore returns a new credentials store based
|
||||||
// on the settings provided in the configuration file.
|
// on the settings provided in the configuration file.
|
||||||
func CredentialsStore(configFile configfile.ConfigFile) credentials.Store {
|
func CredentialsStore(configFile configfile.ConfigFile) credentials.Store {
|
||||||
|
|
|
||||||
|
|
@ -36,30 +36,6 @@ var _ = Describe("Testing with Ginkgo", func() {
|
||||||
|
|
||||||
_, err = EncodedConfigAuth("")
|
_, err = EncodedConfigAuth("")
|
||||||
Expect(err).To(HaveOccurred())
|
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"))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue