github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/test/e2e/checkpoint_image_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"os"
     5  	"os/exec"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/hanks177/podman/v4/pkg/criu"
    10  	. "github.com/hanks177/podman/v4/test/utils"
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/gomega"
    13  	. "github.com/onsi/gomega/gexec"
    14  )
    15  
    16  var _ = Describe("Podman checkpoint", func() {
    17  	var (
    18  		tempdir    string
    19  		err        error
    20  		podmanTest *PodmanTestIntegration
    21  	)
    22  
    23  	BeforeEach(func() {
    24  		SkipIfRootless("checkpoint not supported in rootless mode")
    25  		tempdir, err = CreateTempDirInTempDir()
    26  		if err != nil {
    27  			os.Exit(1)
    28  		}
    29  		podmanTest = PodmanTestCreate(tempdir)
    30  		podmanTest.Setup()
    31  		// Check if the runtime implements checkpointing. Currently only
    32  		// runc's checkpoint/restore implementation is supported.
    33  		cmd := exec.Command(podmanTest.OCIRuntime, "checkpoint", "--help")
    34  		if err := cmd.Start(); err != nil {
    35  			Skip("OCI runtime does not support checkpoint/restore")
    36  		}
    37  		if err := cmd.Wait(); err != nil {
    38  			Skip("OCI runtime does not support checkpoint/restore")
    39  		}
    40  
    41  		if !criu.CheckForCriu(criu.MinCriuVersion) {
    42  			Skip("CRIU is missing or too old.")
    43  		}
    44  	})
    45  
    46  	AfterEach(func() {
    47  		podmanTest.Cleanup()
    48  		f := CurrentGinkgoTestDescription()
    49  		processTestResult(f)
    50  	})
    51  
    52  	It("podman checkpoint --create-image with bogus container", func() {
    53  		checkpointImage := "foobar-checkpoint"
    54  		session := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage, "foobar"})
    55  		session.WaitWithDefaultTimeout()
    56  		Expect(session).To(ExitWithError())
    57  		Expect(session.ErrorToString()).To(ContainSubstring("no container with name or ID \"foobar\" found"))
    58  	})
    59  
    60  	It("podman checkpoint --create-image with running container", func() {
    61  		// Container image must be lowercase
    62  		checkpointImage := "alpine-checkpoint-" + strings.ToLower(RandomString(6))
    63  		containerName := "alpine-container-" + RandomString(6)
    64  
    65  		localRunString := []string{
    66  			"run",
    67  			"-it",
    68  			"-d",
    69  			"--ip", GetRandomIPAddress(),
    70  			"--name", containerName,
    71  			ALPINE,
    72  			"top",
    73  		}
    74  		session := podmanTest.Podman(localRunString)
    75  		session.WaitWithDefaultTimeout()
    76  		Expect(session).Should(Exit(0))
    77  		containerID := session.OutputToString()
    78  
    79  		// Checkpoint image should not exist
    80  		session = podmanTest.Podman([]string{"images"})
    81  		session.WaitWithDefaultTimeout()
    82  		Expect(session).Should(Exit(0))
    83  		Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeFalse())
    84  
    85  		// Check if none of the checkpoint/restore specific information is displayed
    86  		// for newly started containers.
    87  		inspect := podmanTest.Podman([]string{"inspect", containerID})
    88  		inspect.WaitWithDefaultTimeout()
    89  		Expect(inspect).Should(Exit(0))
    90  		inspectOut := inspect.InspectContainerToJSON()
    91  		Expect(inspectOut[0].State.Checkpointed).To(BeFalse(), ".State.Checkpointed")
    92  		Expect(inspectOut[0].State.Restored).To(BeFalse(), ".State.Restored")
    93  		Expect(inspectOut[0].State).To(HaveField("CheckpointPath", ""))
    94  		Expect(inspectOut[0].State).To(HaveField("CheckpointLog", ""))
    95  		Expect(inspectOut[0].State).To(HaveField("RestoreLog", ""))
    96  
    97  		result := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage, "--keep", containerID})
    98  		result.WaitWithDefaultTimeout()
    99  
   100  		Expect(result).Should(Exit(0))
   101  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   102  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   103  
   104  		inspect = podmanTest.Podman([]string{"inspect", containerID})
   105  		inspect.WaitWithDefaultTimeout()
   106  		Expect(inspect).Should(Exit(0))
   107  		inspectOut = inspect.InspectContainerToJSON()
   108  		Expect(inspectOut[0].State.Checkpointed).To(BeTrue(), ".State.Checkpointed")
   109  		Expect(inspectOut[0].State.CheckpointPath).To(ContainSubstring("userdata/checkpoint"))
   110  		Expect(inspectOut[0].State.CheckpointLog).To(ContainSubstring("userdata/dump.log"))
   111  
   112  		// Check if checkpoint image has been created
   113  		session = podmanTest.Podman([]string{"images"})
   114  		session.WaitWithDefaultTimeout()
   115  		Expect(session).Should(Exit(0))
   116  		Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeTrue())
   117  
   118  		// Check if the checkpoint image contains annotations
   119  		inspect = podmanTest.Podman([]string{"inspect", checkpointImage})
   120  		inspect.WaitWithDefaultTimeout()
   121  		Expect(inspect).Should(Exit(0))
   122  		inspectImageOut := inspect.InspectImageJSON()
   123  		Expect(inspectImageOut[0].Annotations["io.podman.annotations.checkpoint.name"]).To(
   124  			BeEquivalentTo(containerName),
   125  			"io.podman.annotations.checkpoint.name",
   126  		)
   127  
   128  		ociRuntimeName := ""
   129  		if strings.Contains(podmanTest.OCIRuntime, "runc") {
   130  			ociRuntimeName = "runc"
   131  		} else if strings.Contains(podmanTest.OCIRuntime, "crun") {
   132  			ociRuntimeName = "crun"
   133  		}
   134  		if ociRuntimeName != "" {
   135  			Expect(inspectImageOut[0].Annotations["io.podman.annotations.checkpoint.runtime.name"]).To(
   136  				BeEquivalentTo(ociRuntimeName),
   137  				"io.podman.annotations.checkpoint.runtime.name",
   138  			)
   139  		}
   140  
   141  		// Remove existing container
   142  		result = podmanTest.Podman([]string{"rm", "-t", "1", "-f", containerID})
   143  		result.WaitWithDefaultTimeout()
   144  		Expect(result).Should(Exit(0))
   145  
   146  		// Restore container from checkpoint image
   147  		result = podmanTest.Podman([]string{"container", "restore", checkpointImage})
   148  		result.WaitWithDefaultTimeout()
   149  
   150  		Expect(result).Should(Exit(0))
   151  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   152  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   153  
   154  		// Clean-up
   155  		result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"})
   156  		result.WaitWithDefaultTimeout()
   157  		Expect(result).Should(Exit(0))
   158  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   159  
   160  		result = podmanTest.Podman([]string{"rmi", checkpointImage})
   161  		result.WaitWithDefaultTimeout()
   162  		Expect(result).Should(Exit(0))
   163  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   164  	})
   165  
   166  	It("podman restore multiple containers from single checkpint image", func() {
   167  		// Container image must be lowercase
   168  		checkpointImage := "alpine-checkpoint-" + strings.ToLower(RandomString(6))
   169  		containerName := "alpine-container-" + RandomString(6)
   170  
   171  		localRunString := []string{"run", "-d", "--name", containerName, ALPINE, "top"}
   172  		session := podmanTest.Podman(localRunString)
   173  		session.WaitWithDefaultTimeout()
   174  		Expect(session).Should(Exit(0))
   175  		containerID := session.OutputToString()
   176  
   177  		// Checkpoint image should not exist
   178  		session = podmanTest.Podman([]string{"images"})
   179  		session.WaitWithDefaultTimeout()
   180  		Expect(session).Should(Exit(0))
   181  		Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeFalse())
   182  
   183  		result := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage, "--keep", containerID})
   184  		result.WaitWithDefaultTimeout()
   185  
   186  		Expect(result).Should(Exit(0))
   187  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   188  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   189  
   190  		// Check if checkpoint image has been created
   191  		session = podmanTest.Podman([]string{"images"})
   192  		session.WaitWithDefaultTimeout()
   193  		Expect(session).Should(Exit(0))
   194  		Expect(session.LineInOutputContainsTag("localhost/"+checkpointImage, "latest")).To(BeTrue())
   195  
   196  		// Remove existing container
   197  		result = podmanTest.Podman([]string{"rm", "-t", "1", "-f", containerID})
   198  		result.WaitWithDefaultTimeout()
   199  		Expect(result).Should(Exit(0))
   200  
   201  		for i := 1; i < 5; i++ {
   202  			// Restore container from checkpoint image
   203  			name := containerName + strconv.Itoa(i)
   204  			result = podmanTest.Podman([]string{"container", "restore", "--name", name, checkpointImage})
   205  			result.WaitWithDefaultTimeout()
   206  			Expect(result).Should(Exit(0))
   207  			Expect(podmanTest.NumberOfContainersRunning()).To(Equal(i))
   208  
   209  			// Check that the container is running
   210  			status := podmanTest.Podman([]string{"inspect", name, "--format={{.State.Status}}"})
   211  			status.WaitWithDefaultTimeout()
   212  			Expect(status).Should(Exit(0))
   213  			Expect(status.OutputToString()).To(Equal("running"))
   214  		}
   215  
   216  		// Clean-up
   217  		result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"})
   218  		result.WaitWithDefaultTimeout()
   219  		Expect(result).Should(Exit(0))
   220  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   221  
   222  		result = podmanTest.Podman([]string{"rmi", checkpointImage})
   223  		result.WaitWithDefaultTimeout()
   224  		Expect(result).Should(Exit(0))
   225  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   226  	})
   227  
   228  	It("podman restore multiple containers from multiple checkpint images", func() {
   229  		// Container image must be lowercase
   230  		checkpointImage1 := "alpine-checkpoint-" + strings.ToLower(RandomString(6))
   231  		checkpointImage2 := "alpine-checkpoint-" + strings.ToLower(RandomString(6))
   232  		containerName1 := "alpine-container-" + RandomString(6)
   233  		containerName2 := "alpine-container-" + RandomString(6)
   234  
   235  		// Create first container
   236  		localRunString := []string{"run", "-d", "--name", containerName1, ALPINE, "top"}
   237  		session := podmanTest.Podman(localRunString)
   238  		session.WaitWithDefaultTimeout()
   239  		Expect(session).Should(Exit(0))
   240  		containerID1 := session.OutputToString()
   241  
   242  		// Create second container
   243  		localRunString = []string{"run", "-d", "--name", containerName2, ALPINE, "top"}
   244  		session = podmanTest.Podman(localRunString)
   245  		session.WaitWithDefaultTimeout()
   246  		Expect(session).Should(Exit(0))
   247  		containerID2 := session.OutputToString()
   248  
   249  		// Checkpoint first container
   250  		result := podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage1, "--keep", containerID1})
   251  		result.WaitWithDefaultTimeout()
   252  		Expect(result).Should(Exit(0))
   253  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   254  
   255  		// Checkpoint second container
   256  		result = podmanTest.Podman([]string{"container", "checkpoint", "--create-image", checkpointImage2, "--keep", containerID2})
   257  		result.WaitWithDefaultTimeout()
   258  		Expect(result).Should(Exit(0))
   259  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   260  
   261  		// Remove existing containers
   262  		result = podmanTest.Podman([]string{"rm", "-t", "1", "-f", containerName1, containerName2})
   263  		result.WaitWithDefaultTimeout()
   264  		Expect(result).Should(Exit(0))
   265  
   266  		// Restore both containers from images
   267  		result = podmanTest.Podman([]string{"container", "restore", checkpointImage1, checkpointImage2})
   268  		result.WaitWithDefaultTimeout()
   269  		Expect(result).Should(Exit(0))
   270  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
   271  
   272  		// Check if first container is running
   273  		status := podmanTest.Podman([]string{"inspect", containerName1, "--format={{.State.Status}}"})
   274  		status.WaitWithDefaultTimeout()
   275  		Expect(status).Should(Exit(0))
   276  		Expect(status.OutputToString()).To(Equal("running"))
   277  
   278  		// Check if second container is running
   279  		status = podmanTest.Podman([]string{"inspect", containerName2, "--format={{.State.Status}}"})
   280  		status.WaitWithDefaultTimeout()
   281  		Expect(status).Should(Exit(0))
   282  		Expect(status.OutputToString()).To(Equal("running"))
   283  
   284  		// Clean-up
   285  		result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"})
   286  		result.WaitWithDefaultTimeout()
   287  		Expect(result).Should(Exit(0))
   288  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   289  
   290  		result = podmanTest.Podman([]string{"rmi", checkpointImage1, checkpointImage2})
   291  		result.WaitWithDefaultTimeout()
   292  		Expect(result).Should(Exit(0))
   293  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   294  	})
   295  })