mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-17 07:30:13 +01:00
fix(manifest): use imported docker image ref manipulations
Closes #1525
This commit is contained in:
parent
c16ac967c5
commit
f0e075c390
2 changed files with 55 additions and 75 deletions
|
|
@ -1,42 +1,43 @@
|
||||||
package manifest
|
package manifest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/containrrr/watchtower/pkg/registry/auth"
|
url2 "net/url"
|
||||||
|
|
||||||
"github.com/containrrr/watchtower/pkg/registry/helpers"
|
"github.com/containrrr/watchtower/pkg/registry/helpers"
|
||||||
"github.com/containrrr/watchtower/pkg/types"
|
"github.com/containrrr/watchtower/pkg/types"
|
||||||
ref "github.com/docker/distribution/reference"
|
ref "github.com/docker/distribution/reference"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
url2 "net/url"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
||||||
normalizedName, err := ref.ParseNormalizedNamed(container.ImageName())
|
if normalizedRef, err := ref.ParseDockerRef(container.ImageName()); err == nil {
|
||||||
if err != nil {
|
var isTagged bool
|
||||||
|
normalizedTaggedRef, isTagged = normalizedRef.(ref.NamedTagged)
|
||||||
|
if !isTagged {
|
||||||
|
return "", errors.New("Parsed container image ref has no tag: " + normalizedRef.String())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
host, err := helpers.NormalizeRegistry(normalizedName.String())
|
host, err := helpers.NormalizeRegistry(normalizedTaggedRef.Name())
|
||||||
img, tag := ExtractImageAndTag(strings.TrimPrefix(container.ImageName(), host+"/"))
|
img, tag := ExtractImageAndTag(normalizedTaggedRef)
|
||||||
|
|
||||||
logrus.WithFields(logrus.Fields{
|
logrus.WithFields(logrus.Fields{
|
||||||
"image": img,
|
"image": img,
|
||||||
"tag": tag,
|
"tag": tag,
|
||||||
"normalized": normalizedName,
|
"normalized": normalizedTaggedRef.Name(),
|
||||||
"host": host,
|
"host": host,
|
||||||
}).Debug("Parsing image ref")
|
}).Debug("Parsing image ref")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
img = auth.GetScopeFromImageName(img, host)
|
|
||||||
|
|
||||||
if !strings.Contains(img, "/") {
|
|
||||||
img = "library/" + img
|
|
||||||
}
|
|
||||||
url := url2.URL{
|
url := url2.URL{
|
||||||
Scheme: "https",
|
Scheme: "https",
|
||||||
Host: host,
|
Host: host,
|
||||||
|
|
@ -45,23 +46,7 @@ func BuildManifestURL(container types.Container) (string, error) {
|
||||||
return url.String(), nil
|
return url.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExtractImageAndTag from a concatenated string
|
// ExtractImageAndTag from image reference
|
||||||
func ExtractImageAndTag(imageName string) (string, string) {
|
func ExtractImageAndTag(namedTaggedRef ref.NamedTagged) (string, string) {
|
||||||
var img string
|
return ref.Path(namedTaggedRef), namedTaggedRef.Tag()
|
||||||
var tag string
|
|
||||||
|
|
||||||
if strings.Contains(imageName, ":") {
|
|
||||||
parts := strings.Split(imageName, ":")
|
|
||||||
if len(parts) > 2 {
|
|
||||||
img = parts[0]
|
|
||||||
tag = strings.Join(parts[1:], ":")
|
|
||||||
} else {
|
|
||||||
img = parts[0]
|
|
||||||
tag = parts[1]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
img = imageName
|
|
||||||
tag = "latest"
|
|
||||||
}
|
|
||||||
return img, tag
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
package manifest_test
|
package manifest_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containrrr/watchtower/internal/actions/mocks"
|
"github.com/containrrr/watchtower/internal/actions/mocks"
|
||||||
"github.com/containrrr/watchtower/pkg/registry/manifest"
|
"github.com/containrrr/watchtower/pkg/registry/manifest"
|
||||||
apiTypes "github.com/docker/docker/api/types"
|
apiTypes "github.com/docker/docker/api/types"
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestManifest(t *testing.T) {
|
func TestManifest(t *testing.T) {
|
||||||
|
|
@ -16,60 +17,54 @@ func TestManifest(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = Describe("the manifest module", func() {
|
var _ = Describe("the manifest module", func() {
|
||||||
mockId := "mock-id"
|
Describe("BuildManifestURL", func() {
|
||||||
mockName := "mock-container"
|
|
||||||
mockCreated := time.Now()
|
|
||||||
|
|
||||||
When("building a manifest url", func() {
|
|
||||||
It("should return a valid url given a fully qualified image", func() {
|
It("should return a valid url given a fully qualified image", func() {
|
||||||
expected := "https://ghcr.io/v2/containrrr/watchtower/manifests/latest"
|
expected := "https://ghcr.io/v2/containrrr/watchtower/manifests/latest"
|
||||||
imageInfo := apiTypes.ImageInspect{
|
|
||||||
RepoTags: []string{
|
URL, err := buildMockContainerManifestURL("ghcr.io/containrrr/watchtower:latest")
|
||||||
"ghcr.io/k6io/operator:latest",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
mock := mocks.CreateMockContainerWithImageInfo(mockId, mockName, "ghcr.io/containrrr/watchtower:latest", mockCreated, imageInfo)
|
|
||||||
res, err := manifest.BuildManifestURL(mock)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(res).To(Equal(expected))
|
Expect(URL).To(Equal(expected))
|
||||||
})
|
})
|
||||||
It("should assume dockerhub for non-qualified images", func() {
|
It("should assume Docker Hub for non-qualified images", func() {
|
||||||
expected := "https://index.docker.io/v2/containrrr/watchtower/manifests/latest"
|
expected := "https://index.docker.io/v2/containrrr/watchtower/manifests/latest"
|
||||||
imageInfo := apiTypes.ImageInspect{
|
|
||||||
RepoTags: []string{
|
|
||||||
"containrrr/watchtower:latest",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
mock := mocks.CreateMockContainerWithImageInfo(mockId, mockName, "containrrr/watchtower:latest", mockCreated, imageInfo)
|
URL, err := buildMockContainerManifestURL("containrrr/watchtower:latest")
|
||||||
res, err := manifest.BuildManifestURL(mock)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(res).To(Equal(expected))
|
Expect(URL).To(Equal(expected))
|
||||||
})
|
})
|
||||||
It("should assume latest for images that lack an explicit tag", func() {
|
It("should assume latest for image refs without an explicit tag", func() {
|
||||||
expected := "https://index.docker.io/v2/containrrr/watchtower/manifests/latest"
|
expected := "https://index.docker.io/v2/containrrr/watchtower/manifests/latest"
|
||||||
imageInfo := apiTypes.ImageInspect{
|
|
||||||
|
|
||||||
RepoTags: []string{
|
URL, err := buildMockContainerManifestURL("containrrr/watchtower")
|
||||||
"containrrr/watchtower",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
mock := mocks.CreateMockContainerWithImageInfo(mockId, mockName, "containrrr/watchtower", mockCreated, imageInfo)
|
|
||||||
|
|
||||||
res, err := manifest.BuildManifestURL(mock)
|
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(res).To(Equal(expected))
|
Expect(URL).To(Equal(expected))
|
||||||
})
|
})
|
||||||
It("should combine the tag name and digest pinning into one digest, given multiple colons", func() {
|
It("should not prepend library/ for single-part container names in registries other than Docker Hub", func() {
|
||||||
in := "containrrr/watchtower:latest@sha256:daf7034c5c89775afe3008393ae033529913548243b84926931d7c84398ecda7"
|
expected := "https://docker-registry.domain/v2/imagename/manifests/latest"
|
||||||
image, tag := "containrrr/watchtower", "latest@sha256:daf7034c5c89775afe3008393ae033529913548243b84926931d7c84398ecda7"
|
|
||||||
|
|
||||||
imageOut, tagOut := manifest.ExtractImageAndTag(in)
|
URL, err := buildMockContainerManifestURL("docker-registry.domain/imagename:latest")
|
||||||
|
Expect(err).NotTo(HaveOccurred())
|
||||||
Expect(imageOut).To(Equal(image))
|
Expect(URL).To(Equal(expected))
|
||||||
Expect(tagOut).To(Equal(tag))
|
})
|
||||||
|
It("should throw an error on pinned images", func() {
|
||||||
|
imageRef := "docker-registry.domain/imagename@sha256:daf7034c5c89775afe3008393ae033529913548243b84926931d7c84398ecda7"
|
||||||
|
URL, err := buildMockContainerManifestURL(imageRef)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(URL).To(BeEmpty())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
func buildMockContainerManifestURL(imageRef string) (string, error) {
|
||||||
|
imageInfo := apiTypes.ImageInspect{
|
||||||
|
RepoTags: []string{
|
||||||
|
imageRef,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mockID := "mock-id"
|
||||||
|
mockName := "mock-container"
|
||||||
|
mockCreated := time.Now()
|
||||||
|
mock := mocks.CreateMockContainerWithImageInfo(mockID, mockName, imageRef, mockCreated, imageInfo)
|
||||||
|
|
||||||
|
return manifest.BuildManifestURL(mock)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue