summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/root.go43
-rw-r--r--docs/source/markdown/podman-container-restore.1.md6
-rw-r--r--libpod/network/netavark/exec.go45
-rw-r--r--libpod/network/netavark/network.go9
-rw-r--r--libpod/network/netavark/run.go4
-rw-r--r--libpod/network/netavark/run_test.go6
-rw-r--r--libpod/options.go8
-rw-r--r--libpod/runtime.go6
-rw-r--r--pkg/checkpoint/checkpoint_restore.go26
-rw-r--r--pkg/checkpoint/crutils/checkpoint_restore_utils.go55
-rw-r--r--pkg/domain/infra/runtime_libpod.go5
-rw-r--r--test/e2e/checkpoint_test.go173
-rw-r--r--test/e2e/common_test.go5
-rw-r--r--test/e2e/import_test.go3
-rw-r--r--test/e2e/logs_test.go2
-rw-r--r--test/e2e/push_test.go2
-rw-r--r--test/e2e/run_cgroup_parent_test.go16
-rw-r--r--test/e2e/run_cleanup_test.go2
-rw-r--r--test/e2e/run_privileged_test.go1
-rw-r--r--test/e2e/run_signal_test.go2
-rw-r--r--test/e2e/run_test.go8
-rw-r--r--test/e2e/run_volume_test.go4
-rw-r--r--test/system/030-run.bats2
-rw-r--r--test/system/400-unprivileged-access.bats5
-rw-r--r--test/utils/utils.go1
25 files changed, 378 insertions, 61 deletions
diff --git a/cmd/podman/root.go b/cmd/podman/root.go
index 9e4c8d24d..bccc559ce 100644
--- a/cmd/podman/root.go
+++ b/cmd/podman/root.go
@@ -15,6 +15,7 @@ import (
"github.com/containers/podman/v3/cmd/podman/registry"
"github.com/containers/podman/v3/cmd/podman/validate"
"github.com/containers/podman/v3/libpod/define"
+ "github.com/containers/podman/v3/pkg/checkpoint/crutils"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/parallel"
"github.com/containers/podman/v3/pkg/rootless"
@@ -114,6 +115,48 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
cfg := registry.PodmanConfig()
+ // Currently it is only possible to restore a container with the same runtime
+ // as used for checkpointing. It should be possible to make crun and runc
+ // compatible to restore a container with another runtime then checkpointed.
+ // Currently that does not work.
+ // To make it easier for users we will look into the checkpoint archive and
+ // set the runtime to the one used during checkpointing.
+ if !registry.IsRemote() && cmd.Name() == "restore" {
+ if cmd.Flag("import").Changed {
+ runtime, err := crutils.CRGetRuntimeFromArchive(cmd.Flag("import").Value.String())
+ if err != nil {
+ return errors.Wrapf(
+ err,
+ "failed extracting runtime information from %s",
+ cmd.Flag("import").Value.String(),
+ )
+ }
+ if cfg.RuntimePath == "" {
+ // If the user did not select a runtime, this takes the one from
+ // the checkpoint archives and tells Podman to use it for the restore.
+ runtimeFlag := cmd.Root().Flags().Lookup("runtime")
+ if runtimeFlag == nil {
+ return errors.Errorf(
+ "Unexcpected error setting runtime to '%s' for restore",
+ *runtime,
+ )
+ }
+ runtimeFlag.Value.Set(*runtime)
+ runtimeFlag.Changed = true
+ logrus.Debugf("Checkpoint was created using '%s'. Restore will use the same runtime", *runtime)
+ } else if cfg.RuntimePath != *runtime {
+ // If the user selected a runtime on the command-line this checks if
+ // it is the same then during checkpointing and errors out if not.
+ return errors.Errorf(
+ "checkpoint archive %s was created with runtime '%s' and cannot be restored with runtime '%s'",
+ cmd.Flag("import").Value.String(),
+ *runtime,
+ cfg.RuntimePath,
+ )
+ }
+ }
+ }
+
// --connection is not as "special" as --remote so we can wait and process it here
conn := cmd.Root().LocalFlags().Lookup("connection")
if conn != nil && conn.Changed {
diff --git a/docs/source/markdown/podman-container-restore.1.md b/docs/source/markdown/podman-container-restore.1.md
index 10477fc77..a4630dedf 100644
--- a/docs/source/markdown/podman-container-restore.1.md
+++ b/docs/source/markdown/podman-container-restore.1.md
@@ -77,6 +77,12 @@ Import a checkpoint tar.gz file, which was exported by Podman. This can be used
to import a checkpointed *container* from another host.\
*IMPORTANT: This OPTION does not need a container name or ID as input argument.*
+During the import of a checkpoint file Podman will select the same container runtime
+which was used during checkpointing. This is especially important if a specific
+(non-default) container runtime was specified during container creation. Podman will
+also abort the restore if the container runtime specified during restore does
+not much the container runtime used for container creation.
+
#### **--import-previous**=*file*
Import a pre-checkpoint tar.gz file which was exported by Podman. This option
diff --git a/libpod/network/netavark/exec.go b/libpod/network/netavark/exec.go
index d6458eeb4..01dea8489 100644
--- a/libpod/network/netavark/exec.go
+++ b/libpod/network/netavark/exec.go
@@ -3,6 +3,7 @@ package netavark
import (
"encoding/json"
"errors"
+ "io"
"os"
"os/exec"
"strconv"
@@ -45,6 +46,15 @@ func newNetavarkError(msg string, err error) error {
}
}
+// Type to implement io.Writer interface
+// This will write the logrus at info level
+type logrusNetavarkWriter struct{}
+
+func (l *logrusNetavarkWriter) Write(b []byte) (int, error) {
+ logrus.Info("netavark: ", string(b))
+ return len(b), nil
+}
+
// getRustLogEnv returns the RUST_LOG env var based on the current logrus level
func getRustLogEnv() string {
level := logrus.GetLevel().String()
@@ -63,26 +73,43 @@ func getRustLogEnv() string {
// used to marshal the netavark output into it. This can be nil.
// All errors return by this function should be of the type netavarkError
// to provide a helpful error message.
-func execNetavark(binary string, args []string, stdin, result interface{}) error {
+func (n *netavarkNetwork) execNetavark(args []string, stdin, result interface{}) error {
stdinR, stdinW, err := os.Pipe()
if err != nil {
return newNetavarkError("failed to create stdin pipe", err)
}
- defer stdinR.Close()
+ stdinWClosed := false
+ defer func() {
+ stdinR.Close()
+ if !stdinWClosed {
+ stdinW.Close()
+ }
+ }()
stdoutR, stdoutW, err := os.Pipe()
if err != nil {
return newNetavarkError("failed to create stdout pipe", err)
}
- defer stdoutR.Close()
- defer stdoutW.Close()
+ stdoutWClosed := false
+ defer func() {
+ stdoutR.Close()
+ if !stdoutWClosed {
+ stdoutW.Close()
+ }
+ }()
- cmd := exec.Command(binary, args...)
+ // connect stderr to the podman stderr for logging
+ var logWriter io.Writer = os.Stderr
+ if n.syslog {
+ // connect logrus to stderr as well so that the logs will be written to the syslog as well
+ logWriter = io.MultiWriter(logWriter, &logrusNetavarkWriter{})
+ }
+
+ cmd := exec.Command(n.netavarkBinary, args...)
// connect the pipes to stdin and stdout
cmd.Stdin = stdinR
cmd.Stdout = stdoutW
- // connect stderr to the podman stderr for logging
- cmd.Stderr = os.Stderr
+ cmd.Stderr = logWriter
// set the netavark log level to the same as the podman
cmd.Env = append(os.Environ(), getRustLogEnv())
// if we run with debug log level lets also set RUST_BACKTRACE=1 so we can get the full stack trace in case of panics
@@ -95,7 +122,9 @@ func execNetavark(binary string, args []string, stdin, result interface{}) error
return newNetavarkError("failed to start process", err)
}
err = json.NewEncoder(stdinW).Encode(stdin)
+ // we have to close stdinW so netavark gets the EOF and does not hang forever
stdinW.Close()
+ stdinWClosed = true
if err != nil {
return newNetavarkError("failed to encode stdin data", err)
}
@@ -103,7 +132,9 @@ func execNetavark(binary string, args []string, stdin, result interface{}) error
dec := json.NewDecoder(stdoutR)
err = cmd.Wait()
+ // we have to close stdoutW so we can decode the json without hanging forever
stdoutW.Close()
+ stdoutWClosed = true
if err != nil {
exitError := &exec.ExitError{}
if errors.As(err, &exitError) {
diff --git a/libpod/network/netavark/network.go b/libpod/network/netavark/network.go
index cc6fb423c..540d8d6e5 100644
--- a/libpod/network/netavark/network.go
+++ b/libpod/network/netavark/network.go
@@ -37,6 +37,10 @@ type netavarkNetwork struct {
// isMachine describes whenever podman runs in a podman machine environment.
isMachine bool
+ // syslog describes whenever the netavark debbug output should be log to the syslog as well.
+ // This will use logrus to do so, make sure logrus is set up to log to the syslog.
+ syslog bool
+
// lock is a internal lock for critical operations
lock lockfile.Locker
@@ -68,6 +72,10 @@ type InitConfig struct {
// LockFile is the path to lock file.
LockFile string
+
+ // Syslog describes whenever the netavark debbug output should be log to the syslog as well.
+ // This will use logrus to do so, make sure logrus is set up to log to the syslog.
+ Syslog bool
}
// NewNetworkInterface creates the ContainerNetwork interface for the netavark backend.
@@ -122,6 +130,7 @@ func NewNetworkInterface(conf InitConfig) (types.ContainerNetwork, error) {
defaultSubnet: defaultNet,
isMachine: conf.IsMachine,
lock: lock,
+ syslog: conf.Syslog,
}
return n, nil
diff --git a/libpod/network/netavark/run.go b/libpod/network/netavark/run.go
index 2f839151e..54917a981 100644
--- a/libpod/network/netavark/run.go
+++ b/libpod/network/netavark/run.go
@@ -54,7 +54,7 @@ func (n *netavarkNetwork) Setup(namespacePath string, options types.SetupOptions
}
result := map[string]types.StatusBlock{}
- err = execNetavark(n.netavarkBinary, []string{"setup", namespacePath}, netavarkOpts, &result)
+ err = n.execNetavark([]string{"setup", namespacePath}, netavarkOpts, &result)
if len(result) != len(options.Networks) {
logrus.Errorf("unexpected netavark result: %v", result)
@@ -86,7 +86,7 @@ func (n *netavarkNetwork) Teardown(namespacePath string, options types.TeardownO
return errors.Wrap(err, "failed to convert net opts")
}
- retErr := execNetavark(n.netavarkBinary, []string{"teardown", namespacePath}, netavarkOpts, nil)
+ retErr := n.execNetavark([]string{"teardown", namespacePath}, netavarkOpts, nil)
// when netavark returned an error we still free the used ips
// otherwise we could end up in a state where block the ips forever
diff --git a/libpod/network/netavark/run_test.go b/libpod/network/netavark/run_test.go
index 67dc51c10..f79e6d812 100644
--- a/libpod/network/netavark/run_test.go
+++ b/libpod/network/netavark/run_test.go
@@ -89,6 +89,10 @@ var _ = Describe("run netavark", func() {
if err != nil {
Fail("Failed to create netns")
}
+
+ // Force iptables driver, firewalld is broken inside the extra
+ // namespace because it still connects to firewalld on the host.
+ _ = os.Setenv("NETAVARK_FW", "iptables")
})
JustBeforeEach(func() {
@@ -109,6 +113,8 @@ var _ = Describe("run netavark", func() {
netns.UnmountNS(netNSContainer)
netNSContainer.Close()
+
+ _ = os.Unsetenv("NETAVARK_FW")
})
It("test basic setup", func() {
diff --git a/libpod/options.go b/libpod/options.go
index 3f0f9fbe0..8f2d5cb15 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -578,6 +578,14 @@ func WithEnableSDNotify() RuntimeOption {
}
}
+// WithSyslog sets a runtime option so we know that we have to log to the syslog as well
+func WithSyslog() RuntimeOption {
+ return func(rt *Runtime) error {
+ rt.syslog = true
+ return nil
+ }
+}
+
// WithRuntimeFlags adds the global runtime flags to the container config
func WithRuntimeFlags(runtimeFlags []string) RuntimeOption {
return func(rt *Runtime) error {
diff --git a/libpod/runtime.go b/libpod/runtime.go
index c751df79b..1a22cd09a 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -88,6 +88,11 @@ type Runtime struct {
libimageEventsShutdown chan bool
lockManager lock.Manager
+ // syslog describes whenever logrus should log to the syslog as well.
+ // Note that the syslog hook will be enabled early in cmd/podman/syslog_linux.go
+ // This bool is just needed so that we can set it for netavark interface.
+ syslog bool
+
// doRenumber indicates that the runtime should perform a lock renumber
// during initialization.
// Once the runtime has been initialized and returned, this variable is
@@ -517,6 +522,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) {
DefaultSubnet: runtime.config.Network.DefaultSubnet,
IsMachine: runtime.config.Engine.MachineEnabled,
LockFile: filepath.Join(runtime.config.Network.NetworkConfigDir, "netavark.lock"),
+ Syslog: runtime.syslog,
})
if err != nil {
return errors.Wrapf(err, "could not create network interface")
diff --git a/pkg/checkpoint/checkpoint_restore.go b/pkg/checkpoint/checkpoint_restore.go
index 85fe6a77e..c371adf5b 100644
--- a/pkg/checkpoint/checkpoint_restore.go
+++ b/pkg/checkpoint/checkpoint_restore.go
@@ -6,7 +6,6 @@ import (
"os"
metadata "github.com/checkpoint-restore/checkpointctl/lib"
- "github.com/checkpoint-restore/go-criu/v5/stats"
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v3/libpod"
@@ -14,10 +13,8 @@ import (
"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"
"github.com/containers/podman/v3/pkg/specgenutil"
- "github.com/containers/storage/pkg/archive"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -30,24 +27,6 @@ import (
func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOptions entities.RestoreOptions) ([]*libpod.Container, error) {
// First get the container definition from the
// tarball to a temporary directory
- archiveFile, err := os.Open(restoreOptions.Import)
- if err != nil {
- return nil, errors.Wrap(err, "failed to open checkpoint archive for import")
- }
- defer errorhandling.CloseQuiet(archiveFile)
- options := &archive.TarOptions{
- // Here we only need the files config.dump and spec.dump
- ExcludePatterns: []string{
- "volumes",
- "ctr.log",
- "artifacts",
- stats.StatsDump,
- metadata.RootFsDiffTar,
- metadata.DeletedFilesFile,
- metadata.NetworkStatusFile,
- metadata.CheckpointDirectory,
- },
- }
dir, err := ioutil.TempDir("", "checkpoint")
if err != nil {
return nil, err
@@ -57,9 +36,8 @@ func CRImportCheckpoint(ctx context.Context, runtime *libpod.Runtime, restoreOpt
logrus.Errorf("Could not recursively remove %s: %q", dir, err)
}
}()
- err = archive.Untar(archiveFile, dir, options)
- if err != nil {
- return nil, errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", restoreOptions.Import)
+ if err := crutils.CRImportCheckpointConfigOnly(dir, restoreOptions.Import); err != nil {
+ return nil, err
}
// Load spec.dump from temporary directory
diff --git a/pkg/checkpoint/crutils/checkpoint_restore_utils.go b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
index 3b77368bb..2765d18e8 100644
--- a/pkg/checkpoint/crutils/checkpoint_restore_utils.go
+++ b/pkg/checkpoint/crutils/checkpoint_restore_utils.go
@@ -3,11 +3,13 @@ package crutils
import (
"bytes"
"io"
+ "io/ioutil"
"os"
"os/exec"
"path/filepath"
metadata "github.com/checkpoint-restore/checkpointctl/lib"
+ "github.com/checkpoint-restore/go-criu/v5/stats"
"github.com/containers/storage/pkg/archive"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
@@ -39,6 +41,36 @@ func CRImportCheckpointWithoutConfig(destination, input string) error {
return nil
}
+// CRImportCheckpointConfigOnly only imports the checkpoint configuration
+// from the checkpoint archive (input) into the directory destination.
+// Only the files "config.dump" and "spec.dump" are extracted.
+func CRImportCheckpointConfigOnly(destination, input string) 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{
+ // Here we only need the files config.dump and spec.dump
+ ExcludePatterns: []string{
+ "volumes",
+ "ctr.log",
+ "artifacts",
+ stats.StatsDump,
+ metadata.RootFsDiffTar,
+ metadata.DeletedFilesFile,
+ metadata.NetworkStatusFile,
+ metadata.CheckpointDirectory,
+ },
+ }
+ if err = archive.Untar(archiveFile, destination, options); err != nil {
+ return errors.Wrapf(err, "Unpacking of checkpoint archive %s failed", input)
+ }
+
+ return nil
+}
+
// CRRemoveDeletedFiles loads the list of deleted files and if
// it exists deletes all files listed.
func CRRemoveDeletedFiles(id, baseDirectory, containerRootDirectory string) error {
@@ -200,3 +232,26 @@ func CRRuntimeSupportsPodCheckpointRestore(runtimePath string) bool {
out, _ := cmd.CombinedOutput()
return bytes.Contains(out, []byte("flag needs an argument"))
}
+
+// CRGetRuntimeFromArchive extracts the checkpoint metadata from the
+// given checkpoint archive and returns the runtime used to create
+// the given checkpoint archive.
+func CRGetRuntimeFromArchive(input string) (*string, error) {
+ dir, err := ioutil.TempDir("", "checkpoint")
+ if err != nil {
+ return nil, err
+ }
+ defer os.RemoveAll(dir)
+
+ if err := CRImportCheckpointConfigOnly(dir, input); err != nil {
+ return nil, err
+ }
+
+ // Load config.dump from temporary directory
+ ctrConfig := new(metadata.ContainerConfig)
+ if _, err = metadata.ReadJSONFile(ctrConfig, dir, metadata.ConfigDumpFile); err != nil {
+ return nil, err
+ }
+
+ return &ctrConfig.OCIRuntime, nil
+}
diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go
index cfb674b6d..90eb6abeb 100644
--- a/pkg/domain/infra/runtime_libpod.go
+++ b/pkg/domain/infra/runtime_libpod.go
@@ -236,6 +236,11 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo
options = append(options, libpod.WithRegistriesConf(cfg.RegistriesConf))
}
+ // no need to handle the error, it will return false anyway
+ if syslog, _ := fs.GetBool("syslog"); syslog {
+ options = append(options, libpod.WithSyslog())
+ }
+
// TODO flag to set CNI plugins dir?
if !opts.withFDS {
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 6b9a96e9f..e34c07d49 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -1377,4 +1377,177 @@ var _ = Describe("Podman checkpoint", func() {
Expect(result).Should(Exit(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
+
+ It("podman checkpoint container with export and verify runtime", func() {
+ SkipIfRemote("podman-remote does not support --runtime flag")
+ localRunString := getRunString([]string{
+ "--rm",
+ ALPINE,
+ "top",
+ })
+ session := podmanTest.Podman(localRunString)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ cid := session.OutputToString()
+
+ session = podmanTest.Podman([]string{
+ "inspect",
+ "--format",
+ "{{.OCIRuntime}}",
+ cid,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ runtime := session.OutputToString()
+
+ fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
+
+ result := podmanTest.Podman([]string{
+ "container",
+ "checkpoint",
+ cid, "-e",
+ fileName,
+ })
+ result.WaitWithDefaultTimeout()
+
+ // As the container has been started with '--rm' it will be completely
+ // cleaned up after checkpointing.
+ Expect(result).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
+
+ result = podmanTest.Podman([]string{
+ "container",
+ "restore",
+ "-i",
+ fileName,
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
+
+ // The restored container should have the same runtime as the original container
+ result = podmanTest.Podman([]string{
+ "inspect",
+ "--format",
+ "{{.OCIRuntime}}",
+ cid,
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(session.OutputToString()).To(Equal(runtime))
+
+ // Remove exported checkpoint
+ os.Remove(fileName)
+ })
+
+ It("podman checkpoint container with export and try to change the runtime", func() {
+ SkipIfRemote("podman-remote does not support --runtime flag")
+ // This test will only run if runc and crun both exist
+ if !strings.Contains(podmanTest.OCIRuntime, "crun") {
+ Skip("Test requires crun and runc")
+ }
+ cmd := exec.Command("runc")
+ if err := cmd.Start(); err != nil {
+ Skip("Test requires crun and runc")
+ }
+ if err := cmd.Wait(); err != nil {
+ Skip("Test requires crun and runc")
+ }
+ localRunString := getRunString([]string{
+ "--rm",
+ ALPINE,
+ "top",
+ })
+ // Let's start a container with runc and try to restore it with crun (expected to fail)
+ localRunString = append(
+ []string{
+ "--runtime",
+ "runc",
+ },
+ localRunString...,
+ )
+ session := podmanTest.Podman(localRunString)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ cid := session.OutputToString()
+
+ session = podmanTest.Podman([]string{
+ "inspect",
+ "--format",
+ "{{.OCIRuntime}}",
+ cid,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ runtime := session.OutputToString()
+
+ fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
+
+ result := podmanTest.Podman([]string{
+ "container",
+ "checkpoint",
+ cid, "-e",
+ fileName,
+ })
+ result.WaitWithDefaultTimeout()
+
+ // As the container has been started with '--rm' it will be completely
+ // cleaned up after checkpointing.
+ Expect(result).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
+
+ // This should fail as the container was checkpointed with runc
+ result = podmanTest.Podman([]string{
+ "--runtime",
+ "crun",
+ "container",
+ "restore",
+ "-i",
+ fileName,
+ })
+ result.WaitWithDefaultTimeout()
+
+ Expect(result).Should(Exit(125))
+ Expect(result.ErrorToString()).To(
+ ContainSubstring("and cannot be restored with runtime"),
+ )
+
+ result = podmanTest.Podman([]string{
+ "--runtime",
+ "runc",
+ "container",
+ "restore",
+ "-i",
+ fileName,
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+
+ result = podmanTest.Podman([]string{
+ "inspect",
+ "--format",
+ "{{.OCIRuntime}}",
+ cid,
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.OutputToString()).To(Equal(runtime))
+
+ result = podmanTest.Podman([]string{
+ "--runtime",
+ "runc",
+ "rm",
+ "-fa",
+ })
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ // Remove exported checkpoint
+ os.Remove(fileName)
+ })
})
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index 200faae2d..6180343a7 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -320,7 +320,7 @@ func (p *PodmanTestIntegration) createArtifact(image string) {
}
dest := strings.Split(image, "/")
destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1))
- fmt.Printf("Caching %s at %s...", image, destName)
+ fmt.Printf("Caching %s at %s...\n", image, destName)
if _, err := os.Stat(destName); os.IsNotExist(err) {
pull := p.PodmanNoCache([]string{"pull", image})
pull.Wait(440)
@@ -466,6 +466,9 @@ func (p *PodmanTestIntegration) BuildImageWithLabel(dockerfile, imageName string
// PodmanPID execs podman and returns its PID
func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegration, int) {
podmanOptions := p.MakeOptions(args, false, false)
+ if p.RemoteTest {
+ podmanOptions = append([]string{"--remote", "--url", p.RemoteSocket}, podmanOptions...)
+ }
fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
command := exec.Command(p.PodmanBinary, podmanOptions...)
session, err := Start(command, GinkgoWriter, GinkgoWriter)
diff --git a/test/e2e/import_test.go b/test/e2e/import_test.go
index 519a7290c..13a0f6f90 100644
--- a/test/e2e/import_test.go
+++ b/test/e2e/import_test.go
@@ -18,7 +18,6 @@ var _ = Describe("Podman import", func() {
)
BeforeEach(func() {
- SkipIfRemote("FIXME: These look like it is supposed to work in remote")
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
@@ -156,6 +155,8 @@ var _ = Describe("Podman import", func() {
})
It("podman import with signature", func() {
+ SkipIfRemote("FIXME: remote ignores --signature-policy, #12357")
+
outfile := filepath.Join(podmanTest.TempDir, "container.tar")
_, ec, cid := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 3beabec4b..d901dde5c 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -214,7 +214,7 @@ var _ = Describe("Podman logs", func() {
It("two containers showing short container IDs: "+log, func() {
skipIfJournaldInContainer()
- SkipIfRemote("FIXME: podman-remote logs does not support showing two containers at the same time")
+ SkipIfRemote("podman-remote logs does not support showing two containers at the same time")
log1 := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
log1.WaitWithDefaultTimeout()
diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go
index 7b35acd35..7038a09e8 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -95,7 +95,7 @@ var _ = Describe("Podman push", func() {
})
It("podman push to local registry with authorization", func() {
- SkipIfRootless("FIXME: Creating content in certs.d we use directories in homedir")
+ SkipIfRootless("volume-mounting a certs.d file N/A over remote")
if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le")
}
diff --git a/test/e2e/run_cgroup_parent_test.go b/test/e2e/run_cgroup_parent_test.go
index e0e1d4b1d..6bdc6af08 100644
--- a/test/e2e/run_cgroup_parent_test.go
+++ b/test/e2e/run_cgroup_parent_test.go
@@ -48,21 +48,22 @@ var _ = Describe("Podman run with --cgroup-parent", func() {
run := podmanTest.Podman([]string{"run", "--cgroupns=host", "--cgroup-parent", cgroup, fedoraMinimal, "cat", "/proc/self/cgroup"})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))
- ok, _ := run.GrepString(cgroup)
- Expect(ok).To(BeTrue())
+ Expect(run.OutputToString()).To(ContainSubstring(cgroup))
})
Specify("no --cgroup-parent", func() {
- SkipIfRootless("FIXME This seems to be broken in rootless mode")
cgroup := "/libpod_parent"
if !Containerized() && podmanTest.CgroupManager != "cgroupfs" {
- cgroup = "/machine.slice"
+ if isRootless() {
+ cgroup = "/user.slice"
+ } else {
+ cgroup = "/machine.slice"
+ }
}
run := podmanTest.Podman([]string{"run", "--cgroupns=host", fedoraMinimal, "cat", "/proc/self/cgroup"})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))
- ok, _ := run.GrepString(cgroup)
- Expect(ok).To(BeTrue())
+ Expect(run.OutputToString()).To(ContainSubstring(cgroup))
})
Specify("always honor --cgroup-parent", func() {
@@ -114,7 +115,6 @@ var _ = Describe("Podman run with --cgroup-parent", func() {
run := podmanTest.Podman([]string{"run", "--cgroupns=host", "--cgroup-parent", cgroup, fedoraMinimal, "cat", "/proc/1/cgroup"})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))
- ok, _ := run.GrepString(cgroup)
- Expect(ok).To(BeTrue())
+ Expect(run.OutputToString()).To(ContainSubstring(cgroup))
})
})
diff --git a/test/e2e/run_cleanup_test.go b/test/e2e/run_cleanup_test.go
index 6753fcf12..cc4e66751 100644
--- a/test/e2e/run_cleanup_test.go
+++ b/test/e2e/run_cleanup_test.go
@@ -35,7 +35,7 @@ var _ = Describe("Podman run exit", func() {
It("podman run -d mount cleanup test", func() {
SkipIfRemote("podman-remote does not support mount")
- SkipIfRootless("FIXME podman mount requires podman unshare first")
+ SkipIfRootless("TODO rootless podman mount requires podman unshare first")
result := podmanTest.Podman([]string{"run", "-dt", ALPINE, "top"})
result.WaitWithDefaultTimeout()
diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go
index 3e4262cfb..d793a01f8 100644
--- a/test/e2e/run_privileged_test.go
+++ b/test/e2e/run_privileged_test.go
@@ -128,7 +128,6 @@ var _ = Describe("Podman privileged container tests", func() {
})
It("podman privileged should inherit host devices", func() {
- SkipIfRootless("FIXME: This seems to be broken for rootless mode, /dev/ is close to the same")
session := podmanTest.Podman([]string{"run", "--privileged", ALPINE, "ls", "-l", "/dev"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/run_signal_test.go b/test/e2e/run_signal_test.go
index e9c073a6c..49f456366 100644
--- a/test/e2e/run_signal_test.go
+++ b/test/e2e/run_signal_test.go
@@ -45,7 +45,6 @@ var _ = Describe("Podman run with --sig-proxy", func() {
})
Specify("signals are forwarded to container using sig-proxy", func() {
- SkipIfRemote("FIXME: This looks like it is supposed to work in remote")
if podmanTest.Host.Arch == "ppc64le" {
Skip("Doesn't work on ppc64le")
}
@@ -111,7 +110,6 @@ var _ = Describe("Podman run with --sig-proxy", func() {
})
Specify("signals are not forwarded to container with sig-proxy false", func() {
- SkipIfRemote("FIXME: This looks like it is supposed to work in remote")
signal := syscall.SIGFPE
if rootless.IsRootless() {
podmanTest.RestoreArtifact(fedoraMinimal)
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 05cb986c6..2be2154ff 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -681,7 +681,7 @@ USER bin`, BB)
})
It("podman run device-read-bps test", func() {
- SkipIfRootless("FIXME: Missing /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control")
+ SkipIfRootless("FIXME: requested cgroup controller `io` is not available")
SkipIfRootlessCgroupsV1("Setting device-read-bps not supported on cgroupv1 for rootless users")
var session *PodmanSessionIntegration
@@ -700,7 +700,7 @@ USER bin`, BB)
})
It("podman run device-write-bps test", func() {
- SkipIfRootless("FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist")
+ SkipIfRootless("FIXME: requested cgroup controller `io` is not available")
SkipIfRootlessCgroupsV1("Setting device-write-bps not supported on cgroupv1 for rootless users")
var session *PodmanSessionIntegration
@@ -718,7 +718,7 @@ USER bin`, BB)
})
It("podman run device-read-iops test", func() {
- SkipIfRootless("FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist")
+ SkipIfRootless("FIXME: requested cgroup controller `io` is not available")
SkipIfRootlessCgroupsV1("Setting device-read-iops not supported on cgroupv1 for rootless users")
var session *PodmanSessionIntegration
@@ -736,7 +736,7 @@ USER bin`, BB)
})
It("podman run device-write-iops test", func() {
- SkipIfRootless("FIXME /sys/fs/cgroup/user.slice/user-14467.slice/user@14467.service/cgroup.subtree_control does not exist")
+ SkipIfRootless("FIXME: requested cgroup controller `io` is not available")
SkipIfRootlessCgroupsV1("Setting device-write-iops not supported on cgroupv1 for rootless users")
var session *PodmanSessionIntegration
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 634a498b9..5ce4d9acf 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -282,8 +282,8 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman run with tmpfs named volume mounts and unmounts", func() {
- SkipIfRootless("FIXME: rootless podman mount requires you to be in a user namespace")
- SkipIfRemote("podman-remote does not support --volumes this test could be simplified to be tested on Remote.")
+ SkipIfRootless("rootless podman mount requires you to be in a user namespace")
+ SkipIfRemote("podman-remote does not support --volumes. This test could be simplified to be tested on Remote.")
volName := "testvol"
mkVolume := podmanTest.Podman([]string{"volume", "create", "--opt", "type=tmpfs", "--opt", "device=tmpfs", "--opt", "o=nodev", "testvol"})
mkVolume.WaitWithDefaultTimeout()
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index ba21cd21d..5937d38f8 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -236,7 +236,7 @@ echo $rand | 0 | $rand
}
@test "podman run docker-archive" {
- skip_if_remote "podman-remote does not support docker-archive (#7116)"
+ skip_if_remote "podman-remote does not support docker-archive"
# Create an image that, when run, outputs a random magic string
expect=$(random_string 20)
diff --git a/test/system/400-unprivileged-access.bats b/test/system/400-unprivileged-access.bats
index f26c97d1e..cf0d0e6bf 100644
--- a/test/system/400-unprivileged-access.bats
+++ b/test/system/400-unprivileged-access.bats
@@ -101,11 +101,6 @@ EOF
# #6957 - mask out /proc/acpi, /sys/dev, and other sensitive system files
@test "sensitive mount points are masked without --privileged" {
- # Weird error, maybe a flake?
- # can only attach to created or running containers: container state improper
- # https://github.com/containers/podman/pull/7111#issuecomment-666858715
- skip_if_remote "FIXME: Weird flake"
-
# FIXME: this should match the list in pkg/specgen/generate/config_linux.go
local -a mps=(
/proc/acpi
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 8d1edb23a..4a57d9ce7 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -121,6 +121,7 @@ func (p *PodmanTest) WaitForContainer() bool {
}
time.Sleep(1 * time.Second)
}
+ fmt.Printf("WaitForContainer(): timed out\n")
return false
}