299 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			299 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
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()
 | 
						|
		// 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() {
 | 
						|
		SkipIfContainerized("FIXME: #15015. All checkpoint tests hang when containerized.")
 | 
						|
		// 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).To(HaveField("CheckpointPath", ""))
 | 
						|
		Expect(inspectOut[0].State).To(HaveField("CheckpointLog", ""))
 | 
						|
		Expect(inspectOut[0].State).To(HaveField("RestoreLog", ""))
 | 
						|
 | 
						|
		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 checkpoint image", func() {
 | 
						|
		SkipIfContainerized("FIXME: #15015. All checkpoint tests hang when containerized.")
 | 
						|
		// 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 checkpoint images", func() {
 | 
						|
		SkipIfContainerized("FIXME: #15015. All checkpoint tests hang when containerized.")
 | 
						|
		// 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))
 | 
						|
	})
 | 
						|
})
 |