From 8ea47498a5952c55c819cc15aee3121efc08aba0 Mon Sep 17 00:00:00 2001 From: TomSweeneyRedHat Date: Sat, 2 Mar 2019 20:10:00 -0500 Subject: [PATCH] Add --all-tags to push Signed-off-by: TomSweeneyRedHat Adds the --all-tags to the push command to emulate the one in the push command. Addresses https://github.com/containers/libpod/issues/2369 on the Buildah side, once approved similar changes will be made to Podman. Signed-off-by: TomSweeneyRedHat --- cmd/buildah/push.go | 74 +++++++++++++++++++++++++++++++++++++++++--- docs/buildah-pull.md | 5 +-- docs/buildah-push.md | 7 +++++ tests/push.bats | 13 ++++++++ 4 files changed, 92 insertions(+), 7 deletions(-) diff --git a/cmd/buildah/push.go b/cmd/buildah/push.go index 73f36018cfd..cc35e97814f 100644 --- a/cmd/buildah/push.go +++ b/cmd/buildah/push.go @@ -13,6 +13,8 @@ import ( "github.com/containers/image/manifest" "github.com/containers/image/transports" "github.com/containers/image/transports/alltransports" + "github.com/containers/storage" + multierror "github.com/hashicorp/go-multierror" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -20,6 +22,7 @@ import ( ) type pushResults struct { + allTags bool authfile string blobCache string certDir string @@ -61,6 +64,7 @@ func init() { flags := pushCommand.Flags() flags.SetInterspersed(false) + flags.BoolVarP(&opts.allTags, "all-tags", "a", false, "push all tagged images to the repository") flags.StringVar(&opts.authfile, "authfile", "", "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json") flags.StringVar(&opts.blobCache, "blob-cache", "", "assume image blobs in the specified directory will be available for pushing") flags.StringVar(&opts.certDir, "cert-dir", "", "use certificates at the specified path to access the registry") @@ -98,16 +102,42 @@ func pushCmd(c *cobra.Command, args []string, iopts pushResults) error { return errors.New("Only two arguments are necessary to push: source and destination") } - compress := imagebuildah.Gzip - if iopts.disableCompression { - compress = imagebuildah.Uncompressed - } - store, err := getStore(c) if err != nil { return err } + // Map of image tags found for the specified image. + // tags stored in the key + var imageTags []string + if iopts.allTags { + if err := getAllTags(src, &imageTags, store); err != nil { + return err + } + logrus.Debugf("For the image: [%s] found tags: %v", src, imageTags) + } + + var errs *multierror.Error + imageName := src + destTarget := destSpec + if len(imageTags) > 1 { + for _, tagKey := range imageTags { + src = imageName + ":" + tagKey + destSpec = destTarget + ":" + tagKey + if err = pushImage(c, src, destSpec, store, iopts); err != nil { + errs = multierror.Append(errs, err) + } + } + } else { + if err = pushImage(c, src, destSpec, store, iopts); err != nil { + errs = multierror.Append(errs, err) + } + } + + return errs.ErrorOrNil() +} + +func pushImage(c *cobra.Command, src string, destSpec string, store storage.Store, iopts pushResults) error { dest, err := alltransports.ParseImageName(destSpec) // add the docker:// transport to see if they neglected it. if err != nil { @@ -148,6 +178,11 @@ func pushCmd(c *cobra.Command, args []string, iopts pushResults) error { } } + compress := imagebuildah.Gzip + if iopts.disableCompression { + compress = imagebuildah.Uncompressed + } + options := buildah.PushOptions{ Compression: compress, ManifestType: manifestType, @@ -179,3 +214,32 @@ func getListOfTransports() string { allTransports := strings.Join(transports.ListNames(), ",") return strings.Replace(allTransports, ",tarball", "", 1) } + +// getAllTags gets all of the locally tagged images and adds them +// to the passed in slice. +func getAllTags(imageName string, imageTags *[]string, store storage.Store) error { + + imageName = "/" + imageName + images, err := store.Images() + if err != nil { + return errors.Wrapf(err, "error reading images") + } + for _, image := range images { + + if len(image.Names) < 1 { + continue + } + // Name should look like: "docker.io/library/alpine:latest" + for _, name := range image.Names { + splitName := strings.Split(name, ":") + if !strings.HasSuffix(splitName[0], imageName) { + break + } + if len(splitName) > 1 { + *imageTags = append(*imageTags, splitName[1]) + } + } + + } + return nil +} diff --git a/docs/buildah-pull.md b/docs/buildah-pull.md index 6d6a3696033..3a96ff37a87 100644 --- a/docs/buildah-pull.md +++ b/docs/buildah-pull.md @@ -45,9 +45,9 @@ The image ID of the image that was pulled. On error 1 is returned. ## OPTIONS -**--all-tags, a** +**--all-tags, -a** -All tagged images in the repository will be pulled. +All tagged images in the repository will be pulled, not just `:latest`. **--authfile** *path* @@ -100,6 +100,7 @@ buildah pull --creds=myusername:mypassword --cert-dir ~/auth myregistry/myreposi buildah pull --authfile=/tmp/auths/myauths.json myregistry/myrepository/imagename:imagetag +buildah pull --all-tags alpine ## Files diff --git a/docs/buildah-push.md b/docs/buildah-push.md index f1cd4112e16..3a5ea551681 100644 --- a/docs/buildah-push.md +++ b/docs/buildah-push.md @@ -45,6 +45,10 @@ If the transport part of DESTINATION is omitted, "docker://" is assumed. ## OPTIONS +**--all-tags, -a** + +All tagged images in the repository will be pushed, not just `:latest`. A tag can not be included in the imageID or DESTINATION fields. + **--authfile** *path* Path of the authentication file. Default is ${XDG\_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. @@ -113,6 +117,9 @@ This example extracts the imageID image and puts it into the registry on the loc This example extracts the imageID image and puts it into the registry on the localhost using credentials and certificates for authentication. `# buildah push --cert-dir ~/auth --tls-verify=true --creds=username:password imageID docker://localhost:5000/my-imageID` +This example pushes all the tagged alpine images to the quay.io registry. + `# buildah push --all-tags alpine docker://quay.io/myrepo/alpine` + ## Files **registries.conf** (`/etc/containers/registries.conf`) diff --git a/tests/push.bats b/tests/push.bats index da59b5191d5..fc37515baf2 100644 --- a/tests/push.bats +++ b/tests/push.bats @@ -76,3 +76,16 @@ load helpers echo "$output" | grep -q "docker://busybox" buildah rmi busybox } + +@test "push-all-tags" { + buildah pull --signature-policy ${TESTSDIR}/policy.json --all-tags alpine + run buildah push --signature-policy ${TESTSDIR}/policy.json --all-tags alpine dir:/my-dir + echo "$output" + [[ "$output" =~ "my-dir:latest" ]] + [ "$status" -eq 0 ] + + run ls /my-dir* + echo "$output" + [ "$status" -eq 0 ] + [ $(wc -l <<< "$output") -ge 50 ] +}