diff options
author | Valentin Rothberg <rothberg@redhat.com> | 2021-05-27 16:13:54 +0200 |
---|---|---|
committer | Valentin Rothberg <rothberg@redhat.com> | 2021-05-31 14:38:43 +0200 |
commit | fb4a0c572ed1264ebb12218e8905c4845cb159c5 (patch) | |
tree | ec71658e6352e62b29e8bb931faf96a0b644ed1c | |
parent | 59236762eca31a20d886837698db58e259a21de5 (diff) | |
download | podman-fb4a0c572ed1264ebb12218e8905c4845cb159c5.tar.gz podman-fb4a0c572ed1264ebb12218e8905c4845cb159c5.tar.bz2 podman-fb4a0c572ed1264ebb12218e8905c4845cb159c5.zip |
support tag@digest notation
Vendor in the latest HEAd of containers/common to implicitly support the
tag@digest notation for images. To remain compatible with Docker, the
tag will be stripped off the image reference and is entirely ignored.
Fixes: #6721
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 4 | ||||
-rw-r--r-- | pkg/api/handlers/compat/containers_create.go | 5 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/images.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/images_pull.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/manifests.go | 2 | ||||
-rw-r--r-- | pkg/api/handlers/utils/images.go | 25 | ||||
-rw-r--r-- | test/e2e/play_kube_test.go | 2 | ||||
-rw-r--r-- | test/system/001-basic.bats | 8 | ||||
-rw-r--r-- | vendor/github.com/containers/common/libimage/normalize.go | 51 | ||||
-rw-r--r-- | vendor/github.com/containers/common/libimage/pull.go | 23 | ||||
-rw-r--r-- | vendor/github.com/containers/common/libimage/runtime.go | 9 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/default.go | 2 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/nosystemd.go | 10 | ||||
-rw-r--r-- | vendor/github.com/containers/common/pkg/config/systemd.go | 40 | ||||
-rw-r--r-- | vendor/github.com/containers/common/version/version.go | 2 | ||||
-rw-r--r-- | vendor/modules.txt | 2 |
17 files changed, 161 insertions, 30 deletions
@@ -12,7 +12,7 @@ require ( github.com/containernetworking/cni v0.8.1 github.com/containernetworking/plugins v0.9.1 github.com/containers/buildah v1.21.0 - github.com/containers/common v0.39.0 + github.com/containers/common v0.39.1-0.20210527140106-e5800a20386a github.com/containers/conmon v2.0.20+incompatible github.com/containers/image/v5 v5.12.0 github.com/containers/ocicrypt v1.1.1 @@ -219,8 +219,8 @@ github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRD github.com/containers/buildah v1.21.0 h1:LuwuqRPjan3X3AIdGwfkEkqMgmrDMNpQznFqNdHgCz8= github.com/containers/buildah v1.21.0/go.mod h1:yPdlpVd93T+i91yGxrJbW1YOWrqN64j5ZhHOZmHUejs= github.com/containers/common v0.38.4/go.mod h1:egfpX/Y3+19Dz4Wa1eRZDdgzoEOeneieF9CQppKzLBg= -github.com/containers/common v0.39.0 h1:MrvpFa/bM4UmUILACv2IhOif4oLmWAiD4C+CpOc/MUo= -github.com/containers/common v0.39.0/go.mod h1:vPUHCg/dHoiyqIyLN+EdbjUaGrVEhs/hAvsqsxuYepk= +github.com/containers/common v0.39.1-0.20210527140106-e5800a20386a h1:XzYOUf7qjgVJ59YGqAzehlbT63EgjUJhMnfhsPSSJV0= +github.com/containers/common v0.39.1-0.20210527140106-e5800a20386a/go.mod h1:CxHAf4iQOZZ8nASIjMdYHHRyA8dMR4tINSS7WQWlv90= github.com/containers/conmon v2.0.20+incompatible h1:YbCVSFSCqFjjVwHTPINGdMX1F6JXHGTUje2ZYobNrkg= github.com/containers/conmon v2.0.20+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.12.0 h1:1hNS2QkzFQ4lH3GYQLyAXB0acRMhS1Ubm6oV++8vw4w= diff --git a/pkg/api/handlers/compat/containers_create.go b/pkg/api/handlers/compat/containers_create.go index 8e9e1fb39..0b5cbd343 100644 --- a/pkg/api/handlers/compat/containers_create.go +++ b/pkg/api/handlers/compat/containers_create.go @@ -71,13 +71,12 @@ func CreateContainer(w http.ResponseWriter, r *http.Request) { imgNameOrID := newImage.ID() // if the img had multi names with the same sha256 ID, should use the InputName, not the ID if len(newImage.Names()) > 1 { - imageRef, err := utils.ParseDockerReference(resolvedName) - if err != nil { + if err := utils.IsRegistryReference(resolvedName); err != nil { utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err) return } // maybe the InputName has no tag, so use full name to display - imgNameOrID = imageRef.DockerReference().String() + imgNameOrID = resolvedName } sg := specgen.NewSpecGenerator(imgNameOrID, cliOpts.RootFS) diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index a90408bfd..fc6ab4b4c 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -482,7 +482,7 @@ func PushImage(w http.ResponseWriter, r *http.Request) { destination = source } - if _, err := utils.ParseDockerReference(destination); err != nil { + if err := utils.IsRegistryReference(destination); err != nil { utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err) return } diff --git a/pkg/api/handlers/libpod/images_pull.go b/pkg/api/handlers/libpod/images_pull.go index 7545ba235..fe56aa31d 100644 --- a/pkg/api/handlers/libpod/images_pull.go +++ b/pkg/api/handlers/libpod/images_pull.go @@ -48,7 +48,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { } // Make sure that the reference has no transport or the docker one. - if _, err := utils.ParseDockerReference(query.Reference); err != nil { + if err := utils.IsRegistryReference(query.Reference); err != nil { utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err) return } diff --git a/pkg/api/handlers/libpod/manifests.go b/pkg/api/handlers/libpod/manifests.go index f21eb2e80..2f36db583 100644 --- a/pkg/api/handlers/libpod/manifests.go +++ b/pkg/api/handlers/libpod/manifests.go @@ -169,7 +169,7 @@ func ManifestPush(w http.ResponseWriter, r *http.Request) { errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) return } - if _, err := utils.ParseDockerReference(query.Destination); err != nil { + if err := utils.IsRegistryReference(query.Destination); err != nil { utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, err) return } diff --git a/pkg/api/handlers/utils/images.go b/pkg/api/handlers/utils/images.go index 2662cd368..2a1908d63 100644 --- a/pkg/api/handlers/utils/images.go +++ b/pkg/api/handlers/utils/images.go @@ -15,22 +15,19 @@ import ( "github.com/pkg/errors" ) -// ParseDockerReference parses the specified image name to a -// `types.ImageReference` and enforces it to refer to a docker-transport -// reference. -func ParseDockerReference(name string) (types.ImageReference, error) { - dockerPrefix := fmt.Sprintf("%s://", docker.Transport.Name()) +// IsRegistryReference checks if the specified name points to the "docker://" +// transport. If it points to no supported transport, we'll assume a +// non-transport reference pointing to an image (e.g., "fedora:latest"). +func IsRegistryReference(name string) error { imageRef, err := alltransports.ParseImageName(name) - if err == nil && imageRef.Transport().Name() != docker.Transport.Name() { - return nil, errors.Errorf("reference %q must be a docker reference", name) - } else if err != nil { - origErr := err - imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s%s", dockerPrefix, name)) - if err != nil { - return nil, errors.Wrapf(origErr, "reference %q must be a docker reference", name) - } + if err != nil { + // No supported transport -> assume a docker-stype reference. + return nil } - return imageRef, nil + if imageRef.Transport().Name() == docker.Transport.Name() { + return nil + } + return errors.Errorf("unsupport transport %s in %q: only docker transport is supported", imageRef.Transport().Name(), name) } // ParseStorageReference parses the specified image name to a diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index e0af27f7a..833991452 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -2119,7 +2119,7 @@ MemoryReservation: {{ .HostConfig.MemoryReservation }}`}) kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) kube.WaitWithDefaultTimeout() Expect(kube.ExitCode()).To(Equal(125)) - Expect(kube.ErrorToString()).To(ContainSubstring(invalidImageName)) + Expect(kube.ErrorToString()).To(ContainSubstring("invalid reference format")) }) It("podman play kube applies log driver to containers", func() { diff --git a/test/system/001-basic.bats b/test/system/001-basic.bats index 97ef61511..963c89281 100644 --- a/test/system/001-basic.bats +++ b/test/system/001-basic.bats @@ -49,6 +49,14 @@ function setup() { @test "podman can pull an image" { run_podman pull $IMAGE + + # Also make sure that the tag@digest syntax is supported. + run_podman inspect --format "{{ .Digest }}" $IMAGE + digest=$output + run_podman pull $IMAGE@$digest + + # Now untag the digest reference again. + run_podman untag $IMAGE $IMAGE@$digest } # PR #7212: allow --remote anywhere before subcommand, not just as 1st flag diff --git a/vendor/github.com/containers/common/libimage/normalize.go b/vendor/github.com/containers/common/libimage/normalize.go index 03d2456de..bfea807c8 100644 --- a/vendor/github.com/containers/common/libimage/normalize.go +++ b/vendor/github.com/containers/common/libimage/normalize.go @@ -5,6 +5,7 @@ import ( "github.com/containers/image/v5/docker/reference" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // NormalizeName normalizes the provided name according to the conventions by @@ -40,6 +41,11 @@ func NormalizeName(name string) (reference.Named, error) { } if _, hasTag := named.(reference.NamedTagged); hasTag { + // Strip off the tag of a tagged and digested reference. + named, err = normalizeTaggedDigestedNamed(named) + if err != nil { + return nil, err + } return named, nil } if _, hasDigest := named.(reference.Digested); hasDigest { @@ -90,3 +96,48 @@ func ToNameTagPairs(repoTags []reference.Named) ([]NameTagPair, error) { } return pairs, nil } + +// normalizeTaggedDigestedString strips the tag off the specified string iff it +// is tagged and digested. Note that the tag is entirely ignored to match +// Docker behavior. +func normalizeTaggedDigestedString(s string) (string, error) { + // Note that the input string is not expected to be parseable, so we + // return it verbatim in error cases. + ref, err := reference.Parse(s) + if err != nil { + return "", err + } + named, ok := ref.(reference.Named) + if !ok { + return s, nil + } + named, err = normalizeTaggedDigestedNamed(named) + if err != nil { + return "", err + } + return named.String(), nil +} + +// normalizeTaggedDigestedNamed strips the tag off the specified named +// reference iff it is tagged and digested. Note that the tag is entirely +// ignored to match Docker behavior. +func normalizeTaggedDigestedNamed(named reference.Named) (reference.Named, error) { + _, isTagged := named.(reference.NamedTagged) + if !isTagged { + return named, nil + } + digested, isDigested := named.(reference.Digested) + if !isDigested { + return named, nil + } + + // Now strip off the tag. + newNamed := reference.TrimNamed(named) + // And re-add the digest. + newNamed, err := reference.WithDigest(newNamed, digested.Digest()) + if err != nil { + return named, err + } + logrus.Debugf("Stripped off tag from tagged and digested reference %q", named.String()) + return newNamed, nil +} diff --git a/vendor/github.com/containers/common/libimage/pull.go b/vendor/github.com/containers/common/libimage/pull.go index 5fa888251..acf5c818f 100644 --- a/vendor/github.com/containers/common/libimage/pull.go +++ b/vendor/github.com/containers/common/libimage/pull.go @@ -52,6 +52,7 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP options = &PullOptions{} } + var possiblyUnqualifiedName string // used for short-name resolution ref, err := alltransports.ParseImageName(name) if err != nil { // If the image clearly refers to a local one, we can look it up directly. @@ -67,6 +68,15 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP return []*Image{local}, err } + // Docker compat: strip off the tag iff name is tagged and digested + // (e.g., fedora:latest@sha256...). In that case, the tag is stripped + // off and entirely ignored. The digest is the sole source of truth. + normalizedName, normalizeError := normalizeTaggedDigestedString(name) + if normalizeError != nil { + return nil, normalizeError + } + name = normalizedName + // If the input does not include a transport assume it refers // to a registry. dockerRef, dockerErr := alltransports.ParseImageName("docker://" + name) @@ -74,6 +84,17 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP return nil, err } ref = dockerRef + possiblyUnqualifiedName = name + } else if ref.Transport().Name() == registryTransport.Transport.Name() { + // Normalize the input if we're referring to the docker + // transport directly. That makes sure that a `docker://fedora` + // will resolve directly to `docker.io/library/fedora:latest` + // and not be subject to short-name resolution. + named := ref.DockerReference() + if named == nil { + return nil, errors.New("internal error: unexpected nil reference") + } + possiblyUnqualifiedName = named.String() } if options.AllTags && ref.Transport().Name() != registryTransport.Transport.Name() { @@ -94,7 +115,7 @@ func (r *Runtime) Pull(ctx context.Context, name string, pullPolicy config.PullP // DOCKER REGISTRY case registryTransport.Transport.Name(): - pulledImages, pullError = r.copyFromRegistry(ctx, ref, strings.TrimPrefix(name, "docker://"), pullPolicy, options) + pulledImages, pullError = r.copyFromRegistry(ctx, ref, possiblyUnqualifiedName, pullPolicy, options) // DOCKER ARCHIVE case dockerArchiveTransport.Transport.Name(): diff --git a/vendor/github.com/containers/common/libimage/runtime.go b/vendor/github.com/containers/common/libimage/runtime.go index aa798d008..bbf1c2a61 100644 --- a/vendor/github.com/containers/common/libimage/runtime.go +++ b/vendor/github.com/containers/common/libimage/runtime.go @@ -180,6 +180,15 @@ func (r *Runtime) LookupImage(name string, options *LookupImageOptions) (*Image, } logrus.Debugf("Found image %q in local containers storage (%s)", name, storageRef.StringWithinTransport()) return r.storageToImage(img, storageRef), "", nil + } else { + // Docker compat: strip off the tag iff name is tagged and digested + // (e.g., fedora:latest@sha256...). In that case, the tag is stripped + // off and entirely ignored. The digest is the sole source of truth. + normalizedName, err := normalizeTaggedDigestedString(name) + if err != nil { + return nil, "", err + } + name = normalizedName } originalName := name diff --git a/vendor/github.com/containers/common/pkg/config/default.go b/vendor/github.com/containers/common/pkg/config/default.go index 2b660d1ab..d5a7d5b84 100644 --- a/vendor/github.com/containers/common/pkg/config/default.go +++ b/vendor/github.com/containers/common/pkg/config/default.go @@ -195,7 +195,7 @@ func DefaultConfig() (*Config, error) { Init: false, InitPath: "", IPCNS: "private", - LogDriver: DefaultLogDriver, + LogDriver: defaultLogDriver(), LogSizeMax: DefaultLogSizeMax, NetNS: netns, NoHosts: false, diff --git a/vendor/github.com/containers/common/pkg/config/nosystemd.go b/vendor/github.com/containers/common/pkg/config/nosystemd.go index 5b82b1389..6e39a6ccd 100644 --- a/vendor/github.com/containers/common/pkg/config/nosystemd.go +++ b/vendor/github.com/containers/common/pkg/config/nosystemd.go @@ -3,9 +3,17 @@ package config func defaultCgroupManager() string { - return "cgroupfs" + return CgroupfsCgroupsManager } func defaultEventsLogger() string { return "file" } + +func defaultLogDriver() string { + return DefaultLogDriver +} + +func useSystemd() bool { + return false +} diff --git a/vendor/github.com/containers/common/pkg/config/systemd.go b/vendor/github.com/containers/common/pkg/config/systemd.go index 02e5c4ac2..ed014126b 100644 --- a/vendor/github.com/containers/common/pkg/config/systemd.go +++ b/vendor/github.com/containers/common/pkg/config/systemd.go @@ -3,11 +3,23 @@ package config import ( + "io/ioutil" + "strings" + "sync" + "github.com/containers/common/pkg/cgroupv2" "github.com/containers/storage/pkg/unshare" ) +var ( + systemdOnce sync.Once + usesSystemd bool +) + func defaultCgroupManager() string { + if !useSystemd() { + return CgroupfsCgroupsManager + } enabled, err := cgroupv2.Enabled() if err == nil && !enabled && unshare.IsRootless() { return CgroupfsCgroupsManager @@ -15,6 +27,32 @@ func defaultCgroupManager() string { return SystemdCgroupsManager } + func defaultEventsLogger() string { - return "journald" + if useSystemd() { + return "journald" + } + return "file" +} + +func defaultLogDriver() string { + // If we decide to change the default for logdriver, it should be done here. + if useSystemd() { + return DefaultLogDriver + } + + return DefaultLogDriver + +} + +func useSystemd() bool { + systemdOnce.Do(func() { + dat, err := ioutil.ReadFile("/proc/1/comm") + if err == nil { + val := strings.TrimSuffix(string(dat), "\n") + usesSystemd = (val == "systemd") + } + return + }) + return usesSystemd } diff --git a/vendor/github.com/containers/common/version/version.go b/vendor/github.com/containers/common/version/version.go index 54661f433..ff3bf9a32 100644 --- a/vendor/github.com/containers/common/version/version.go +++ b/vendor/github.com/containers/common/version/version.go @@ -1,4 +1,4 @@ package version // Version is the version of the build. -const Version = "0.39.0" +const Version = "0.39.1-dev" diff --git a/vendor/modules.txt b/vendor/modules.txt index 879bb2759..c6a275a09 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -91,7 +91,7 @@ github.com/containers/buildah/pkg/overlay github.com/containers/buildah/pkg/parse github.com/containers/buildah/pkg/rusage github.com/containers/buildah/util -# github.com/containers/common v0.39.0 +# github.com/containers/common v0.39.1-0.20210527140106-e5800a20386a github.com/containers/common/libimage github.com/containers/common/libimage/manifests github.com/containers/common/pkg/apparmor |