package main import ( "fmt" "io" "os" buildahcli "github.com/containers/buildah/pkg/cli" "github.com/containers/image/v5/docker" dockerarchive "github.com/containers/image/v5/docker/archive" "github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/adapter" "github.com/containers/libpod/pkg/util" "github.com/docker/distribution/reference" "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) var ( pullCommand cliconfig.PullValues pullDescription = `Pulls an image from a registry and stores it locally. An image can be pulled using its tag or digest. If a tag is not specified, the image with the 'latest' tag (if it exists) is pulled.` _pullCommand = &cobra.Command{ Use: "pull [flags] IMAGE-PATH", Short: "Pull an image from a registry", Long: pullDescription, RunE: func(cmd *cobra.Command, args []string) error { pullCommand.InputArgs = args pullCommand.GlobalFlags = MainGlobalOpts pullCommand.Remote = remoteclient return pullCmd(&pullCommand) }, Example: `podman pull imageName podman pull fedora:latest`, } ) func init() { if !remote { _pullCommand.Example = fmt.Sprintf("%s\n podman pull --cert-dir image/certs --authfile temp-auths/myauths.json docker://docker.io/myrepo/finaltest", _pullCommand.Example) } pullCommand.Command = _pullCommand pullCommand.SetHelpTemplate(HelpTemplate()) pullCommand.SetUsageTemplate(UsageTemplate()) flags := pullCommand.Flags() flags.BoolVar(&pullCommand.AllTags, "all-tags", false, "All tagged images in the repository will be pulled") flags.StringVar(&pullCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") flags.BoolVarP(&pullCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images") flags.StringVar(&pullCommand.OverrideArch, "override-arch", "", "use `ARCH` instead of the architecture of the machine for choosing images") flags.StringVar(&pullCommand.OverrideOS, "override-os", "", "use `OS` instead of the running OS for choosing images") markFlagHidden(flags, "override-os") // Disabled flags for the remote client if !remote { flags.StringVar(&pullCommand.Authfile, "authfile", buildahcli.GetDefaultAuthFile(), "Path of the authentication file. 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.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") markFlagHidden(flags, "signature-policy") } } // pullCmd gets the data from the command line and calls pullImage // to copy an image from a registry to a local machine func pullCmd(c *cliconfig.PullValues) (retError error) { defer func() { if retError != nil && exitCode == 0 { exitCode = 1 } }() if c.Bool("trace") { span, _ := opentracing.StartSpanFromContext(Ctx, "pullCmd") defer span.Finish() } runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } defer runtime.DeferredShutdown(false) args := c.InputArgs if len(args) == 0 { return errors.Errorf("an image name must be specified") } if len(args) > 1 { return errors.Errorf("too many arguments. Requires exactly 1") } if c.Authfile != "" { if _, err := os.Stat(c.Authfile); err != nil { return errors.Wrapf(err, "error getting authfile %s", c.Authfile) } } ctx := getContext() imageName := args[0] imageRef, err := alltransports.ParseImageName(imageName) if err != nil { imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s://%s", docker.Transport.Name(), imageName)) if err != nil { return errors.Errorf("invalid image reference %q", imageName) } } var writer io.Writer if !c.Quiet { writer = os.Stderr } // Special-case for docker-archive which allows multiple tags. if imageRef.Transport().Name() == dockerarchive.Transport.Name() { newImage, err := runtime.LoadFromArchiveReference(getContext(), imageRef, c.SignaturePolicy, writer) if err != nil { return errors.Wrapf(err, "error pulling image %q", imageName) } fmt.Println(newImage[0].ID()) return nil } var registryCreds *types.DockerAuthConfig if c.Flag("creds").Changed { creds, err := util.ParseRegistryCreds(c.Creds) if err != nil { return err } registryCreds = creds } dockerRegistryOptions := image.DockerRegistryOptions{ DockerRegistryCreds: registryCreds, DockerCertPath: c.CertDir, OSChoice: c.OverrideOS, ArchitectureChoice: c.OverrideArch, } if c.IsSet("tls-verify") { dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) } if !c.Bool("all-tags") { newImage, err := runtime.New(getContext(), imageName, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) if err != nil { return errors.Wrapf(err, "error pulling image %q", imageName) } fmt.Println(newImage.ID()) return nil } // --all-tags requires the docker transport if imageRef.Transport().Name() != docker.Transport.Name() { return errors.New("--all-tags requires docker transport") } // all-tags doesn't work with a tagged reference, so let's check early namedRef, err := reference.Parse(imageName) if err != nil { return errors.Wrapf(err, "error parsing %q", imageName) } if _, isTagged := namedRef.(reference.Tagged); isTagged { return errors.New("--all-tags requires a reference without a tag") } systemContext := image.GetSystemContext("", c.Authfile, false) tags, err := docker.GetRepositoryTags(ctx, systemContext, imageRef) if err != nil { return errors.Wrapf(err, "error getting repository tags") } var foundIDs []string for _, tag := range tags { name := imageName + ":" + tag newImage, err := runtime.New(getContext(), name, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) if err != nil { logrus.Errorf("error pulling image %q", name) continue } foundIDs = append(foundIDs, newImage.ID()) } if len(tags) != len(foundIDs) { return errors.Errorf("error pulling image %q", imageName) } if len(foundIDs) > 1 { fmt.Println("Pulled Images:") } for _, id := range foundIDs { fmt.Println(id) } return nil }