summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/containers/checkpoint.go4
-rw-r--r--cmd/podman/containers/restore.go72
-rw-r--r--cmd/podman/system/service_abi.go13
3 files changed, 60 insertions, 29 deletions
diff --git a/cmd/podman/containers/checkpoint.go b/cmd/podman/containers/checkpoint.go
index f24e77106..40d689c4d 100644
--- a/cmd/podman/containers/checkpoint.go
+++ b/cmd/podman/containers/checkpoint.go
@@ -68,6 +68,10 @@ func init() {
flags.BoolVarP(&checkpointOptions.PreCheckPoint, "pre-checkpoint", "P", false, "Dump container's memory information only, leave the container running")
flags.BoolVar(&checkpointOptions.WithPrevious, "with-previous", false, "Checkpoint container with pre-checkpoint images")
+ createImageFlagName := "create-image"
+ flags.StringVarP(&checkpointOptions.CreateImage, createImageFlagName, "", "", "Create checkpoint image with specified name")
+ _ = checkpointCommand.RegisterFlagCompletionFunc(createImageFlagName, completion.AutocompleteNone)
+
flags.StringP("compress", "c", "zstd", "Select compression algorithm (gzip, none, zstd) for checkpoint archive.")
_ = checkpointCommand.RegisterFlagCompletionFunc("compress", common.AutocompleteCheckpointCompressType)
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index 3b51f5f17..eeda5a05f 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -10,9 +10,9 @@ import (
"github.com/containers/podman/v4/cmd/podman/registry"
"github.com/containers/podman/v4/cmd/podman/utils"
"github.com/containers/podman/v4/cmd/podman/validate"
+ "github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/rootless"
- "github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -23,15 +23,16 @@ var (
Restores a container from a checkpoint. The container name or ID can be used.
`
restoreCommand = &cobra.Command{
- Use: "restore [options] CONTAINER [CONTAINER...]",
+ Use: "restore [options] CONTAINER|IMAGE [CONTAINER|IMAGE...]",
Short: "Restores one or more containers from a checkpoint",
Long: restoreDescription,
RunE: restore,
Args: func(cmd *cobra.Command, args []string) error {
return validate.CheckAllLatestAndCIDFile(cmd, args, true, false)
},
- ValidArgsFunction: common.AutocompleteContainers,
+ ValidArgsFunction: common.AutocompleteContainersAndImages,
Example: `podman container restore ctrID
+ podman container restore imageID
podman container restore --latest
podman container restore --all`,
}
@@ -60,7 +61,7 @@ func init() {
_ = restoreCommand.RegisterFlagCompletionFunc(importFlagName, completion.AutocompleteDefault)
nameFlagName := "name"
- flags.StringVarP(&restoreOptions.Name, nameFlagName, "n", "", "Specify new name for container restored from exported checkpoint (only works with --import)")
+ flags.StringVarP(&restoreOptions.Name, nameFlagName, "n", "", "Specify new name for container restored from exported checkpoint (only works with image or --import)")
_ = restoreCommand.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone)
importPreviousFlagName := "import-previous"
@@ -78,7 +79,7 @@ func init() {
)
_ = restoreCommand.RegisterFlagCompletionFunc("publish", completion.AutocompleteNone)
- flags.StringVar(&restoreOptions.Pod, "pod", "", "Restore container into existing Pod (only works with --import)")
+ flags.StringVar(&restoreOptions.Pod, "pod", "", "Restore container into existing Pod (only works with image or --import)")
_ = restoreCommand.RegisterFlagCompletionFunc("pod", common.AutocompletePodsRunning)
flags.BoolVar(
@@ -95,25 +96,51 @@ func restore(cmd *cobra.Command, args []string) error {
var errs utils.OutputErrors
podmanStart := time.Now()
if rootless.IsRootless() {
- return errors.New("restoring a container requires root")
+ return fmt.Errorf("restoring a container requires root")
}
- if restoreOptions.Import == "" && restoreOptions.ImportPrevious != "" {
- return errors.Errorf("--import-previous can only be used with --import")
+
+ // Find out if this is an image
+ inspectOpts := entities.InspectOptions{}
+ imgData, _, err := registry.ImageEngine().Inspect(context.Background(), args, inspectOpts)
+ if err != nil {
+ return err
}
- if restoreOptions.Import == "" && restoreOptions.IgnoreRootFS {
- return errors.Errorf("--ignore-rootfs can only be used with --import")
+
+ hostInfo, err := registry.ContainerEngine().Info(context.Background())
+ if err != nil {
+ return err
}
- if restoreOptions.Import == "" && restoreOptions.IgnoreVolumes {
- return errors.Errorf("--ignore-volumes can only be used with --import")
+
+ for i := range imgData {
+ restoreOptions.CheckpointImage = true
+ checkpointRuntimeName, found := imgData[i].Annotations[define.CheckpointAnnotationRuntimeName]
+ if !found {
+ return fmt.Errorf("image is not a checkpoint: %s", imgData[i].ID)
+ }
+ if hostInfo.Host.OCIRuntime.Name != checkpointRuntimeName {
+ return fmt.Errorf("container image \"%s\" requires runtime: \"%s\"", imgData[i].ID, checkpointRuntimeName)
+ }
+ }
+
+ notImport := (!restoreOptions.CheckpointImage && restoreOptions.Import == "")
+
+ if notImport && restoreOptions.ImportPrevious != "" {
+ return fmt.Errorf("--import-previous can only be used with image or --import")
}
- if restoreOptions.Import == "" && restoreOptions.Name != "" {
- return errors.Errorf("--name can only be used with --import")
+ if notImport && restoreOptions.IgnoreRootFS {
+ return fmt.Errorf("--ignore-rootfs can only be used with image or --import")
}
- if restoreOptions.Import == "" && restoreOptions.Pod != "" {
- return errors.Errorf("--pod can only be used with --import")
+ if notImport && restoreOptions.IgnoreVolumes {
+ return fmt.Errorf("--ignore-volumes can only be used with image or --import")
+ }
+ if notImport && restoreOptions.Name != "" {
+ return fmt.Errorf("--name can only be used with image or --import")
+ }
+ if notImport && restoreOptions.Pod != "" {
+ return fmt.Errorf("--pod can only be used with image or --import")
}
if restoreOptions.Name != "" && restoreOptions.TCPEstablished {
- return errors.Errorf("--tcp-established cannot be used with --name")
+ return fmt.Errorf("--tcp-established cannot be used with --name")
}
inputPorts, err := cmd.Flags().GetStringSlice("publish")
@@ -125,17 +152,20 @@ func restore(cmd *cobra.Command, args []string) error {
argLen := len(args)
if restoreOptions.Import != "" {
if restoreOptions.All || restoreOptions.Latest {
- return errors.Errorf("Cannot use --import with --all or --latest")
+ return fmt.Errorf("cannot use --import with --all or --latest")
}
if argLen > 0 {
- return errors.Errorf("Cannot use --import with positional arguments")
+ return fmt.Errorf("cannot use --import with positional arguments")
}
}
if (restoreOptions.All || restoreOptions.Latest) && argLen > 0 {
- return errors.Errorf("--all or --latest and containers cannot be used together")
+ return fmt.Errorf("--all or --latest and containers cannot be used together")
}
if argLen < 1 && !restoreOptions.All && !restoreOptions.Latest && restoreOptions.Import == "" {
- return errors.Errorf("you must provide at least one name or id")
+ return fmt.Errorf("you must provide at least one name or id")
+ }
+ if argLen > 1 && restoreOptions.Name != "" {
+ return fmt.Errorf("--name can only be used with one checkpoint image")
}
responses, err := registry.ContainerEngine().ContainerRestore(context.Background(), args, restoreOptions)
if err != nil {
diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go
index d6b42ed29..f8abea3aa 100644
--- a/cmd/podman/system/service_abi.go
+++ b/cmd/podman/system/service_abi.go
@@ -23,7 +23,7 @@ import (
func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities.ServiceOptions) error {
var (
- listener *net.Listener
+ listener net.Listener
err error
)
@@ -44,17 +44,15 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
// If it is activated by systemd, use the first LISTEN_FD (3)
// instead of opening the socket file.
f := os.NewFile(uintptr(3), "podman.sock")
- l, err := net.FileListener(f)
+ listener, err = net.FileListener(f)
if err != nil {
return err
}
- listener = &l
} else {
- l, err := net.Listen(uri.Scheme, path)
+ listener, err = net.Listen(uri.Scheme, path)
if err != nil {
return errors.Wrapf(err, "unable to create socket")
}
- listener = &l
}
case "tcp":
host := uri.Host
@@ -62,11 +60,10 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
// For backward compatibility, support "tcp:<host>:<port>" and "tcp://<host>:<port>"
host = uri.Opaque
}
- l, err := net.Listen(uri.Scheme, host)
+ listener, err = net.Listen(uri.Scheme, host)
if err != nil {
return errors.Wrapf(err, "unable to create socket %v", host)
}
- listener = &l
default:
logrus.Debugf("Attempting API Service endpoint scheme %q", uri.Scheme)
}
@@ -101,7 +98,7 @@ func restService(flags *pflag.FlagSet, cfg *entities.PodmanConfig, opts entities
err = server.Serve()
if listener != nil {
- _ = (*listener).Close()
+ _ = listener.Close()
}
return err
}