diff --git a/cmd/buildah/push.go b/cmd/buildah/push.go index 893671a4b3a..a2b89fd5dab 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") @@ -97,16 +101,48 @@ 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 map[string]string + if iopts.allTags { + imageTags = make(map[string]string) + fmt.Printf("TOM: all-tags found src [%v] dest [%v]\n", src, destSpec) + if err := getAllTags(src, imageTags, store); err != nil { + return err + } + logrus.Debugf("For the image: [%s] found tags: %v", src, imageTags) + fmt.Printf("For the image: [%s] found %d tags: [%v]", src, len(imageTags), imageTags) + } + + var errs *multierror.Error + var pushErr error + imageName := src + destTarget := destSpec + if len(imageTags) > 1 { + for tagKey := range imageTags { + src = imageName + ":" + tagKey + destSpec = destTarget + ":" + tagKey + pushErr = pushImage(c, src, destSpec, store, iopts) + if pushErr != nil { + errs = multierror.Append(errs, pushErr) + } + } + } else { + pushErr = pushImage(c, src, destSpec, store, iopts) + if pushErr != nil { + errs = multierror.Append(errs, pushErr) + } + } + + 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 { @@ -147,6 +183,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, @@ -178,3 +219,33 @@ func getListOfTransports() string { allTransports := strings.Join(transports.ListNames(), ",") return strings.Replace(allTransports, ",tarball", "", 1) } + +// getAllTags gets all of the locally tagged images and returns them +// in a slice. +func getAllTags(image string, imageTags map[string]string, store storage.Store) error { + + images, err := store.Images() + if err != nil { + return errors.Wrapf(err, "error reading images") + } + for _, image := range images { + + names := []string{} + + if len(image.Names) > 0 { + names = image.Names + } else { + continue + } + + for _, name := range names { + splitName := strings.Split(name, ":") + if len(splitName) > 1 { + fmt.Printf("TOM: tagName [%s]\n", splitName[1]) + imageTags[splitName[1]] = "" + } + } + + } + return nil +} diff --git a/docs/buildah-pull.md b/docs/buildah-pull.md index aa3c50fc41d..9eecce06ba3 100644 --- a/docs/buildah-pull.md +++ b/docs/buildah-pull.md @@ -47,7 +47,7 @@ The image ID of the image that was pulled. On error 1 is returned. **--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* @@ -108,6 +108,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 014edfb8cd8..b39e5fb483e 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`. @@ -119,6 +123,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 ] +}