From 1543a01be874af690b7ade9b226d9d62e43ac036 Mon Sep 17 00:00:00 2001 From: TomSweeneyRedHat Date: Fri, 18 Jan 2019 20:01:29 -0500 Subject: Add --all-tags to pull command Signed-off-by: TomSweeneyRedHat Add --all-tags for the `podman pull` command so all tags of an image will be pulled, not just ':latest'. Emulates the change in Buildah https://github.com/containers/buildah/pull/1263 Signed-off-by: TomSweeneyRedHat --- cmd/podman/cliconfig/config.go | 1 + cmd/podman/pull.go | 71 ++++++++++++++++++++++++++++++++++++------ docs/podman-pull.1.md | 4 +++ test/e2e/pull_test.go | 16 ++++++++++ test/utils/utils.go | 2 +- 5 files changed, 83 insertions(+), 11 deletions(-) diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index b925d29ff..a4c1bf0c0 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -334,6 +334,7 @@ type PsValues struct { type PullValues struct { PodmanCommand + AllTags bool Authfile string CertDir string Creds string diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index d70719164..b9ef3f96b 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -6,11 +6,13 @@ import ( "os" "strings" + "github.com/containers/image/docker" dockerarchive "github.com/containers/image/docker/archive" "github.com/containers/image/transports/alltransports" "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/libpod/adapter" + "github.com/containers/libpod/libpod/common" image2 "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" @@ -41,6 +43,7 @@ specified, the image with the 'latest' tag (if it exists) is pulled func init() { pullCommand.Command = _pullCommand flags := pullCommand.Flags() + flags.BoolVar(&pullCommand.AllTags, "all-tags", false, "All tagged images inthe repository will be pulled") flags.StringVar(&pullCommand.Authfile, "authfile", "", "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override") flags.StringVar(&pullCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys") flags.StringVar(&pullCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") @@ -69,6 +72,15 @@ func pullCmd(c *cliconfig.PullValues) error { logrus.Errorf("too many arguments. Requires exactly 1") return nil } + + arr := strings.SplitN(args[0], ":", 2) + if len(arr) == 2 { + if c.Bool("all-tags") { + logrus.Errorf("tag can't be used with --all-tags") + return nil + } + } + ctx := getContext() image := args[0] var registryCreds *types.DockerAuthConfig @@ -83,7 +95,6 @@ func pullCmd(c *cliconfig.PullValues) error { var ( writer io.Writer - imgID string ) if !c.Quiet { writer = os.Stderr @@ -107,18 +118,58 @@ func pullCmd(c *cliconfig.PullValues) error { if err != nil { return errors.Wrapf(err, "error pulling image from %q", image) } - imgID = newImage[0].ID() + fmt.Println(newImage[0].ID()) } else { - authfile := getAuthFile(c.Authfile) - newImage, err := runtime.New(getContext(), image, c.SignaturePolicy, authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true, nil) + authfile := getAuthFile(c.String("authfile")) + spec := image + systemContext := common.GetSystemContext("", authfile, false) + srcRef, err := alltransports.ParseImageName(spec) if err != nil { + dockerTransport := "docker://" + logrus.Debugf("error parsing image name %q, trying with transport %q: %v", spec, dockerTransport, err) + spec = dockerTransport + spec + srcRef2, err2 := alltransports.ParseImageName(spec) + if err2 != nil { + return errors.Wrapf(err2, "error parsing image name %q", image) + } + srcRef = srcRef2 + } + var names []string + if c.Bool("all-tags") { + if srcRef.DockerReference() == nil { + return errors.New("Non-docker transport is currently not supported") + } + tags, err := docker.GetRepositoryTags(ctx, systemContext, srcRef) + if err != nil { + return errors.Wrapf(err, "error getting repository tags") + } + for _, tag := range tags { + name := spec + ":" + tag + names = append(names, name) + } + } else { + names = append(names, spec) + } + var foundIDs []string + foundImage := true + for _, name := range names { + newImage, err := runtime.New(getContext(), name, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true, nil) + if err != nil { + println(errors.Wrapf(err, "error pulling image %q", name)) + foundImage = false + continue + } + foundIDs = append(foundIDs, newImage.ID()) + } + if len(names) == 1 && !foundImage { return errors.Wrapf(err, "error pulling image %q", image) } - imgID = newImage.ID() - } - - // Intentionally choosing to ignore if there is an error because - // outputting the image ID is a NTH and not integral to the pull - fmt.Println(imgID) + if len(names) > 1 { + fmt.Println("Pulled Images:") + } + for _, id := range foundIDs { + fmt.Println(id) + } + } // end else if strings.HasPrefix(image, dockerarchive.Transport.Name()+":") return nil } diff --git a/docs/podman-pull.1.md b/docs/podman-pull.1.md index 2196e251e..bce11b096 100644 --- a/docs/podman-pull.1.md +++ b/docs/podman-pull.1.md @@ -45,6 +45,10 @@ Image stored in local container/storage ## OPTIONS +**--all-tags, a** + +All tagged images in the repository will be pulled. + **--authfile** Path of the authentication file. Default is ${XDG_RUNTIME\_DIR}/containers/auth.json, which is set using `podman login`. diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go index bfae15152..faad8202e 100644 --- a/test/e2e/pull_test.go +++ b/test/e2e/pull_test.go @@ -163,4 +163,20 @@ var _ = Describe("Podman pull", func() { Expect(pull.OutputToString()).To(ContainSubstring(shortImageId)) }) + + It("podman pull check all tags", func() { + session := podmanTest.Podman([]string{"pull", "--all-tags", "alpine"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.LineInOuputStartsWith("Pulled Images:")).To(BeTrue()) + + session = podmanTest.Podman([]string{"images"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 4)) + + rmi := podmanTest.Podman([]string{"rmi", "-a", "-f"}) + rmi.WaitWithDefaultTimeout() + Expect(rmi.ExitCode()).To(Equal(0)) + }) }) diff --git a/test/utils/utils.go b/test/utils/utils.go index 23dcb95e3..aace018cd 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -270,7 +270,7 @@ func (s *PodmanSession) LineInOuputStartsWith(term string) bool { } //LineInOutputContains returns true if a line in a -// session output starts with the supplied string +// session output contains the supplied string func (s *PodmanSession) LineInOutputContains(term string) bool { for _, i := range s.OutputToStringArray() { if strings.Contains(i, term) { -- cgit v1.2.3-54-g00ecf