forked from containers/podman
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The patch introduces the following test cases: 1. An attempt to checkpoint a container that does not exist should fail. 2. Checkpoint of a running container with --create-image should create a checkpoint image. 3. A single checkpoint image can be used to restore multiple containers, each with a different name. 4. Restoring multiple containers from checkpoint images with a single restore command. Signed-off-by: Radostin Stoyanov <[email protected]>
- Loading branch information
Showing
1 changed file
with
296 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) | ||
}) | ||
}) |