summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/handlers/compat/containers_archive.go17
-rw-r--r--pkg/api/server/register_archive.go4
-rw-r--r--pkg/bindings/containers/types.go3
-rw-r--r--pkg/bindings/containers/types_copy_options.go16
-rw-r--r--pkg/bindings/containers/types_restore_options.go16
-rw-r--r--pkg/checkpoint/checkpoint_restore.go96
-rw-r--r--pkg/checkpoint/crutils/checkpoint_restore_utils.go11
-rw-r--r--pkg/copy/parse.go12
-rw-r--r--pkg/criu/criu.go10
-rw-r--r--pkg/domain/entities/containers.go3
-rw-r--r--pkg/domain/entities/engine_container.go3
-rw-r--r--pkg/domain/infra/abi/archive.go2
-rw-r--r--pkg/domain/infra/abi/containers.go3
-rw-r--r--pkg/domain/infra/abi/system.go12
-rw-r--r--pkg/domain/infra/tunnel/containers.go3
-rw-r--r--pkg/domain/infra/tunnel/system.go3
16 files changed, 184 insertions, 30 deletions
diff --git a/pkg/api/handlers/compat/containers_archive.go b/pkg/api/handlers/compat/containers_archive.go
index a9d74e5f4..541f702e7 100644
--- a/pkg/api/handlers/compat/containers_archive.go
+++ b/pkg/api/handlers/compat/containers_archive.go
@@ -1,6 +1,7 @@
package compat
import (
+ "encoding/json"
"fmt"
"net/http"
"os"
@@ -93,8 +94,9 @@ func handleHeadAndGet(w http.ResponseWriter, r *http.Request, decoder *schema.De
func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder, runtime *libpod.Runtime) {
query := struct {
- Path string `schema:"path"`
- Chown bool `schema:"copyUIDGID"`
+ Path string `schema:"path"`
+ Chown bool `schema:"copyUIDGID"`
+ Rename string `schema:"rename"`
// TODO handle params below
NoOverwriteDirNonDir bool `schema:"noOverwriteDirNonDir"`
}{
@@ -107,10 +109,19 @@ func handlePut(w http.ResponseWriter, r *http.Request, decoder *schema.Decoder,
return
}
+ var rename map[string]string
+ if query.Rename != "" {
+ if err := json.Unmarshal([]byte(query.Rename), &rename); err != nil {
+ utils.Error(w, "Bad Request.", http.StatusBadRequest, errors.Wrap(err, "couldn't decode the query"))
+ return
+ }
+ }
+
containerName := utils.GetName(r)
containerEngine := abi.ContainerEngine{Libpod: runtime}
- copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body, entities.CopyOptions{Chown: query.Chown})
+ copyOptions := entities.CopyOptions{Chown: query.Chown, Rename: rename}
+ copyFunc, err := containerEngine.ContainerCopyFromArchive(r.Context(), containerName, query.Path, r.Body, copyOptions)
if errors.Cause(err) == define.ErrNoSuchCtr || os.IsNotExist(err) {
// 404 is returned for an absent container and path. The
// clients must deal with it accordingly.
diff --git a/pkg/api/server/register_archive.go b/pkg/api/server/register_archive.go
index ee7449fbb..82d72ee6a 100644
--- a/pkg/api/server/register_archive.go
+++ b/pkg/api/server/register_archive.go
@@ -151,6 +151,10 @@ func (s *APIServer) registerArchiveHandlers(r *mux.Router) error {
// type: string
// description: Path to a directory in the container to extract
// required: true
+ // - in: query
+ // name: rename
+ // type: string
+ // description: JSON encoded map[string]string to translate paths
// responses:
// 200:
// description: no error
diff --git a/pkg/bindings/containers/types.go b/pkg/bindings/containers/types.go
index 1058c7a48..cf088441f 100644
--- a/pkg/bindings/containers/types.go
+++ b/pkg/bindings/containers/types.go
@@ -62,6 +62,7 @@ type RestoreOptions struct {
Keep *bool
Name *string
TCPEstablished *bool
+ Pod *string
}
//go:generate go run ../generator/generator.go CreateOptions
@@ -263,4 +264,6 @@ type CopyOptions struct {
// If used with CopyFromArchive and set to true it will change ownership of files from the source tar archive
// to the primary uid/gid of the target container.
Chown *bool `schema:"copyUIDGID"`
+ // Map to translate path names.
+ Rename map[string]string
}
diff --git a/pkg/bindings/containers/types_copy_options.go b/pkg/bindings/containers/types_copy_options.go
index 12ad085fd..0624b450e 100644
--- a/pkg/bindings/containers/types_copy_options.go
+++ b/pkg/bindings/containers/types_copy_options.go
@@ -35,3 +35,19 @@ func (o *CopyOptions) GetChown() bool {
}
return *o.Chown
}
+
+// WithRename
+func (o *CopyOptions) WithRename(value map[string]string) *CopyOptions {
+ v := value
+ o.Rename = v
+ return o
+}
+
+// GetRename
+func (o *CopyOptions) GetRename() map[string]string {
+ var rename map[string]string
+ if o.Rename == nil {
+ return rename
+ }
+ return o.Rename
+}
diff --git a/pkg/bindings/containers/types_restore_options.go b/pkg/bindings/containers/types_restore_options.go
index ea6c810a2..820a7696f 100644
--- a/pkg/bindings/containers/types_restore_options.go
+++ b/pkg/bindings/containers/types_restore_options.go
@@ -131,3 +131,19 @@ func (o *RestoreOptions) GetTCPEstablished() bool {
}
return *o.TCPEstablished
}
+
+// WithPod
+func (o *RestoreOptions) WithPod(value string) *RestoreOptions {
+ v := &value
+ o.Pod = v
+ return o
+}
+
+// GetPod
+func (o *RestoreOptions) GetPod() string {
+ var pod string
+ if o.Pod == nil {
+ return pod
+ }
+ return *o.Pod
+}
diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go
index 0d45cab5f..9fdf04933 100644
--- a/pkg/checkpoint/checkpoint_restore.go
+++ b/pkg/checkpoint/checkpoint_restore.go
@@ -9,6 +9,9 @@ import (
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
+ ann "github.com/containers/podman/v3/pkg/annotations"
+ "github.com/containers/podman/v3/pkg/checkpoint/crutils"
+ "github.com/containers/podman/v3/pkg/criu"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/errorhandling"
"github.com/containers/podman/v3/pkg/specgen/generate"
@@ -68,6 +71,14 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
return nil, err
}
+ if ctrConfig.Pod != "" && restoreOptions.Pod == "" {
+ return nil, errors.New("cannot restore pod container without --pod")
+ }
+
+ if ctrConfig.Pod == "" && restoreOptions.Pod != "" {
+ return nil, errors.New("cannot restore non pod container into pod")
+ }
+
// This should not happen as checkpoints with these options are not exported.
if len(ctrConfig.Dependencies) > 0 {
return nil, errors.Errorf("Cannot import checkpoints of containers with dependencies")
@@ -96,6 +107,91 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
newName = true
}
+ if restoreOptions.Pod != "" {
+ // Restoring into a Pod requires much newer versions of CRIU
+ if !criu.CheckForCriu(criu.PodCriuVersion) {
+ return nil, errors.Errorf("restoring containers into pods requires at least CRIU %d", criu.PodCriuVersion)
+ }
+ // The runtime also has to support it
+ if !crutils.CRRuntimeSupportsPodCheckpointRestore(runtime.GetOCIRuntimePath()) {
+ return nil, errors.Errorf("runtime %s does not support pod restore", runtime.GetOCIRuntimePath())
+ }
+ // Restoring into an existing Pod
+ ctrConfig.Pod = restoreOptions.Pod
+
+ // According to podman pod create a pod can share the following namespaces:
+ // cgroup, ipc, net, pid, uts
+ // Let's make sure we a restoring into a pod with the same shared namespaces.
+ pod, err := runtime.LookupPod(ctrConfig.Pod)
+ if err != nil {
+ return nil, errors.Wrapf(err, "pod %q cannot be retrieved", ctrConfig.Pod)
+ }
+
+ infraContainer, err := pod.InfraContainer()
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot retrieve infra container from pod %q", ctrConfig.Pod)
+ }
+
+ // If a namespaces was shared (!= "") it needs to be set to the new infrastructure container
+ // If the infrastructure container does not share the same namespaces as the to be restored
+ // container we abort.
+ if ctrConfig.IPCNsCtr != "" {
+ if !pod.SharesIPC() {
+ return nil, errors.Errorf("pod %s does not share the IPC namespace", ctrConfig.Pod)
+ }
+ ctrConfig.IPCNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.NetNsCtr != "" {
+ if !pod.SharesNet() {
+ return nil, errors.Errorf("pod %s does not share the network namespace", ctrConfig.Pod)
+ }
+ ctrConfig.NetNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.PIDNsCtr != "" {
+ if !pod.SharesPID() {
+ return nil, errors.Errorf("pod %s does not share the PID namespace", ctrConfig.Pod)
+ }
+ ctrConfig.PIDNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.UTSNsCtr != "" {
+ if !pod.SharesUTS() {
+ return nil, errors.Errorf("pod %s does not share the UTS namespace", ctrConfig.Pod)
+ }
+ ctrConfig.UTSNsCtr = infraContainer.ID()
+ }
+
+ if ctrConfig.CgroupNsCtr != "" {
+ if !pod.SharesCgroup() {
+ return nil, errors.Errorf("pod %s does not share the cgroup namespace", ctrConfig.Pod)
+ }
+ ctrConfig.CgroupNsCtr = infraContainer.ID()
+ }
+
+ // Change SELinux labels to infrastructure container labels
+ ctrConfig.MountLabel = infraContainer.MountLabel()
+ ctrConfig.ProcessLabel = infraContainer.ProcessLabel()
+
+ // Fix parent cgroup
+ cgroupPath, err := pod.CgroupPath()
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot retrieve cgroup path from pod %q", ctrConfig.Pod)
+ }
+ ctrConfig.CgroupParent = cgroupPath
+
+ oldPodID := dumpSpec.Annotations[ann.SandboxID]
+ // Fix up SandboxID in the annotations
+ dumpSpec.Annotations[ann.SandboxID] = ctrConfig.Pod
+ // Fix up CreateCommand
+ for i, c := range ctrConfig.CreateCommand {
+ if c == oldPodID {
+ ctrConfig.CreateCommand[i] = ctrConfig.Pod
+ }
+ }
+ }
+
if len(restoreOptions.PublishPorts) > 0 {
ports, _, _, err := generate.ParsePortMapping(restoreOptions.PublishPorts)
if err != nil {
diff --git a/pkg/checkpoint/crutils/checkpoint_restore_utils.go b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
index 53ff55865..3b77368bb 100644
--- a/pkg/checkpoint/crutils/checkpoint_restore_utils.go
+++ b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
@@ -1,6 +1,7 @@
package crutils
import (
+ "bytes"
"io"
"os"
"os/exec"
@@ -189,3 +190,13 @@ func CRRuntimeSupportsCheckpointRestore(runtimePath string) bool {
}
return false
}
+
+// CRRuntimeSupportsCheckpointRestore tests if the runtime at 'runtimePath'
+// supports restoring into existing Pods. The runtime needs to support
+// the CRIU option --lsm-mount-context and the existence of this is checked
+// by this function. In addition it is necessary to at least have CRIU 3.16.
+func CRRuntimeSupportsPodCheckpointRestore(runtimePath string) bool {
+ cmd := exec.Command(runtimePath, "restore", "--lsm-mount-context")
+ out, _ := cmd.CombinedOutput()
+ return bytes.Contains(out, []byte("flag needs an argument"))
+}
diff --git a/pkg/copy/parse.go b/pkg/copy/parse.go
index 39e0e1547..93edec5fa 100644
--- a/pkg/copy/parse.go
+++ b/pkg/copy/parse.go
@@ -18,18 +18,6 @@ func ParseSourceAndDestination(source, destination string) (string, string, stri
sourceContainer, sourcePath := parseUserInput(source)
destContainer, destPath := parseUserInput(destination)
- numContainers := 0
- if len(sourceContainer) > 0 {
- numContainers++
- }
- if len(destContainer) > 0 {
- numContainers++
- }
-
- if numContainers != 1 {
- return "", "", "", "", errors.Errorf("invalid arguments %q, %q: exactly 1 container expected but %d specified", source, destination, numContainers)
- }
-
if len(sourcePath) == 0 || len(destPath) == 0 {
return "", "", "", "", errors.Errorf("invalid arguments %q, %q: you must specify paths", source, destination)
}
diff --git a/pkg/criu/criu.go b/pkg/criu/criu.go
index f4cce238a..2a6805979 100644
--- a/pkg/criu/criu.go
+++ b/pkg/criu/criu.go
@@ -1,17 +1,21 @@
package criu
import (
- "github.com/checkpoint-restore/go-criu"
+ "github.com/checkpoint-restore/go-criu/v5"
)
// MinCriuVersion for Podman at least CRIU 3.11 is required
const MinCriuVersion = 31100
+// PodCriuVersion is the version of CRIU needed for
+// checkpointing and restoring containers out of and into Pods.
+const PodCriuVersion = 31600
+
// CheckForCriu uses CRIU's go bindings to check if the CRIU
// binary exists and if it at least the version Podman needs.
-func CheckForCriu() bool {
+func CheckForCriu(version int) bool {
c := criu.MakeCriu()
- result, err := c.IsCriuAtLeast(MinCriuVersion)
+ result, err := c.IsCriuAtLeast(version)
if err != nil {
return false
}
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go
index 4d85941cd..564921c52 100644
--- a/pkg/domain/entities/containers.go
+++ b/pkg/domain/entities/containers.go
@@ -165,6 +165,8 @@ type CopyOptions struct {
// it will change ownership of files from the source tar archive
// to the primary uid/gid of the destination container.
Chown bool
+ // Map to translate path names.
+ Rename map[string]string
}
type CommitReport struct {
@@ -207,6 +209,7 @@ type RestoreOptions struct {
TCPEstablished bool
ImportPrevious string
PublishPorts []specgen.PortMapping
+ Pod string
}
type RestoreReport struct {
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 62e83fab3..d573e4704 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -8,7 +8,6 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
"github.com/containers/podman/v3/pkg/specgen"
- "github.com/spf13/cobra"
)
type ContainerCopyFunc func() error
@@ -82,7 +81,7 @@ type ContainerEngine interface {
PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error)
PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error)
PodUnpause(ctx context.Context, namesOrIds []string, options PodunpauseOptions) ([]*PodUnpauseReport, error)
- SetupRootless(ctx context.Context, cmd *cobra.Command) error
+ SetupRootless(ctx context.Context, noMoveProcess bool) error
SecretCreate(ctx context.Context, name string, reader io.Reader, options SecretCreateOptions) (*SecretCreateReport, error)
SecretInspect(ctx context.Context, nameOrIDs []string) ([]*SecretInfoReport, []error, error)
SecretList(ctx context.Context) ([]*SecretInfoReport, error)
diff --git a/pkg/domain/infra/abi/archive.go b/pkg/domain/infra/abi/archive.go
index 1a5bb6dc4..b60baa935 100644
--- a/pkg/domain/infra/abi/archive.go
+++ b/pkg/domain/infra/abi/archive.go
@@ -12,7 +12,7 @@ func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrI
if err != nil {
return nil, err
}
- return container.CopyFromArchive(ctx, containerPath, options.Chown, reader)
+ return container.CopyFromArchive(ctx, containerPath, options.Chown, options.Rename, reader)
}
func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, containerPath string, writer io.Writer) (entities.ContainerCopyFunc, error) {
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 485ab944d..2003879b8 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -529,6 +529,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
IgnoreStaticIP: options.IgnoreStaticIP,
IgnoreStaticMAC: options.IgnoreStaticMAC,
ImportPrevious: options.ImportPrevious,
+ Pod: options.Pod,
}
filterFuncs := []libpod.ContainerFilter{
@@ -618,7 +619,7 @@ func makeExecConfig(options entities.ExecOptions, rt *libpod.Runtime) (*libpod.E
return nil, errors.Wrapf(err, "error retrieving Libpod configuration to build exec exit command")
}
// TODO: Add some ability to toggle syslog
- exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, false, true, true)
+ exitCommandArgs, err := generate.CreateExitCommandArgs(storageConfig, runtimeConfig, false, false, true)
if err != nil {
return nil, errors.Wrapf(err, "error constructing exit command for exec session")
}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 155cda21d..bc98edd06 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -24,7 +24,6 @@ import (
"github.com/containers/storage/pkg/unshare"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@@ -57,7 +56,7 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
return info, err
}
-func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
+func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool) error {
// do it only after podman has already re-execed and running with uid==0.
hasCapSysAdmin, err := unshare.HasCapSysAdmin()
if err != nil {
@@ -104,6 +103,9 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
if became {
os.Exit(ret)
}
+ if noMoveProcess {
+ return nil
+ }
// if there is no pid file, try to join existing containers, and create a pause process.
ctrs, err := ic.Libpod.GetRunningContainers()
@@ -118,9 +120,10 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command)
}
became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths)
+
if err := movePauseProcessToScope(ic.Libpod); err != nil {
- conf, err := ic.Config(context.Background())
- if err != nil {
+ conf, err2 := ic.Config(context.Background())
+ if err2 != nil {
return err
}
if conf.Engine.CgroupManager == config.SystemdCgroupsManager {
@@ -148,7 +151,6 @@ func movePauseProcessToScope(r *libpod.Runtime) error {
if err != nil {
return errors.Wrapf(err, "could not get pause process pid file path")
}
-
data, err := ioutil.ReadFile(pausePidPath)
if err != nil {
return errors.Wrapf(err, "cannot read pause pid file")
diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go
index d7e8a4e46..58f9c5fb0 100644
--- a/pkg/domain/infra/tunnel/containers.go
+++ b/pkg/domain/infra/tunnel/containers.go
@@ -853,7 +853,8 @@ func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrID string, o
}
func (ic *ContainerEngine) ContainerCopyFromArchive(ctx context.Context, nameOrID, path string, reader io.Reader, options entities.CopyOptions) (entities.ContainerCopyFunc, error) {
- return containers.CopyFromArchiveWithOptions(ic.ClientCtx, nameOrID, path, reader, new(containers.CopyOptions).WithChown(options.Chown))
+ copyOptions := new(containers.CopyOptions).WithChown(options.Chown).WithRename(options.Rename)
+ return containers.CopyFromArchiveWithOptions(ic.ClientCtx, nameOrID, path, reader, copyOptions)
}
func (ic *ContainerEngine) ContainerCopyToArchive(ctx context.Context, nameOrID string, path string, writer io.Writer) (entities.ContainerCopyFunc, error) {
diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go
index 7400d3771..6b43cf038 100644
--- a/pkg/domain/infra/tunnel/system.go
+++ b/pkg/domain/infra/tunnel/system.go
@@ -7,14 +7,13 @@ import (
"github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/bindings/system"
"github.com/containers/podman/v3/pkg/domain/entities"
- "github.com/spf13/cobra"
)
func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
return system.Info(ic.ClientCtx, nil)
}
-func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error {
+func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool) error {
panic(errors.New("rootless engine mode is not supported when tunneling"))
}