diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/e2e/checkpoint_image_test.go | 296 | ||||
-rw-r--r-- | test/e2e/common_test.go | 11 | ||||
-rw-r--r-- | test/e2e/create_test.go | 9 | ||||
-rw-r--r-- | test/e2e/libpod_suite_remote_test.go | 3 | ||||
-rw-r--r-- | test/e2e/pod_create_test.go | 8 | ||||
-rw-r--r-- | test/system/200-pod.bats | 2 | ||||
-rw-r--r-- | test/system/520-checkpoint.bats | 3 | ||||
-rw-r--r-- | test/upgrade/test-upgrade.bats | 8 | ||||
-rw-r--r-- | test/utils/utils.go | 2 |
9 files changed, 322 insertions, 20 deletions
diff --git a/test/e2e/checkpoint_image_test.go b/test/e2e/checkpoint_image_test.go new file mode 100644 index 000000000..8274dfc80 --- /dev/null +++ b/test/e2e/checkpoint_image_test.go @@ -0,0 +1,296 @@ +package integration + +import ( + "os" + "os/exec" + "strconv" + "strings" + + "github.com/containers/podman/v4/pkg/criu" + . "github.com/containers/podman/v4/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gexec" +) + +var _ = Describe("Podman checkpoint", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + ) + + BeforeEach(func() { + SkipIfRootless("checkpoint not supported in rootless mode") + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.Setup() + podmanTest.SeedImages() + // Check if the runtime implements checkpointing. Currently only + // runc's checkpoint/restore implementation is supported. + cmd := exec.Command(podmanTest.OCIRuntime, "checkpoint", "--help") + if err := cmd.Start(); err != nil { + Skip("OCI runtime does not support checkpoint/restore") + } + if err := cmd.Wait(); err != nil { + Skip("OCI runtime does not support checkpoint/restore") + } + + if !criu.CheckForCriu(criu.MinCriuVersion) { + Skip("CRIU is missing or too old.") + } + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + processTestResult(f) + }) + + It("podman checkpoint --create-image with bogus container", func() { + checkpointImage := "foobar-checkpoint" + session := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage, "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + Expect(session.ErrorToString()).To(ContainSubstring("no container with name or ID \"foobar\" found")) + }) + + It("podman checkpoint --create-image with running container", func() { + // Container image must be lowercase + checkpointImage := "alpine-checkpoint-" + strings.ToLower(RandomString(6)) + containerName := "alpine-container-" + RandomString(6) + + localRunString := []string{ + "run", + "-it", + "-d", + "--ip", GetRandomIPAddress(), + "--name", containerName, + ALPINE, + "top", + } + session := podmanTest.Podman(localRunString) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + containerID := session.OutputToString() + + // Checkpoint image should not exist + session = podmanTest.Podman([]string{"images"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeFalse()) + + // Check if none of the checkpoint/restore specific information is displayed + // for newly started containers. + inspect := podmanTest.Podman([]string{"inspect", containerID}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + inspectOut := inspect.InspectContainerToJSON() + Expect(inspectOut[0].State.Checkpointed).To(BeFalse(), ".State.Checkpointed") + Expect(inspectOut[0].State.Restored).To(BeFalse(), ".State.Restored") + Expect(inspectOut[0].State.CheckpointPath).To(Equal("")) + Expect(inspectOut[0].State.CheckpointLog).To(Equal("")) + Expect(inspectOut[0].State.RestoreLog).To(Equal("")) + + result := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage, "--keep", containerID}) + result.WaitWithDefaultTimeout() + + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) + + inspect = podmanTest.Podman([]string{"inspect", containerID}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + inspectOut = inspect.InspectContainerToJSON() + Expect(inspectOut[0].State.Checkpointed).To(BeTrue(), ".State.Checkpointed") + Expect(inspectOut[0].State.CheckpointPath).To(ContainSubstring("userdata/checkpoint")) + Expect(inspectOut[0].State.CheckpointLog).To(ContainSubstring("userdata/dump.log")) + + // Check if checkpoint image has been created + session = podmanTest.Podman([]string{"images"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeTrue()) + + // Check if the checkpoint image contains annotations + inspect = podmanTest.Podman([]string{"inspect", checkpointImage}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + inspectImageOut := inspect.InspectImageJSON() + Expect(inspectImageOut[0].Annotations["io.podman.annotations.checkpoint.name"]).To( + BeEquivalentTo(containerName), + "io.podman.annotations.checkpoint.name", + ) + + ociRuntimeName := "" + if strings.Contains(podmanTest.OCIRuntime, "runc") { + ociRuntimeName = "runc" + } else if strings.Contains(podmanTest.OCIRuntime, "crun") { + ociRuntimeName = "crun" + } + if ociRuntimeName != "" { + Expect(inspectImageOut[0].Annotations["io.podman.annotations.checkpoint.runtime.name"]).To( + BeEquivalentTo(ociRuntimeName), + "io.podman.annotations.checkpoint.runtime.name", + ) + } + + // Remove existing container + result = podmanTest.Podman([]string{"rm", "-t", "1", "-f", containerID}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + + // Restore container from checkpoint image + result = podmanTest.Podman([]string{"container", "restore", checkpointImage}) + result.WaitWithDefaultTimeout() + + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) + + // Clean-up + result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + + result = podmanTest.Podman([]string{"rmi", checkpointImage}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) + + It("podman restore multiple containers from single checkpint image", func() { + // Container image must be lowercase + checkpointImage := "alpine-checkpoint-" + strings.ToLower(RandomString(6)) + containerName := "alpine-container-" + RandomString(6) + + localRunString := []string{"run", "-d", "--name", containerName, ALPINE, "top"} + session := podmanTest.Podman(localRunString) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + containerID := session.OutputToString() + + // Checkpoint image should not exist + session = podmanTest.Podman([]string{"images"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeFalse()) + + result := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage, "--keep", containerID}) + result.WaitWithDefaultTimeout() + + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) + + // Check if checkpoint image has been created + session = podmanTest.Podman([]string{"images"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeTrue()) + + // Remove existing container + result = podmanTest.Podman([]string{"rm", "-t", "1", "-f", containerID}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + + for i := 1; i < 5; i++ { + // Restore container from checkpoint image + name := containerName + strconv.Itoa(i) + result = podmanTest.Podman([]string{"container", "restore", "--name", name, checkpointImage}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(i)) + + // Check that the container is running + status := podmanTest.Podman([]string{"inspect", name, "--format={{.State.Status}}"}) + status.WaitWithDefaultTimeout() + Expect(status).Should(Exit(0)) + Expect(status.OutputToString()).To(Equal("running")) + } + + // Clean-up + result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + + result = podmanTest.Podman([]string{"rmi", checkpointImage}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) + + It("podman restore multiple containers from multiple checkpint images", func() { + // Container image must be lowercase + checkpointImage1 := "alpine-checkpoint-" + strings.ToLower(RandomString(6)) + checkpointImage2 := "alpine-checkpoint-" + strings.ToLower(RandomString(6)) + containerName1 := "alpine-container-" + RandomString(6) + containerName2 := "alpine-container-" + RandomString(6) + + // Create first container + localRunString := []string{"run", "-d", "--name", containerName1, ALPINE, "top"} + session := podmanTest.Podman(localRunString) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + containerID1 := session.OutputToString() + + // Create second container + localRunString = []string{"run", "-d", "--name", containerName2, ALPINE, "top"} + session = podmanTest.Podman(localRunString) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + containerID2 := session.OutputToString() + + // Checkpoint first container + result := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage1, "--keep", containerID1}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + + // Checkpoint second container + result = podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage2, "--keep", containerID2}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + + // Remove existing containers + result = podmanTest.Podman([]string{"rm", "-t", "1", "-f", containerName1, containerName2}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + + // Restore both containers from images + result = podmanTest.Podman([]string{"container", "restore", checkpointImage1, checkpointImage2}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) + + // Check if first container is running + status := podmanTest.Podman([]string{"inspect", containerName1, "--format={{.State.Status}}"}) + status.WaitWithDefaultTimeout() + Expect(status).Should(Exit(0)) + Expect(status.OutputToString()).To(Equal("running")) + + // Check if second container is running + status = podmanTest.Podman([]string{"inspect", containerName2, "--format={{.State.Status}}"}) + status.WaitWithDefaultTimeout() + Expect(status).Should(Exit(0)) + Expect(status.OutputToString()).To(Equal("running")) + + // Clean-up + result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + + result = podmanTest.Podman([]string{"rmi", checkpointImage1, checkpointImage2}) + result.WaitWithDefaultTimeout() + Expect(result).Should(Exit(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + }) +}) diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go index 9580230b5..2f4146bba 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/common_test.go @@ -858,18 +858,15 @@ func (p *PodmanTestIntegration) makeOptions(args []string, noEvents, noCache boo eventsType = "none" } - networkBackend := p.NetworkBackend.ToString() - networkDir := p.NetworkConfigDir - if p.NetworkBackend == Netavark { - networkDir = p.NetworkConfigDir - } podmanOptions := strings.Split(fmt.Sprintf("%s--root %s --runroot %s --runtime %s --conmon %s --network-config-dir %s --cgroup-manager %s --tmpdir %s --events-backend %s", - debug, p.Root, p.RunRoot, p.OCIRuntime, p.ConmonBinary, networkDir, p.CgroupManager, p.TmpDir, eventsType), " ") + debug, p.Root, p.RunRoot, p.OCIRuntime, p.ConmonBinary, p.NetworkConfigDir, p.CgroupManager, p.TmpDir, eventsType), " ") if os.Getenv("HOOK_OPTION") != "" { podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) } - podmanOptions = append(podmanOptions, "--network-backend", networkBackend) + if !p.RemoteTest { + podmanOptions = append(podmanOptions, "--network-backend", p.NetworkBackend.ToString()) + } podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...) if !noCache { diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go index 11f8b5abf..4c3b5604a 100644 --- a/test/e2e/create_test.go +++ b/test/e2e/create_test.go @@ -118,7 +118,7 @@ var _ = Describe("Podman create", func() { result := podmanTest.Podman([]string{"inspect", "entrypoint_test", "--format", "{{.Config.Entrypoint}}"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) - Expect(result.OutputToString()).To(Equal("[/bin/foobar]")) + Expect(result.OutputToString()).To(Equal("/bin/foobar")) }) It("podman create --entrypoint \"\"", func() { @@ -130,7 +130,7 @@ var _ = Describe("Podman create", func() { result := podmanTest.Podman([]string{"inspect", session.OutputToString(), "--format", "{{.Config.Entrypoint}}"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) - Expect(result.OutputToString()).To(Equal("[]")) + Expect(result.OutputToString()).To(Equal("")) }) It("podman create --entrypoint json", func() { @@ -143,7 +143,7 @@ var _ = Describe("Podman create", func() { result := podmanTest.Podman([]string{"inspect", "entrypoint_json", "--format", "{{.Config.Entrypoint}}"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) - Expect(result.OutputToString()).To(Equal("[/bin/foo -c]")) + Expect(result.OutputToString()).To(Equal("/bin/foo -c")) }) It("podman create --mount flag with multiple mounts", func() { @@ -281,8 +281,7 @@ var _ = Describe("Podman create", func() { Expect(ctrJSON).To(HaveLen(1)) Expect(ctrJSON[0].Config.Cmd).To(HaveLen(1)) Expect(ctrJSON[0].Config.Cmd[0]).To(Equal("redis-server")) - Expect(ctrJSON[0].Config.Entrypoint).To(HaveLen(1)) - Expect(ctrJSON[0].Config.Entrypoint[0]).To(Equal("docker-entrypoint.sh")) + Expect(ctrJSON[0].Config.Entrypoint).To(Equal("docker-entrypoint.sh")) }) It("podman create --pull", func() { diff --git a/test/e2e/libpod_suite_remote_test.go b/test/e2e/libpod_suite_remote_test.go index dddcf5c14..9ad2bf7b9 100644 --- a/test/e2e/libpod_suite_remote_test.go +++ b/test/e2e/libpod_suite_remote_test.go @@ -137,6 +137,9 @@ func getRemoteOptions(p *PodmanTestIntegration, args []string) []string { if os.Getenv("HOOK_OPTION") != "" { podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION")) } + if p.NetworkBackend.ToString() == "netavark" { + podmanOptions = append(podmanOptions, "--network-backend", "netavark") + } podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...) podmanOptions = append(podmanOptions, args...) return podmanOptions diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index dc43ce6fd..8def80213 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -368,7 +368,7 @@ var _ = Describe("Podman pod create", func() { check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID}) check1.WaitWithDefaultTimeout() Expect(check1).Should(Exit(0)) - Expect(check1.OutputToString()).To(Equal("[/catatonit -P]")) + Expect(check1.OutputToString()).To(Equal("/catatonit -P")) // check the Path and Args check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) @@ -391,7 +391,7 @@ var _ = Describe("Podman pod create", func() { check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID}) check1.WaitWithDefaultTimeout() Expect(check1).Should(Exit(0)) - Expect(check1.OutputToString()).To(Equal("[/pause1]")) + Expect(check1.OutputToString()).To(Equal("/pause1")) // check the Path and Args check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) @@ -418,7 +418,7 @@ entrypoint ["/fromimage"] check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID}) check1.WaitWithDefaultTimeout() Expect(check1).Should(Exit(0)) - Expect(check1.OutputToString()).To(Equal("[/fromimage]")) + Expect(check1.OutputToString()).To(Equal("/fromimage")) // check the Path and Args check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) @@ -445,7 +445,7 @@ entrypoint ["/fromimage"] check1 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Config.Entrypoint}}", data.Containers[0].ID}) check1.WaitWithDefaultTimeout() Expect(check1).Should(Exit(0)) - Expect(check1.OutputToString()).To(Equal("[/fromcommand]")) + Expect(check1.OutputToString()).To(Equal("/fromcommand")) // check the Path and Args check2 := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.Path}}:{{.Args}}", data.Containers[0].ID}) diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index e6f4ecdbc..f5fe41924 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -234,7 +234,7 @@ EOF local infra_cid="$output" # confirm that entrypoint is what we set run_podman container inspect --format '{{.Config.Entrypoint}}' $infra_cid - is "$output" "[$infra_command]" "infra-command took effect" + is "$output" "$infra_command" "infra-command took effect" # confirm that infra container name is set run_podman container inspect --format '{{.Name}}' $infra_cid is "$output" "$infra_name" "infra-name took effect" diff --git a/test/system/520-checkpoint.bats b/test/system/520-checkpoint.bats index 046dfd126..b41d460a4 100644 --- a/test/system/520-checkpoint.bats +++ b/test/system/520-checkpoint.bats @@ -47,7 +47,8 @@ function teardown() { # Checkpoint, and confirm via inspect run_podman container checkpoint $cid - is "$output" "$cid" "podman container checkpoint" + # FIXME: remove the `.*` prefix after fix packaged for https://github.com/checkpoint-restore/criu/pull/1706 + is "$output" ".*$cid" "podman container checkpoint" run_podman container inspect \ --format '{{.State.Status}}:{{.State.Running}}:{{.State.Paused}}:{{.State.Checkpointed}}' $cid diff --git a/test/upgrade/test-upgrade.bats b/test/upgrade/test-upgrade.bats index 198d8a169..5efe05d49 100644 --- a/test/upgrade/test-upgrade.bats +++ b/test/upgrade/test-upgrade.bats @@ -146,6 +146,12 @@ EOF # cause connectivity issues since cni and netavark should never be mixed. mkdir -p /run/netns /run/cni /run/containers /var/lib/cni /etc/cni/net.d + # Containers-common around release 1-55 no-longer supplies this file + sconf=/etc/containers/storage.conf + v_sconf= + if [[ -e "$sconf" ]]; then + v_sconf="-v $sconf:$sconf" + fi # # Use new-podman to run the above script under old-podman. @@ -165,7 +171,7 @@ EOF --net=host \ --cgroupns=host \ --pid=host \ - -v /etc/containers/storage.conf:/etc/containers/storage.conf \ + $v_sconf \ -v /dev/fuse:/dev/fuse \ -v /run/crun:/run/crun \ -v /run/netns:/run/netns:rshared \ diff --git a/test/utils/utils.go b/test/utils/utils.go index da56a3a2e..39a0ac875 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -110,7 +110,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string } runCmd := append(wrapper, podmanBinary) - if p.NetworkBackend == Netavark { + if !p.RemoteTest && p.NetworkBackend == Netavark { runCmd = append(runCmd, []string{"--network-backend", "netavark"}...) } |