github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/pull.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 8 buildahcli "github.com/containers/buildah/pkg/cli" 9 "github.com/containers/image/v5/docker" 10 dockerarchive "github.com/containers/image/v5/docker/archive" 11 "github.com/containers/image/v5/transports/alltransports" 12 "github.com/containers/image/v5/types" 13 "github.com/containers/libpod/cmd/podman/cliconfig" 14 "github.com/containers/libpod/libpod/image" 15 "github.com/containers/libpod/pkg/adapter" 16 "github.com/containers/libpod/pkg/util" 17 "github.com/docker/distribution/reference" 18 "github.com/opentracing/opentracing-go" 19 "github.com/pkg/errors" 20 "github.com/sirupsen/logrus" 21 "github.com/spf13/cobra" 22 ) 23 24 var ( 25 pullCommand cliconfig.PullValues 26 pullDescription = `Pulls an image from a registry and stores it locally. 27 28 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.` 29 _pullCommand = &cobra.Command{ 30 Use: "pull [flags] IMAGE-PATH", 31 Short: "Pull an image from a registry", 32 Long: pullDescription, 33 RunE: func(cmd *cobra.Command, args []string) error { 34 pullCommand.InputArgs = args 35 pullCommand.GlobalFlags = MainGlobalOpts 36 pullCommand.Remote = remoteclient 37 return pullCmd(&pullCommand) 38 }, 39 Example: `podman pull imageName 40 podman pull fedora:latest`, 41 } 42 ) 43 44 func init() { 45 46 if !remote { 47 _pullCommand.Example = fmt.Sprintf("%s\n podman pull --cert-dir image/certs --authfile temp-auths/myauths.json docker://docker.io/myrepo/finaltest", _pullCommand.Example) 48 49 } 50 pullCommand.Command = _pullCommand 51 pullCommand.SetHelpTemplate(HelpTemplate()) 52 pullCommand.SetUsageTemplate(UsageTemplate()) 53 flags := pullCommand.Flags() 54 flags.BoolVar(&pullCommand.AllTags, "all-tags", false, "All tagged images in the repository will be pulled") 55 flags.StringVar(&pullCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") 56 flags.BoolVarP(&pullCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images") 57 flags.StringVar(&pullCommand.OverrideArch, "override-arch", "", "use `ARCH` instead of the architecture of the machine for choosing images") 58 flags.StringVar(&pullCommand.OverrideOS, "override-os", "", "use `OS` instead of the running OS for choosing images") 59 markFlagHidden(flags, "override-os") 60 // Disabled flags for the remote client 61 if !remote { 62 flags.StringVar(&pullCommand.Authfile, "authfile", buildahcli.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") 63 flags.StringVar(&pullCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys") 64 flags.StringVar(&pullCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") 65 flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") 66 markFlagHidden(flags, "signature-policy") 67 } 68 } 69 70 // pullCmd gets the data from the command line and calls pullImage 71 // to copy an image from a registry to a local machine 72 func pullCmd(c *cliconfig.PullValues) (retError error) { 73 defer func() { 74 if retError != nil && exitCode == 0 { 75 exitCode = 1 76 } 77 }() 78 if c.Bool("trace") { 79 span, _ := opentracing.StartSpanFromContext(Ctx, "pullCmd") 80 defer span.Finish() 81 } 82 83 runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) 84 85 if err != nil { 86 return errors.Wrapf(err, "could not get runtime") 87 } 88 defer runtime.DeferredShutdown(false) 89 90 args := c.InputArgs 91 if len(args) == 0 { 92 return errors.Errorf("an image name must be specified") 93 } 94 if len(args) > 1 { 95 return errors.Errorf("too many arguments. Requires exactly 1") 96 } 97 98 if c.Authfile != "" { 99 if _, err := os.Stat(c.Authfile); err != nil { 100 return errors.Wrapf(err, "error getting authfile %s", c.Authfile) 101 } 102 } 103 104 ctx := getContext() 105 imageName := args[0] 106 107 imageRef, err := alltransports.ParseImageName(imageName) 108 if err != nil { 109 imageRef, err = alltransports.ParseImageName(fmt.Sprintf("%s://%s", docker.Transport.Name(), imageName)) 110 if err != nil { 111 return errors.Errorf("invalid image reference %q", imageName) 112 } 113 } 114 115 var writer io.Writer 116 if !c.Quiet { 117 writer = os.Stderr 118 } 119 // Special-case for docker-archive which allows multiple tags. 120 if imageRef.Transport().Name() == dockerarchive.Transport.Name() { 121 newImage, err := runtime.LoadFromArchiveReference(getContext(), imageRef, c.SignaturePolicy, writer) 122 if err != nil { 123 return errors.Wrapf(err, "error pulling image %q", imageName) 124 } 125 fmt.Println(newImage[0].ID()) 126 return nil 127 } 128 129 var registryCreds *types.DockerAuthConfig 130 if c.Flag("creds").Changed { 131 creds, err := util.ParseRegistryCreds(c.Creds) 132 if err != nil { 133 return err 134 } 135 registryCreds = creds 136 } 137 dockerRegistryOptions := image.DockerRegistryOptions{ 138 DockerRegistryCreds: registryCreds, 139 DockerCertPath: c.CertDir, 140 OSChoice: c.OverrideOS, 141 ArchitectureChoice: c.OverrideArch, 142 } 143 if c.IsSet("tls-verify") { 144 dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) 145 } 146 147 if !c.Bool("all-tags") { 148 newImage, err := runtime.New(getContext(), imageName, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) 149 if err != nil { 150 return errors.Wrapf(err, "error pulling image %q", imageName) 151 } 152 fmt.Println(newImage.ID()) 153 return nil 154 } 155 156 // --all-tags requires the docker transport 157 if imageRef.Transport().Name() != docker.Transport.Name() { 158 return errors.New("--all-tags requires docker transport") 159 } 160 161 // all-tags doesn't work with a tagged reference, so let's check early 162 namedRef, err := reference.Parse(imageName) 163 if err != nil { 164 return errors.Wrapf(err, "error parsing %q", imageName) 165 } 166 if _, isTagged := namedRef.(reference.Tagged); isTagged { 167 return errors.New("--all-tags requires a reference without a tag") 168 169 } 170 171 systemContext := image.GetSystemContext("", c.Authfile, false) 172 tags, err := docker.GetRepositoryTags(ctx, systemContext, imageRef) 173 if err != nil { 174 return errors.Wrapf(err, "error getting repository tags") 175 } 176 177 var foundIDs []string 178 for _, tag := range tags { 179 name := imageName + ":" + tag 180 newImage, err := runtime.New(getContext(), name, c.SignaturePolicy, c.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, util.PullImageAlways) 181 if err != nil { 182 logrus.Errorf("error pulling image %q", name) 183 continue 184 } 185 foundIDs = append(foundIDs, newImage.ID()) 186 } 187 188 if len(tags) != len(foundIDs) { 189 return errors.Errorf("error pulling image %q", imageName) 190 } 191 192 if len(foundIDs) > 1 { 193 fmt.Println("Pulled Images:") 194 } 195 for _, id := range foundIDs { 196 fmt.Println(id) 197 } 198 199 return nil 200 }