summaryrefslogtreecommitdiff
path: root/test/e2e/checkpoint_image_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/e2e/checkpoint_image_test.go')
-rw-r--r--test/e2e/checkpoint_image_test.go296
1 files changed, 296 insertions, 0 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))
+ })
+})