diff options
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 } |