package main import ( "fmt" "io" "os" "strings" "github.com/containers/image/directory" "github.com/containers/image/manifest" "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/util" imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "github.com/urfave/cli" ) var ( pushFlags = []cli.Flag{ cli.StringFlag{ Name: "signature-policy", Usage: "`Pathname` of signature policy file (not usually used)", Hidden: true, }, cli.StringFlag{ Name: "creds", Usage: "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry", }, cli.StringFlag{ Name: "cert-dir", Usage: "`Pathname` of a directory containing TLS certificates and keys", }, cli.BoolFlag{ Name: "compress", Usage: "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)", }, cli.StringFlag{ Name: "format, f", Usage: "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)", }, cli.BoolTFlag{ Name: "tls-verify", Usage: "Require HTTPS and verify certificates when contacting registries (default: true)", }, cli.BoolFlag{ Name: "remove-signatures", Usage: "Discard any pre-existing signatures in the image", }, cli.StringFlag{ Name: "sign-by", Usage: "Add a signature at the destination using the specified key", }, cli.BoolFlag{ Name: "quiet, q", Usage: "Don't output progress information when pushing images", }, cli.StringFlag{ Name: "authfile", Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json. Use REGISTRY_AUTH_FILE environment variable to override. ", }, } pushDescription = fmt.Sprintf(` Pushes an image to a specified location. The Image "DESTINATION" uses a "transport":"details" format. See podman-push(1) section "DESTINATION" for the expected format`) pushCommand = cli.Command{ Name: "push", Usage: "Push an image to a specified destination", Description: pushDescription, Flags: sortFlags(pushFlags), Action: pushCmd, ArgsUsage: "IMAGE DESTINATION", OnUsageError: usageErrorHandler, } ) func pushCmd(c *cli.Context) error { var ( registryCreds *types.DockerAuthConfig destName string ) args := c.Args() if len(args) == 0 || len(args) > 2 { return errors.New("podman push requires at least one image name, and optionally a second to specify a different destination name") } srcName := args[0] switch len(args) { case 1: destName = args[0] case 2: destName = args[1] } if err := validateFlags(c, pushFlags); err != nil { return err } // --compress and --format can only be used for the "dir" transport splitArg := strings.SplitN(destName, ":", 2) if c.IsSet("compress") || c.IsSet("format") { if splitArg[0] != directory.Transport.Name() { return errors.Errorf("--compress and --format can be set only when pushing to a directory using the 'dir' transport") } } certPath := c.String("cert-dir") removeSignatures := c.Bool("remove-signatures") signBy := c.String("sign-by") if c.IsSet("creds") { creds, err := util.ParseRegistryCreds(c.String("creds")) if err != nil { return err } registryCreds = creds } runtime, err := libpodruntime.GetRuntime(c) if err != nil { return errors.Wrapf(err, "could not create runtime") } defer runtime.Shutdown(false) var writer io.Writer if !c.Bool("quiet") { writer = os.Stderr } var manifestType string if c.IsSet("format") { switch c.String("format") { case "oci": manifestType = imgspecv1.MediaTypeImageManifest case "v2s1": manifestType = manifest.DockerV2Schema1SignedMediaType case "v2s2", "docker": manifestType = manifest.DockerV2Schema2MediaType default: return fmt.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", c.String("format")) } } dockerRegistryOptions := image.DockerRegistryOptions{ DockerRegistryCreds: registryCreds, DockerCertPath: certPath, } if c.IsSet("tls-verify") { dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!c.BoolT("tls-verify")) } so := image.SigningOptions{ RemoveSignatures: removeSignatures, SignBy: signBy, } newImage, err := runtime.ImageRuntime().NewFromLocal(srcName) if err != nil { return err } authfile := getAuthFile(c.String("authfile")) return newImage.PushImageToHeuristicDestination(getContext(), destName, manifestType, authfile, c.String("signature-policy"), writer, c.Bool("compress"), so, &dockerRegistryOptions, nil) }