summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/containers/checkpoint.go4
-rw-r--r--cmd/podman/containers/restore.go4
-rw-r--r--docs/source/markdown/podman-container-checkpoint.1.md6
-rw-r--r--docs/source/markdown/podman-container-restore.1.md7
-rw-r--r--libpod/container_api.go3
-rw-r--r--libpod/container_internal_linux.go73
-rw-r--r--pkg/api/handlers/libpod/containers.go1
-rw-r--r--pkg/checkpoint/checkpoint_restore.go18
-rw-r--r--pkg/domain/entities/containers.go2
-rw-r--r--pkg/domain/infra/abi/containers.go2
10 files changed, 116 insertions, 4 deletions
diff --git a/cmd/podman/containers/checkpoint.go b/cmd/podman/containers/checkpoint.go
index b6dc21348..4a477eb10 100644
--- a/cmd/podman/containers/checkpoint.go
+++ b/cmd/podman/containers/checkpoint.go
@@ -57,6 +57,7 @@ func init() {
_ = checkpointCommand.RegisterFlagCompletionFunc(exportFlagName, completion.AutocompleteDefault)
flags.BoolVar(&checkpointOptions.IgnoreRootFS, "ignore-rootfs", false, "Do not include root file-system changes when exporting")
+ flags.BoolVar(&checkpointOptions.IgnoreVolumes, "ignore-volumes", false, "Do not export volumes associated with container")
validate.AddLatestFlag(checkpointCommand, &checkpointOptions.Latest)
}
@@ -68,6 +69,9 @@ func checkpoint(cmd *cobra.Command, args []string) error {
if checkpointOptions.Export == "" && checkpointOptions.IgnoreRootFS {
return errors.Errorf("--ignore-rootfs can only be used with --export")
}
+ if checkpointOptions.Export == "" && checkpointOptions.IgnoreVolumes {
+ return errors.Errorf("--ignore-volumes can only be used with --export")
+ }
responses, err := registry.ContainerEngine().ContainerCheckpoint(context.Background(), args, checkpointOptions)
if err != nil {
return err
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index 6a1d2b319..5245a68fa 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -62,6 +62,7 @@ func init() {
flags.BoolVar(&restoreOptions.IgnoreRootFS, "ignore-rootfs", false, "Do not apply root file-system changes when importing from exported checkpoint")
flags.BoolVar(&restoreOptions.IgnoreStaticIP, "ignore-static-ip", false, "Ignore IP address set via --static-ip")
flags.BoolVar(&restoreOptions.IgnoreStaticMAC, "ignore-static-mac", false, "Ignore MAC address set via --mac-address")
+ flags.BoolVar(&restoreOptions.IgnoreVolumes, "ignore-volumes", false, "Do not export volumes associated with container")
validate.AddLatestFlag(restoreCommand, &restoreOptions.Latest)
}
@@ -73,6 +74,9 @@ func restore(_ *cobra.Command, args []string) error {
if restoreOptions.Import == "" && restoreOptions.IgnoreRootFS {
return errors.Errorf("--ignore-rootfs can only be used with --import")
}
+ if restoreOptions.Import == "" && restoreOptions.IgnoreVolumes {
+ return errors.Errorf("--ignore-volumes can only be used with --import")
+ }
if restoreOptions.Import == "" && restoreOptions.Name != "" {
return errors.Errorf("--name can only be used with --import")
}
diff --git a/docs/source/markdown/podman-container-checkpoint.1.md b/docs/source/markdown/podman-container-checkpoint.1.md
index bfda782c5..6a9469156 100644
--- a/docs/source/markdown/podman-container-checkpoint.1.md
+++ b/docs/source/markdown/podman-container-checkpoint.1.md
@@ -52,6 +52,12 @@ exported to a tar.gz file it is possible with the help of **--ignore-rootfs**
to explicitly disable including changes to the root file-system into
the checkpoint archive file.
+#### **--ignore-volumes**
+
+This option must be used in combination with the **--export, -e** option.
+When this option is specified, the content of volumes associated with
+the container will not be included into the checkpoint tar.gz file.
+
## EXAMPLE
podman container checkpoint mywebserver
diff --git a/docs/source/markdown/podman-container-restore.1.md b/docs/source/markdown/podman-container-restore.1.md
index 494e7db1e..0593e6fe9 100644
--- a/docs/source/markdown/podman-container-restore.1.md
+++ b/docs/source/markdown/podman-container-restore.1.md
@@ -85,6 +85,13 @@ exported checkpoint with **--name, -n**.
Using **--ignore-static-mac** tells Podman to ignore the MAC address if it was
configured with **--mac-address** during container creation.
+
+#### **--ignore-volumes**
+
+This option must be used in combination with the **--import, -i** option.
+When restoring containers from a checkpoint tar.gz file with this option,
+the content of associated volumes will not be restored.
+
## EXAMPLE
podman container restore mywebserver
diff --git a/libpod/container_api.go b/libpod/container_api.go
index c3e1a23d2..2c7dc79c9 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -703,6 +703,9 @@ type ContainerCheckpointOptions struct {
// important to be able to restore a container multiple
// times with '--import --name'.
IgnoreStaticMAC bool
+ // IgnoreVolumes tells the API to not export or not to import
+ // the content of volumes associated with the container
+ IgnoreVolumes bool
}
// Checkpoint checkpoints a container
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 9dd39ac8c..f947d1ed9 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -791,8 +791,8 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
}
func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
- if (len(c.config.NamedVolumes) > 0) || (len(c.Dependencies()) > 0) {
- return errors.Errorf("Cannot export checkpoints of containers with named volumes or dependencies")
+ if len(c.Dependencies()) > 0 {
+ return errors.Errorf("Cannot export checkpoints of containers with dependencies")
}
logrus.Debugf("Exporting checkpoint image of container %q to %q", c.ID(), options.TargetFile)
@@ -870,6 +870,47 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
}
}
+ // Folder containing archived volumes that will be included in the export
+ expVolDir := filepath.Join(c.bundlePath(), "volumes")
+
+ // Create an archive for each volume associated with the container
+ if !options.IgnoreVolumes {
+ if err := os.MkdirAll(expVolDir, 0700); err != nil {
+ return errors.Wrapf(err, "error creating volumes export directory %q", expVolDir)
+ }
+
+ for _, v := range c.config.NamedVolumes {
+ volumeTarFilePath := filepath.Join("volumes", v.Name+".tar")
+ volumeTarFileFullPath := filepath.Join(c.bundlePath(), volumeTarFilePath)
+
+ volumeTarFile, err := os.Create(volumeTarFileFullPath)
+ if err != nil {
+ return errors.Wrapf(err, "error creating %q", volumeTarFileFullPath)
+ }
+
+ volume, err := c.runtime.GetVolume(v.Name)
+ if err != nil {
+ return err
+ }
+
+ input, err := archive.TarWithOptions(volume.MountPoint(), &archive.TarOptions{
+ Compression: archive.Uncompressed,
+ IncludeSourceDir: true,
+ })
+ if err != nil {
+ return errors.Wrapf(err, "error reading volume directory %q", v.Dest)
+ }
+
+ _, err = io.Copy(volumeTarFile, input)
+ if err != nil {
+ return err
+ }
+ volumeTarFile.Close()
+
+ includeFiles = append(includeFiles, volumeTarFilePath)
+ }
+ }
+
input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
Compression: archive.Gzip,
IncludeSourceDir: true,
@@ -898,6 +939,10 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
os.Remove(rootfsDiffPath)
os.Remove(deleteFilesList)
+ if !options.IgnoreVolumes {
+ os.RemoveAll(expVolDir)
+ }
+
return nil
}
@@ -1193,6 +1238,30 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
return err
}
+ // When restoring from an imported archive, allow restoring the content of volumes.
+ // Volumes are created in setupContainer()
+ if options.TargetFile != "" && !options.IgnoreVolumes {
+ for _, v := range c.config.NamedVolumes {
+ volumeFilePath := filepath.Join(c.bundlePath(), "volumes", v.Name+".tar")
+
+ volumeFile, err := os.Open(volumeFilePath)
+ if err != nil {
+ return errors.Wrapf(err, "Failed to open volume file %s", volumeFilePath)
+ }
+ defer volumeFile.Close()
+
+ volume, err := c.runtime.GetVolume(v.Name)
+ if err != nil {
+ return errors.Wrapf(err, "Failed to retrieve volume %s", v.Name)
+ }
+
+ mountPoint := volume.MountPoint()
+ if err := archive.UntarUncompressed(volumeFile, mountPoint, nil); err != nil {
+ return errors.Wrapf(err, "Failed to extract volume %s to %s", volumeFilePath, mountPoint)
+ }
+ }
+ }
+
// Before actually restarting the container, apply the root file-system changes
if !options.IgnoreRootfs {
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 14eb44831..6b07b1cc5 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -275,6 +275,7 @@ func Restore(w http.ResponseWriter, r *http.Request) {
Import bool `schema:"import"`
Name string `schema:"name"`
IgnoreRootFS bool `schema:"ignoreRootFS"`
+ IgnoreVolumes bool `schema:"ignoreVolumes"`
IgnoreStaticIP bool `schema:"ignoreStaticIP"`
IgnoreStaticMAC bool `schema:"ignoreStaticMAC"`
}{
diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go
index 90f629354..f6cd3b38f 100644
--- a/pkg/checkpoint/checkpoint_restore.go
+++ b/pkg/checkpoint/checkpoint_restore.go
@@ -54,6 +54,7 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
"rootfs-diff.tar",
"network.status",
"deleted.files",
+ "volumes",
},
}
dir, err := ioutil.TempDir("", "checkpoint")
@@ -83,8 +84,21 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
}
// This should not happen as checkpoints with these options are not exported.
- if (len(config.Dependencies) > 0) || (len(config.NamedVolumes) > 0) {
- return nil, errors.Errorf("Cannot import checkpoints of containers with named volumes or dependencies")
+ if len(config.Dependencies) > 0 {
+ return nil, errors.Errorf("Cannot import checkpoints of containers with dependencies")
+ }
+
+ // Volumes included in the checkpoint should not exist
+ if !restoreOptions.IgnoreVolumes {
+ for _, vol := range config.NamedVolumes {
+ exists, err := runtime.HasVolume(vol.Name)
+ if err != nil {
+ return nil, err
+ }
+ if exists {
+ return nil, errors.Errorf("volume with name %s already exists. Use --ignore-volumes to not restore content of volumes", vol.Name)
+ }
+ }
}
ctrID := config.ID
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 05b9b774e..a67ecebd5 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -173,6 +173,7 @@ type CheckpointOptions struct {
All bool
Export string
IgnoreRootFS bool
+ IgnoreVolumes bool
Keep bool
Latest bool
LeaveRunning bool
@@ -187,6 +188,7 @@ type CheckpointReport struct {
type RestoreOptions struct {
All bool
IgnoreRootFS bool
+ IgnoreVolumes bool
IgnoreStaticIP bool
IgnoreStaticMAC bool
Import string
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 721a8c3ab..f7a538934 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -487,6 +487,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
TCPEstablished: options.TCPEstablished,
TargetFile: options.Export,
IgnoreRootfs: options.IgnoreRootFS,
+ IgnoreVolumes: options.IgnoreVolumes,
KeepRunning: options.LeaveRunning,
}
@@ -525,6 +526,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
TargetFile: options.Import,
Name: options.Name,
IgnoreRootfs: options.IgnoreRootFS,
+ IgnoreVolumes: options.IgnoreVolumes,
IgnoreStaticIP: options.IgnoreStaticIP,
IgnoreStaticMAC: options.IgnoreStaticMAC,
}