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  }