aboutsummaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2021-01-08 10:41:05 -0500
committerGitHub <noreply@github.com>2021-01-08 10:41:05 -0500
commit49db79e735acd2c693762eaff62680cd9a8cb60b (patch)
treea2c4346700f7ba85acdd313293817e5a02701897 /libpod
parenta0b432d29d18c7385c2c976249bdc4eec95d335a (diff)
parent1215bd9ffd9ac068f30212a68f36c7d77542f92d (diff)
downloadpodman-49db79e735acd2c693762eaff62680cd9a8cb60b.tar.gz
podman-49db79e735acd2c693762eaff62680cd9a8cb60b.tar.bz2
podman-49db79e735acd2c693762eaff62680cd9a8cb60b.zip
Merge pull request #8781 from rst0git/cr-volumes
Add support for checkpoint/restore of containers with volumes
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_api.go3
-rw-r--r--libpod/container_internal_linux.go87
2 files changed, 81 insertions, 9 deletions
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 bc8f0f932..ac20e1f25 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -798,11 +798,11 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
return nil
}
-func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) error {
- if (len(c.config.NamedVolumes) > 0) || (len(c.Dependencies()) > 0) {
- return errors.Errorf("Cannot export checkpoints of containers with named volumes or dependencies")
+func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
+ 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(), dest)
+ logrus.Debugf("Exporting checkpoint image of container %q to %q", c.ID(), options.TargetFile)
includeFiles := []string{
"checkpoint",
@@ -815,7 +815,7 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) error {
// Get root file-system changes included in the checkpoint archive
rootfsDiffPath := filepath.Join(c.bundlePath(), "rootfs-diff.tar")
deleteFilesList := filepath.Join(c.bundlePath(), "deleted.files")
- if !ignoreRootfs {
+ if !options.IgnoreRootfs {
// To correctly track deleted files, let's go through the output of 'podman diff'
tarFiles, err := c.runtime.GetDiff("", c.ID())
if err != nil {
@@ -878,6 +878,47 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) 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,
@@ -888,13 +929,13 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) error {
return errors.Wrapf(err, "error reading checkpoint directory %q", c.ID())
}
- outFile, err := os.Create(dest)
+ outFile, err := os.Create(options.TargetFile)
if err != nil {
- return errors.Wrapf(err, "error creating checkpoint export file %q", dest)
+ return errors.Wrapf(err, "error creating checkpoint export file %q", options.TargetFile)
}
defer outFile.Close()
- if err := os.Chmod(dest, 0600); err != nil {
+ if err := os.Chmod(options.TargetFile, 0600); err != nil {
return err
}
@@ -906,6 +947,10 @@ func (c *Container) exportCheckpoint(dest string, ignoreRootfs bool) error {
os.Remove(rootfsDiffPath)
os.Remove(deleteFilesList)
+ if !options.IgnoreVolumes {
+ os.RemoveAll(expVolDir)
+ }
+
return nil
}
@@ -971,7 +1016,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
defer c.newContainerEvent(events.Checkpoint)
if options.TargetFile != "" {
- if err = c.exportCheckpoint(options.TargetFile, options.IgnoreRootfs); err != nil {
+ if err = c.exportCheckpoint(options); err != nil {
return err
}
}
@@ -1201,6 +1246,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")