add http head based digest comparison to avoid dockerhub rate limits

This commit is contained in:
Simon Aronsson 2020-12-06 13:21:04 +01:00 committed by GitHub
parent c8bd484b9e
commit cb62b16369
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 1476 additions and 57 deletions

View file

@ -0,0 +1,64 @@
package manifest
import (
"fmt"
"github.com/containrrr/watchtower/pkg/registry/helpers"
"github.com/containrrr/watchtower/pkg/types"
ref "github.com/docker/distribution/reference"
"github.com/sirupsen/logrus"
url2 "net/url"
"strings"
)
// BuildManifestURL from raw image data
func BuildManifestURL(container types.Container) (string, error) {
normalizedName, err := ref.ParseNormalizedNamed(container.ImageName())
if err != nil {
return "", err
}
host, err := helpers.NormalizeRegistry(normalizedName.String())
img, tag := extractImageAndTag(strings.TrimPrefix(container.ImageName(), host+"/"))
logrus.WithFields(logrus.Fields{
"image": img,
"tag": tag,
"normalized": normalizedName,
"host": host,
}).Debug("Parsing image ref")
if err != nil {
return "", err
}
img = strings.TrimPrefix(img, fmt.Sprintf("%s/", host))
if !strings.Contains(img, "/") {
img = "library/" + img
}
url := url2.URL{
Scheme: "https",
Host: host,
Path: fmt.Sprintf("/v2/%s/manifests/%s", img, tag),
}
return url.String(), nil
}
func extractImageAndTag(imageName string) (string, string) {
var img string
var tag string
if strings.Contains(imageName, ":") {
parts := strings.Split(imageName, ":")
if len(parts) > 2 {
img = fmt.Sprintf("%s%s", parts[0], parts[1])
tag = parts[3]
} else {
img = parts[0]
tag = parts[1]
}
} else {
img = imageName
tag = "latest"
}
return img, tag
}

View file

@ -0,0 +1,66 @@
package manifest_test
import (
"github.com/containrrr/watchtower/internal/actions/mocks"
"github.com/containrrr/watchtower/pkg/registry/manifest"
apiTypes "github.com/docker/docker/api/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
"time"
)
func TestManifest(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Manifest Suite")
}
var _ = Describe("the manifest module", func() {
mockId := "mock-id"
mockName := "mock-container"
mockCreated := time.Now()
When("building a manifest url", func() {
It("should return a valid url given a fully qualified image", func() {
expected := "https://ghcr.io/v2/containrrr/watchtower/manifests/latest"
imageInfo := apiTypes.ImageInspect{
RepoTags: []string{
"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(res).To(Equal(expected))
})
It("should assume dockerhub for non-qualified images", func() {
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)
res, err := manifest.BuildManifestURL(mock)
Expect(err).NotTo(HaveOccurred())
Expect(res).To(Equal(expected))
})
It("should assume latest for images that lack an explicit tag", func() {
expected := "https://index.docker.io/v2/containrrr/watchtower/manifests/latest"
imageInfo := apiTypes.ImageInspect{
RepoTags: []string{
"containrrr/watchtower",
},
}
mock := mocks.CreateMockContainerWithImageInfo(mockId, mockName, "containrrr/watchtower", mockCreated, imageInfo)
res, err := manifest.BuildManifestURL(mock)
Expect(err).NotTo(HaveOccurred())
Expect(res).To(Equal(expected))
})
})
})