mirror of
https://github.com/containers/podman.git
synced 2025-05-22 01:27:07 +08:00
Added helper functions for container migration
This adds a couple of function in structure members needed in the next commit to make container migration actually work. This just splits of the function which are not modifying existing code. Signed-off-by: Adrian Reber <areber@redhat.com>
This commit is contained in:
@ -815,6 +815,11 @@ type ContainerCheckpointOptions struct {
|
|||||||
// TCPEstablished tells the API to checkpoint a container
|
// TCPEstablished tells the API to checkpoint a container
|
||||||
// even if it contains established TCP connections
|
// even if it contains established TCP connections
|
||||||
TCPEstablished bool
|
TCPEstablished bool
|
||||||
|
// Export tells the API to write the checkpoint image to
|
||||||
|
// the filename set in TargetFile
|
||||||
|
// Import tells the API to read the checkpoint image from
|
||||||
|
// the filename set in TargetFile
|
||||||
|
TargetFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checkpoint checkpoints a container
|
// Checkpoint checkpoints a container
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"github.com/containers/storage/pkg/archive"
|
"github.com/containers/storage/pkg/archive"
|
||||||
"github.com/containers/storage/pkg/mount"
|
"github.com/containers/storage/pkg/mount"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
opentracing "github.com/opentracing/opentracing-go"
|
opentracing "github.com/opentracing/opentracing-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -1501,3 +1502,40 @@ func (c *Container) checkReadyForRemoval() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeJSONFile marshalls and writes the given data to a JSON file
|
||||||
|
// in the bundle path
|
||||||
|
func (c *Container) writeJSONFile(v interface{}, file string) (err error) {
|
||||||
|
fileJSON, err := json.MarshalIndent(v, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error writing JSON to %s for container %s", file, c.ID())
|
||||||
|
}
|
||||||
|
file = filepath.Join(c.bundlePath(), file)
|
||||||
|
if err := ioutil.WriteFile(file, fileJSON, 0644); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepareCheckpointExport writes the config and spec to
|
||||||
|
// JSON files for later export
|
||||||
|
func (c *Container) prepareCheckpointExport() (err error) {
|
||||||
|
// save live config
|
||||||
|
if err := c.writeJSONFile(c.Config(), "config.dump"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// save spec
|
||||||
|
jsonPath := filepath.Join(c.bundlePath(), "config.json")
|
||||||
|
g, err := generate.NewFromFile(jsonPath)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debugf("generating spec for container %q failed with %v", c.ID(), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.writeJSONFile(g.Spec(), "spec.dump"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ package libpod
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -25,6 +26,7 @@ import (
|
|||||||
"github.com/containers/libpod/pkg/lookup"
|
"github.com/containers/libpod/pkg/lookup"
|
||||||
"github.com/containers/libpod/pkg/resolvconf"
|
"github.com/containers/libpod/pkg/resolvconf"
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"github.com/containers/libpod/pkg/rootless"
|
||||||
|
"github.com/containers/storage/pkg/archive"
|
||||||
securejoin "github.com/cyphar/filepath-securejoin"
|
securejoin "github.com/cyphar/filepath-securejoin"
|
||||||
"github.com/opencontainers/runc/libcontainer/user"
|
"github.com/opencontainers/runc/libcontainer/user"
|
||||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
@ -496,6 +498,42 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) exportCheckpoint(dest string) (err error) {
|
||||||
|
logrus.Debugf("Exporting checkpoint image of container %q to %q", c.ID(), dest)
|
||||||
|
input, err := archive.TarWithOptions(c.bundlePath(), &archive.TarOptions{
|
||||||
|
Compression: archive.Gzip,
|
||||||
|
IncludeSourceDir: true,
|
||||||
|
IncludeFiles: []string{
|
||||||
|
"checkpoint",
|
||||||
|
"artifacts",
|
||||||
|
"ctr.log",
|
||||||
|
"config.dump",
|
||||||
|
"spec.dump",
|
||||||
|
"network.status"},
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error reading checkpoint directory %q", c.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile, err := os.Create(dest)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "error creating checkpoint export file %q", dest)
|
||||||
|
}
|
||||||
|
defer outFile.Close()
|
||||||
|
|
||||||
|
if err := os.Chmod(dest, 0600); err != nil {
|
||||||
|
return errors.Wrapf(err, "cannot chmod %q", dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(outFile, input)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Container) checkpointRestoreSupported() (err error) {
|
func (c *Container) checkpointRestoreSupported() (err error) {
|
||||||
if !criu.CheckForCriu() {
|
if !criu.CheckForCriu() {
|
||||||
return errors.Errorf("Checkpoint/Restore requires at least CRIU %d", criu.MinCriuVersion)
|
return errors.Errorf("Checkpoint/Restore requires at least CRIU %d", criu.MinCriuVersion)
|
||||||
@ -561,15 +599,50 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !options.Keep {
|
if !options.Keep {
|
||||||
// Remove log file
|
cleanup := []string{
|
||||||
os.Remove(filepath.Join(c.bundlePath(), "dump.log"))
|
"dump.log",
|
||||||
// Remove statistic file
|
"stats-dump",
|
||||||
os.Remove(filepath.Join(c.bundlePath(), "stats-dump"))
|
"config.dump",
|
||||||
|
"spec.dump",
|
||||||
|
}
|
||||||
|
for _, delete := range cleanup {
|
||||||
|
file := filepath.Join(c.bundlePath(), delete)
|
||||||
|
os.Remove(file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.save()
|
return c.save()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Container) importCheckpoint(input string) (err error) {
|
||||||
|
archiveFile, err := os.Open(input)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Failed to open checkpoint archive %s for import", input)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer archiveFile.Close()
|
||||||
|
options := &archive.TarOptions{
|
||||||
|
ExcludePatterns: []string{
|
||||||
|
// config.dump and spec.dump are only required
|
||||||
|
// container creation
|
||||||
|
"config.dump",
|
||||||
|
"spec.dump",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err = archive.Untar(archiveFile, c.bundlePath(), options)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", input)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the newly created config.json exists on disk
|
||||||
|
g := generate.NewFromSpec(c.config.Spec)
|
||||||
|
if err = c.saveSpec(g.Spec()); err != nil {
|
||||||
|
return errors.Wrap(err, "Saving imported container specification for restore failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (err error) {
|
func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (err error) {
|
||||||
|
|
||||||
if err := c.checkpointRestoreSupported(); err != nil {
|
if err := c.checkpointRestoreSupported(); err != nil {
|
||||||
|
Reference in New Issue
Block a user