summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go40
-rw-r--r--libpod/container_api.go20
-rw-r--r--libpod/container_copy_linux.go3
-rw-r--r--libpod/container_inspect.go33
-rw-r--r--libpod/container_internal_linux.go120
-rw-r--r--libpod/oci_conmon_linux.go24
-rw-r--r--libpod/runtime_ctr.go12
7 files changed, 209 insertions, 43 deletions
diff --git a/libpod/container.go b/libpod/container.go
index 4b9bea5fc..f3f4b27b7 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -1173,6 +1173,46 @@ func (c *Container) Networks() ([]string, bool, error) {
return c.networks()
}
+// NetworkMode gets the configured network mode for the container.
+// Get actual value from the database
+func (c *Container) NetworkMode() string {
+ networkMode := ""
+ ctrSpec := c.config.Spec
+
+ switch {
+ case c.config.CreateNetNS:
+ // We actually store the network
+ // mode for Slirp and Bridge, so
+ // we can just use that
+ networkMode = string(c.config.NetMode)
+ case c.config.NetNsCtr != "":
+ networkMode = fmt.Sprintf("container:%s", c.config.NetNsCtr)
+ default:
+ // Find the spec's network namespace.
+ // If there is none, it's host networking.
+ // If there is one and it has a path, it's "ns:".
+ foundNetNS := false
+ for _, ns := range ctrSpec.Linux.Namespaces {
+ if ns.Type == spec.NetworkNamespace {
+ foundNetNS = true
+ if ns.Path != "" {
+ networkMode = fmt.Sprintf("ns:%s", ns.Path)
+ } else {
+ // We're making a network ns, but not
+ // configuring with Slirp or CNI. That
+ // means it's --net=none
+ networkMode = "none"
+ }
+ break
+ }
+ }
+ if !foundNetNS {
+ networkMode = "host"
+ }
+ }
+ return networkMode
+}
+
// Unlocked accessor for networks
func (c *Container) networks() ([]string, bool, error) {
networks, err := c.runtime.state.GetNetworks(c)
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 390bba7bb..637f5b686 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -780,6 +780,16 @@ type ContainerCheckpointOptions struct {
// Compression tells the API which compression to use for
// the exported checkpoint archive.
Compression archive.Compression
+ // If Pod is set the container should be restored into the
+ // given Pod. If Pod is empty it is a restore without a Pod.
+ // Restoring a non Pod container into a Pod or a Pod container
+ // without a Pod is theoretically possible, but will
+ // probably not work if a PID namespace is shared.
+ // A shared PID namespace means that a Pod container has PID 1
+ // in the infrastructure container, but without the infrastructure
+ // container no PID 1 will be in the namespace and that is not
+ // possible.
+ Pod string
}
// Checkpoint checkpoints a container
@@ -811,7 +821,11 @@ func (c *Container) Checkpoint(ctx context.Context, options ContainerCheckpointO
// Restore restores a container
func (c *Container) Restore(ctx context.Context, options ContainerCheckpointOptions) error {
- logrus.Debugf("Trying to restore container %s", c.ID())
+ if options.Pod == "" {
+ logrus.Debugf("Trying to restore container %s", c.ID())
+ } else {
+ logrus.Debugf("Trying to restore container %s into pod %s", c.ID(), options.Pod)
+ }
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -840,7 +854,7 @@ func (c *Container) ShouldRestart(ctx context.Context) bool {
// CopyFromArchive copies the contents from the specified tarStream to path
// *inside* the container.
-func (c *Container) CopyFromArchive(ctx context.Context, containerPath string, chown bool, tarStream io.Reader) (func() error, error) {
+func (c *Container) CopyFromArchive(ctx context.Context, containerPath string, chown bool, rename map[string]string, tarStream io.Reader) (func() error, error) {
if !c.batched {
c.lock.Lock()
defer c.lock.Unlock()
@@ -850,7 +864,7 @@ func (c *Container) CopyFromArchive(ctx context.Context, containerPath string, c
}
}
- return c.copyFromArchive(ctx, containerPath, chown, tarStream)
+ return c.copyFromArchive(ctx, containerPath, chown, rename, tarStream)
}
// CopyToArchive copies the contents from the specified path *inside* the
diff --git a/libpod/container_copy_linux.go b/libpod/container_copy_linux.go
index 01e7ecacb..a35824289 100644
--- a/libpod/container_copy_linux.go
+++ b/libpod/container_copy_linux.go
@@ -23,7 +23,7 @@ import (
"golang.org/x/sys/unix"
)
-func (c *Container) copyFromArchive(ctx context.Context, path string, chown bool, reader io.Reader) (func() error, error) {
+func (c *Container) copyFromArchive(ctx context.Context, path string, chown bool, rename map[string]string, reader io.Reader) (func() error, error) {
var (
mountPoint string
resolvedRoot string
@@ -89,6 +89,7 @@ func (c *Container) copyFromArchive(ctx context.Context, path string, chown bool
GIDMap: c.config.IDMappings.GIDMap,
ChownDirs: idPair,
ChownFiles: idPair,
+ Rename: rename,
}
return c.joinMountAndExec(ctx,
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 638e0b756..8c662c488 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -618,38 +618,7 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
hostConfig.Tmpfs = tmpfs
// Network mode parsing.
- networkMode := ""
- switch {
- case c.config.CreateNetNS:
- // We actually store the network
- // mode for Slirp and Bridge, so
- // we can just use that
- networkMode = string(c.config.NetMode)
- case c.config.NetNsCtr != "":
- networkMode = fmt.Sprintf("container:%s", c.config.NetNsCtr)
- default:
- // Find the spec's network namespace.
- // If there is none, it's host networking.
- // If there is one and it has a path, it's "ns:".
- foundNetNS := false
- for _, ns := range ctrSpec.Linux.Namespaces {
- if ns.Type == spec.NetworkNamespace {
- foundNetNS = true
- if ns.Path != "" {
- networkMode = fmt.Sprintf("ns:%s", ns.Path)
- } else {
- // We're making a network ns, but not
- // configuring with Slirp or CNI. That
- // means it's --net=none
- networkMode = "none"
- }
- break
- }
- }
- if !foundNetNS {
- networkMode = "host"
- }
- }
+ networkMode := c.NetworkMode()
hostConfig.NetworkMode = networkMode
// Port bindings.
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index b69ad4105..bff64aa95 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -901,8 +901,27 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
}
func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
- if len(c.Dependencies()) > 0 {
- return errors.Errorf("Cannot export checkpoints of containers with dependencies")
+ if len(c.Dependencies()) == 1 {
+ // Check if the dependency is an infra container. If it is we can checkpoint
+ // the container out of the Pod.
+ if c.config.Pod == "" {
+ return errors.Errorf("cannot export checkpoints of containers with dependencies")
+ }
+
+ pod, err := c.runtime.state.Pod(c.config.Pod)
+ if err != nil {
+ return errors.Wrapf(err, "container %s is in pod %s, but pod cannot be retrieved", c.ID(), c.config.Pod)
+ }
+ infraID, err := pod.InfraContainerID()
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve infra container ID for pod %s", c.config.Pod)
+ }
+ if c.Dependencies()[0] != infraID {
+ return errors.Errorf("cannot export checkpoints of containers with dependencies")
+ }
+ }
+ if len(c.Dependencies()) > 1 {
+ return errors.Errorf("cannot export checkpoints of containers with dependencies")
}
logrus.Debugf("Exporting checkpoint image of container %q to %q", c.ID(), options.TargetFile)
@@ -1021,9 +1040,9 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
return nil
}
-func (c *Container) checkpointRestoreSupported() error {
- if !criu.CheckForCriu() {
- return errors.Errorf("checkpoint/restore requires at least CRIU %d", criu.MinCriuVersion)
+func (c *Container) checkpointRestoreSupported(version int) error {
+ if !criu.CheckForCriu(version) {
+ return errors.Errorf("checkpoint/restore requires at least CRIU %d", version)
}
if !c.ociRuntime.SupportsCheckpoint() {
return errors.Errorf("configured runtime does not support checkpoint/restore")
@@ -1032,7 +1051,7 @@ func (c *Container) checkpointRestoreSupported() error {
}
func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointOptions) error {
- if err := c.checkpointRestoreSupported(); err != nil {
+ if err := c.checkpointRestoreSupported(criu.MinCriuVersion); err != nil {
return err
}
@@ -1136,10 +1155,20 @@ func (c *Container) importPreCheckpoint(input string) error {
}
func (c *Container) restore(ctx context.Context, options ContainerCheckpointOptions) (retErr error) {
- if err := c.checkpointRestoreSupported(); err != nil {
+ minCriuVersion := func() int {
+ if options.Pod == "" {
+ return criu.MinCriuVersion
+ }
+ return criu.PodCriuVersion
+ }()
+ if err := c.checkpointRestoreSupported(minCriuVersion); err != nil {
return err
}
+ if options.Pod != "" && !crutils.CRRuntimeSupportsPodCheckpointRestore(c.ociRuntime.Path()) {
+ return errors.Errorf("runtime %s does not support pod restore", c.ociRuntime.Path())
+ }
+
if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateExited) {
return errors.Wrapf(define.ErrCtrStateInvalid, "container %s is running or paused, cannot restore", c.ID())
}
@@ -1247,6 +1276,83 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
}
+ if options.Pod != "" {
+ // Running in a Pod means that we have to change all namespace settings to
+ // the ones from the infrastructure container.
+ pod, err := c.runtime.LookupPod(options.Pod)
+ if err != nil {
+ return errors.Wrapf(err, "pod %q cannot be retrieved", options.Pod)
+ }
+
+ infraContainer, err := pod.InfraContainer()
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieved infra container from pod %q", options.Pod)
+ }
+
+ infraContainer.lock.Lock()
+ if err := infraContainer.syncContainer(); err != nil {
+ infraContainer.lock.Unlock()
+ return errors.Wrapf(err, "Error syncing infrastructure container %s status", infraContainer.ID())
+ }
+ if infraContainer.state.State != define.ContainerStateRunning {
+ if err := infraContainer.initAndStart(ctx); err != nil {
+ infraContainer.lock.Unlock()
+ return errors.Wrapf(err, "Error starting infrastructure container %s status", infraContainer.ID())
+ }
+ }
+ infraContainer.lock.Unlock()
+
+ if c.config.IPCNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(IPCNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve IPC namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.NetNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(NetNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve network namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.PIDNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(PIDNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve PID namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.UTSNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(UTSNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve UTS namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+
+ if c.config.CgroupNsCtr != "" {
+ nsPath, err := infraContainer.namespacePath(CgroupNS)
+ if err != nil {
+ return errors.Wrapf(err, "cannot retrieve Cgroup namespace path for Pod %q", options.Pod)
+ }
+ if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), nsPath); err != nil {
+ return err
+ }
+ }
+ }
+
if err := c.makeBindMounts(); err != nil {
return err
}
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index 2914bd1a1..846d3815a 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -1064,6 +1064,30 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
if restoreOptions.TCPEstablished {
args = append(args, "--runtime-opt", "--tcp-established")
}
+ if restoreOptions.Pod != "" {
+ mountLabel := ctr.config.MountLabel
+ processLabel := ctr.config.ProcessLabel
+ if mountLabel != "" {
+ args = append(
+ args,
+ "--runtime-opt",
+ fmt.Sprintf(
+ "--lsm-mount-context=%s",
+ mountLabel,
+ ),
+ )
+ }
+ if processLabel != "" {
+ args = append(
+ args,
+ "--runtime-opt",
+ fmt.Sprintf(
+ "--lsm-profile=selinux:%s",
+ processLabel,
+ ),
+ )
+ }
+ }
}
logrus.WithFields(logrus.Fields{
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index ce4c5d758..31e2d09ce 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -894,6 +894,18 @@ func (r *Runtime) LookupContainer(idOrName string) (*Container, error) {
return r.state.LookupContainer(idOrName)
}
+// LookupContainerId looks up a container id by its name or a partial ID
+// If a partial ID is not unique, an error will be returned
+func (r *Runtime) LookupContainerID(idOrName string) (string, error) {
+ r.lock.RLock()
+ defer r.lock.RUnlock()
+
+ if !r.valid {
+ return "", define.ErrRuntimeStopped
+ }
+ return r.state.LookupContainerID(idOrName)
+}
+
// GetContainers retrieves all containers from the state
// Filters can be provided which will determine what containers are included in
// the output. Multiple filters are handled by ANDing their output, so only