github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/push.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "strings" 8 9 buildahcli "github.com/containers/buildah/pkg/cli" 10 "github.com/containers/image/v5/directory" 11 "github.com/containers/image/v5/manifest" 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 imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" 18 "github.com/pkg/errors" 19 "github.com/spf13/cobra" 20 ) 21 22 var ( 23 pushCommand cliconfig.PushValues 24 pushDescription = fmt.Sprintf(`Pushes an image to a specified location. 25 26 The Image "DESTINATION" uses a "transport":"details" format. See podman-push(1) section "DESTINATION" for the expected format.`) 27 28 _pushCommand = &cobra.Command{ 29 Use: "push [flags] IMAGE REGISTRY", 30 Short: "Push an image to a specified destination", 31 Long: pushDescription, 32 RunE: func(cmd *cobra.Command, args []string) error { 33 pushCommand.InputArgs = args 34 pushCommand.GlobalFlags = MainGlobalOpts 35 pushCommand.Remote = remoteclient 36 return pushCmd(&pushCommand) 37 }, 38 Example: `podman push imageID docker://registry.example.com/repository:tag 39 podman push imageID oci-archive:/path/to/layout:image:tag`, 40 } 41 ) 42 43 func init() { 44 if !remote { 45 _pushCommand.Example = fmt.Sprintf("%s\n podman push --authfile temp-auths/myauths.json alpine docker://docker.io/myrepo/alpine", _pushCommand.Example) 46 47 } 48 49 pushCommand.Command = _pushCommand 50 pushCommand.SetHelpTemplate(HelpTemplate()) 51 pushCommand.SetUsageTemplate(UsageTemplate()) 52 flags := pushCommand.Flags() 53 flags.StringVar(&pushCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry") 54 flags.StringVar(&pushCommand.Digestfile, "digestfile", "", "After copying the image, write the digest of the resulting image to the file") 55 flags.StringVarP(&pushCommand.Format, "format", "f", "", "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)") 56 flags.BoolVarP(&pushCommand.Quiet, "quiet", "q", false, "Don't output progress information when pushing images") 57 flags.BoolVar(&pushCommand.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image") 58 flags.StringVar(&pushCommand.SignBy, "sign-by", "", "Add a signature at the destination using the specified key") 59 60 // Disabled flags for the remote client 61 if !remote { 62 flags.StringVar(&pushCommand.Authfile, "authfile", buildahcli.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override") 63 flags.StringVar(&pushCommand.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys") 64 flags.BoolVar(&pushCommand.Compress, "compress", false, "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)") 65 flags.StringVar(&pushCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)") 66 flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries") 67 markFlagHidden(flags, "signature-policy") 68 } 69 } 70 71 func pushCmd(c *cliconfig.PushValues) error { 72 var ( 73 registryCreds *types.DockerAuthConfig 74 destName string 75 ) 76 77 if c.Authfile != "" { 78 if _, err := os.Stat(c.Authfile); err != nil { 79 return errors.Wrapf(err, "error getting authfile %s", c.Authfile) 80 } 81 } 82 83 args := c.InputArgs 84 if len(args) == 0 || len(args) > 2 { 85 return errors.New("podman push requires at least one image name, and optionally a second to specify a different destination name") 86 } 87 srcName := args[0] 88 switch len(args) { 89 case 1: 90 destName = args[0] 91 case 2: 92 destName = args[1] 93 } 94 95 runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) 96 if err != nil { 97 return errors.Wrapf(err, "could not create runtime") 98 } 99 defer runtime.DeferredShutdown(false) 100 101 // --compress and --format can only be used for the "dir" transport 102 splitArg := strings.SplitN(destName, ":", 2) 103 104 if c.IsSet("compress") || c.Flag("format").Changed { 105 if splitArg[0] != directory.Transport.Name() { 106 return errors.Errorf("--compress and --format can be set only when pushing to a directory using the 'dir' transport") 107 } 108 } 109 110 certPath := c.CertDir 111 removeSignatures := c.RemoveSignatures 112 signBy := c.SignBy 113 114 if c.Flag("creds").Changed { 115 creds, err := util.ParseRegistryCreds(c.Creds) 116 if err != nil { 117 return err 118 } 119 registryCreds = creds 120 } 121 122 var writer io.Writer 123 if !c.Quiet { 124 writer = os.Stderr 125 } 126 127 var manifestType string 128 if c.Flag("format").Changed { 129 switch c.String("format") { 130 case "oci": 131 manifestType = imgspecv1.MediaTypeImageManifest 132 case "v2s1": 133 manifestType = manifest.DockerV2Schema1SignedMediaType 134 case "v2s2", "docker": 135 manifestType = manifest.DockerV2Schema2MediaType 136 default: 137 return fmt.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", c.String("format")) 138 } 139 } 140 141 dockerRegistryOptions := image.DockerRegistryOptions{ 142 DockerRegistryCreds: registryCreds, 143 DockerCertPath: certPath, 144 } 145 if c.IsSet("tls-verify") { 146 dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.TlsVerify) 147 } 148 149 so := image.SigningOptions{ 150 RemoveSignatures: removeSignatures, 151 SignBy: signBy, 152 } 153 154 return runtime.Push(getContext(), srcName, destName, manifestType, c.Authfile, c.String("digestfile"), c.SignaturePolicy, writer, c.Compress, so, &dockerRegistryOptions, nil) 155 }