summaryrefslogtreecommitdiff
path: root/cmd/podmanV2/images
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podmanV2/images')
-rw-r--r--cmd/podmanV2/images/import.go87
-rw-r--r--cmd/podmanV2/images/load.go61
-rw-r--r--cmd/podmanV2/images/push.go127
-rw-r--r--cmd/podmanV2/images/save.go87
4 files changed, 362 insertions, 0 deletions
diff --git a/cmd/podmanV2/images/import.go b/cmd/podmanV2/images/import.go
new file mode 100644
index 000000000..09a15585f
--- /dev/null
+++ b/cmd/podmanV2/images/import.go
@@ -0,0 +1,87 @@
+package images
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/hashicorp/go-multierror"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ importDescription = `Create a container image from the contents of the specified tarball (.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz).
+
+ Note remote tar balls can be specified, via web address.
+ Optionally tag the image. You can specify the instructions using the --change option.`
+ importCommand = &cobra.Command{
+ Use: "import [flags] PATH [REFERENCE]",
+ Short: "Import a tarball to create a filesystem image",
+ Long: importDescription,
+ RunE: importCon,
+ PersistentPreRunE: preRunE,
+ Example: `podman import http://example.com/ctr.tar url-image
+ cat ctr.tar | podman -q import --message "importing the ctr.tar tarball" - image-imported
+ cat ctr.tar | podman import -`,
+ }
+)
+
+var (
+ importOpts entities.ImageImportOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: importCommand,
+ })
+
+ importCommand.SetHelpTemplate(registry.HelpTemplate())
+ importCommand.SetUsageTemplate(registry.UsageTemplate())
+ flags := importCommand.Flags()
+ flags.StringArrayVarP(&importOpts.Changes, "change", "c", []string{}, "Apply the following possible instructions to the created image (default []): CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | STOPSIGNAL | USER | VOLUME | WORKDIR")
+ flags.StringVarP(&importOpts.Message, "message", "m", "", "Set commit message for imported image")
+ flags.BoolVarP(&importOpts.Quiet, "quiet", "q", false, "Suppress output")
+}
+
+func importCon(cmd *cobra.Command, args []string) error {
+ var (
+ source string
+ reference string
+ )
+ switch len(args) {
+ case 0:
+ return errors.Errorf("need to give the path to the tarball, or must specify a tarball of '-' for stdin")
+ case 1:
+ source = args[0]
+ case 2:
+ source = args[0]
+ // TODO when save is merged, we need to process reference
+ // like it is done in there or we end up with docker.io prepends
+ // instead of the localhost ones
+ reference = args[1]
+ default:
+ return errors.Errorf("too many arguments. Usage TARBALL [REFERENCE]")
+ }
+ errFileName := parse.ValidateFileName(source)
+ errURL := parse.ValidURL(source)
+ if errURL == nil {
+ importOpts.SourceIsURL = true
+ }
+ if errFileName != nil && errURL != nil {
+ return multierror.Append(errFileName, errURL)
+ }
+
+ importOpts.Source = source
+ importOpts.Reference = reference
+
+ response, err := registry.ImageEngine().Import(context.Background(), importOpts)
+ if err != nil {
+ return err
+ }
+ fmt.Println(response.Id)
+ return nil
+}
diff --git a/cmd/podmanV2/images/load.go b/cmd/podmanV2/images/load.go
new file mode 100644
index 000000000..f60dc4908
--- /dev/null
+++ b/cmd/podmanV2/images/load.go
@@ -0,0 +1,61 @@
+package images
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ loadDescription = "Loads an image from a locally stored archive (tar file) into container storage."
+ loadCommand = &cobra.Command{
+ Use: "load [flags] [NAME[:TAG]]",
+ Short: "Load an image from container archive",
+ Long: loadDescription,
+ RunE: load,
+ Args: cobra.MaximumNArgs(1),
+ PersistentPreRunE: preRunE,
+ }
+)
+
+var (
+ loadOpts entities.ImageLoadOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: loadCommand,
+ })
+
+ loadCommand.SetHelpTemplate(registry.HelpTemplate())
+ loadCommand.SetUsageTemplate(registry.UsageTemplate())
+ flags := loadCommand.Flags()
+ flags.StringVarP(&loadOpts.Input, "input", "i", "", "Read from specified archive file (default: stdin)")
+ flags.BoolVarP(&loadOpts.Quiet, "quiet", "q", false, "Suppress the output")
+ flags.StringVar(&loadOpts.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file")
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("signature-policy")
+ }
+
+}
+
+func load(cmd *cobra.Command, args []string) error {
+ if len(args) > 0 {
+ repo, err := image.NormalizedTag(args[0])
+ if err != nil {
+ return err
+ }
+ loadOpts.Name = repo.Name()
+ }
+ response, err := registry.ImageEngine().Load(context.Background(), loadOpts)
+ if err != nil {
+ return err
+ }
+ fmt.Println("Loaded image: " + response.Name)
+ return nil
+}
diff --git a/cmd/podmanV2/images/push.go b/cmd/podmanV2/images/push.go
new file mode 100644
index 000000000..82cc0c486
--- /dev/null
+++ b/cmd/podmanV2/images/push.go
@@ -0,0 +1,127 @@
+package images
+
+import (
+ buildahcli "github.com/containers/buildah/pkg/cli"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ "github.com/spf13/pflag"
+)
+
+// pushOptionsWrapper wraps entities.ImagepushOptions and prevents leaking
+// CLI-only fields into the API types.
+type pushOptionsWrapper struct {
+ entities.ImagePushOptions
+ TLSVerifyCLI bool // CLI only
+}
+
+var (
+ pushOptions = pushOptionsWrapper{}
+ pushDescription = `Pushes a source image to a specified destination.
+
+ The Image "DESTINATION" uses a "transport":"details" format. See podman-push(1) section "DESTINATION" for the expected format.`
+
+ // Command: podman push
+ pushCmd = &cobra.Command{
+ Use: "push [flags] SOURCE DESTINATION",
+ Short: "Push an image to a specified destination",
+ Long: pushDescription,
+ PreRunE: preRunE,
+ RunE: imagePush,
+ Example: `podman push imageID docker://registry.example.com/repository:tag
+ podman push imageID oci-archive:/path/to/layout:image:tag`,
+ }
+
+ // Command: podman image push
+ // It's basically a clone of `pushCmd` with the exception of being a
+ // child of the images command.
+ imagePushCmd = &cobra.Command{
+ Use: pushCmd.Use,
+ Short: pushCmd.Short,
+ Long: pushCmd.Long,
+ PreRunE: pushCmd.PreRunE,
+ RunE: pushCmd.RunE,
+ Example: `podman image push imageID docker://registry.example.com/repository:tag
+ podman image push imageID oci-archive:/path/to/layout:image:tag`,
+ }
+)
+
+func init() {
+ // push
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: pushCmd,
+ })
+
+ pushCmd.SetHelpTemplate(registry.HelpTemplate())
+ pushCmd.SetUsageTemplate(registry.UsageTemplate())
+
+ flags := pushCmd.Flags()
+ pushFlags(flags)
+
+ // images push
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: imagePushCmd,
+ Parent: imageCmd,
+ })
+
+ imagePushCmd.SetHelpTemplate(registry.HelpTemplate())
+ imagePushCmd.SetUsageTemplate(registry.UsageTemplate())
+ pushFlags(imagePushCmd.Flags())
+}
+
+// pushFlags set the flags for the push command.
+func pushFlags(flags *pflag.FlagSet) {
+ flags.StringVar(&pushOptions.Authfile, "authfile", buildahcli.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&pushOptions.CertDir, "cert-dir", "", "Path to a directory containing TLS certificates and keys")
+ flags.BoolVar(&pushOptions.Compress, "compress", false, "Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)")
+ flags.StringVar(&pushOptions.Credentials, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
+ flags.StringVar(&pushOptions.DigestFile, "digestfile", "", "Write the digest of the pushed image to the specified file")
+ flags.StringVarP(&pushOptions.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)")
+ flags.BoolVarP(&pushOptions.Quiet, "quiet", "q", false, "Suppress output information when pushing images")
+ flags.BoolVar(&pushOptions.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image")
+ flags.StringVar(&pushOptions.SignaturePolicy, "signature-policy", "", "Path to a signature-policy file")
+ flags.StringVar(&pushOptions.SignBy, "sign-by", "", "Add a signature at the destination using the specified key")
+ flags.BoolVar(&pushOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
+
+ if registry.IsRemote() {
+ _ = flags.MarkHidden("authfile")
+ _ = flags.MarkHidden("cert-dir")
+ _ = flags.MarkHidden("compress")
+ _ = flags.MarkHidden("quiet")
+ _ = flags.MarkHidden("signature-policy")
+ _ = flags.MarkHidden("tls-verify")
+ }
+}
+
+// imagePush is implement the command for pushing images.
+func imagePush(cmd *cobra.Command, args []string) error {
+ var source, destination string
+ switch len(args) {
+ case 1:
+ source = args[0]
+ case 2:
+ source = args[0]
+ destination = args[1]
+ case 0:
+ fallthrough
+ default:
+ return errors.New("push requires at least one image name, or optionally a second to specify a different destination")
+ }
+
+ pushOptsAPI := pushOptions.ImagePushOptions
+ // TLS verification in c/image is controlled via a `types.OptionalBool`
+ // which allows for distinguishing among set-true, set-false, unspecified
+ // which is important to implement a sane way of dealing with defaults of
+ // boolean CLI flags.
+ if cmd.Flags().Changed("tls-verify") {
+ pushOptsAPI.TLSVerify = types.NewOptionalBool(pushOptions.TLSVerifyCLI)
+ }
+
+ // Let's do all the remaining Yoga in the API to prevent us from scattering
+ // logic across (too) many parts of the code.
+ return registry.ImageEngine().Push(registry.GetContext(), source, destination, pushOptsAPI)
+}
diff --git a/cmd/podmanV2/images/save.go b/cmd/podmanV2/images/save.go
new file mode 100644
index 000000000..ae39b7bce
--- /dev/null
+++ b/cmd/podmanV2/images/save.go
@@ -0,0 +1,87 @@
+package images
+
+import (
+ "context"
+ "os"
+ "strings"
+
+ "github.com/containers/libpod/libpod/define"
+
+ "github.com/containers/libpod/cmd/podmanV2/parse"
+ "github.com/containers/libpod/cmd/podmanV2/registry"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+ "golang.org/x/crypto/ssh/terminal"
+)
+
+var validFormats = []string{define.OCIManifestDir, define.OCIArchive, define.V2s2ManifestDir, define.V2s2Archive}
+
+var (
+ saveDescription = `Save an image to docker-archive or oci-archive on the local machine. Default is docker-archive.`
+
+ saveCommand = &cobra.Command{
+ Use: "save [flags] IMAGE",
+ Short: "Save image to an archive",
+ Long: saveDescription,
+ PersistentPreRunE: preRunE,
+ RunE: save,
+ Args: func(cmd *cobra.Command, args []string) error {
+ if len(args) == 0 {
+ return errors.Errorf("need at least 1 argument")
+ }
+ format, err := cmd.Flags().GetString("format")
+ if err != nil {
+ return err
+ }
+ if !util.StringInSlice(format, validFormats) {
+ return errors.Errorf("format value must be one of %s", strings.Join(validFormats, " "))
+ }
+ return nil
+ },
+ Example: `podman save --quiet -o myimage.tar imageID
+ podman save --format docker-dir -o ubuntu-dir ubuntu
+ podman save > alpine-all.tar alpine:latest`,
+ }
+)
+
+var (
+ saveOpts entities.ImageSaveOptions
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: saveCommand,
+ })
+ flags := saveCommand.Flags()
+ flags.BoolVar(&saveOpts.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)")
+ flags.StringVar(&saveOpts.Format, "format", define.V2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)")
+ flags.StringVarP(&saveOpts.Output, "output", "o", "", "Write to a specified file (default: stdout, which must be redirected)")
+ flags.BoolVarP(&saveOpts.Quiet, "quiet", "q", false, "Suppress the output")
+
+}
+
+func save(cmd *cobra.Command, args []string) error {
+ var (
+ tags []string
+ )
+ if cmd.Flag("compress").Changed && (saveOpts.Format != define.OCIManifestDir && saveOpts.Format != define.V2s2ManifestDir && saveOpts.Format == "") {
+ return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'")
+ }
+ if len(saveOpts.Output) == 0 {
+ fi := os.Stdout
+ if terminal.IsTerminal(int(fi.Fd())) {
+ return errors.Errorf("refusing to save to terminal. Use -o flag or redirect")
+ }
+ saveOpts.Output = "/dev/stdout"
+ }
+ if err := parse.ValidateFileName(saveOpts.Output); err != nil {
+ return err
+ }
+ if len(args) > 1 {
+ tags = args[1:]
+ }
+ return registry.ImageEngine().Save(context.Background(), args[0], tags, saveOpts)
+}