github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/test/e2e/checkpoint_test.go (about)

     1  // +build !remoteclient
     2  
     3  package integration
     4  
     5  import (
     6  	"net"
     7  	"os"
     8  	"os/exec"
     9  
    10  	"github.com/containers/libpod/pkg/criu"
    11  	. "github.com/containers/libpod/test/utils"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  func getRunString(input []string) []string {
    17  	// CRIU does not work with seccomp correctly on RHEL7 : seccomp=unconfined
    18  	runString := []string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", "--ip", GetRandomIPAddress()}
    19  	return append(runString, input...)
    20  }
    21  
    22  var _ = Describe("Podman checkpoint", func() {
    23  	var (
    24  		tempdir    string
    25  		err        error
    26  		podmanTest *PodmanTestIntegration
    27  	)
    28  
    29  	BeforeEach(func() {
    30  		SkipIfRootless()
    31  		tempdir, err = CreateTempDirInTempDir()
    32  		if err != nil {
    33  			os.Exit(1)
    34  		}
    35  		podmanTest = PodmanTestCreate(tempdir)
    36  		podmanTest.Setup()
    37  		podmanTest.SeedImages()
    38  		// Check if the runtime implements checkpointing. Currently only
    39  		// runc's checkpoint/restore implementation is supported.
    40  		cmd := exec.Command(podmanTest.OCIRuntime, "checkpoint", "--help")
    41  		if err := cmd.Start(); err != nil {
    42  			Skip("OCI runtime does not support checkpoint/restore")
    43  		}
    44  		if err := cmd.Wait(); err != nil {
    45  			Skip("OCI runtime does not support checkpoint/restore")
    46  		}
    47  
    48  		if !criu.CheckForCriu() {
    49  			Skip("CRIU is missing or too old.")
    50  		}
    51  		// Only Fedora 29 and newer has a new enough selinux-policy and
    52  		// container-selinux package to support CRIU in correctly
    53  		// restoring threaded processes
    54  		hostInfo := podmanTest.Host
    55  		if hostInfo.Distribution == "fedora" && hostInfo.Version < "29" {
    56  			Skip("Checkpoint/Restore with SELinux only works on Fedora >= 29")
    57  		}
    58  	})
    59  
    60  	AfterEach(func() {
    61  		podmanTest.Cleanup()
    62  		f := CurrentGinkgoTestDescription()
    63  		processTestResult(f)
    64  
    65  	})
    66  
    67  	It("podman checkpoint bogus container", func() {
    68  		session := podmanTest.Podman([]string{"container", "checkpoint", "foobar"})
    69  		session.WaitWithDefaultTimeout()
    70  		Expect(session).To(ExitWithError())
    71  	})
    72  
    73  	It("podman restore bogus container", func() {
    74  		session := podmanTest.Podman([]string{"container", "restore", "foobar"})
    75  		session.WaitWithDefaultTimeout()
    76  		Expect(session).To(ExitWithError())
    77  	})
    78  
    79  	It("podman checkpoint a running container by id", func() {
    80  		localRunString := getRunString([]string{ALPINE, "top"})
    81  		session := podmanTest.Podman(localRunString)
    82  		session.WaitWithDefaultTimeout()
    83  		Expect(session.ExitCode()).To(Equal(0))
    84  		cid := session.OutputToString()
    85  
    86  		result := podmanTest.Podman([]string{"container", "checkpoint", cid})
    87  		result.WaitWithDefaultTimeout()
    88  
    89  		Expect(result.ExitCode()).To(Equal(0))
    90  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
    91  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
    92  
    93  		result = podmanTest.Podman([]string{"container", "restore", cid})
    94  		result.WaitWithDefaultTimeout()
    95  
    96  		Expect(result.ExitCode()).To(Equal(0))
    97  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
    98  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
    99  	})
   100  
   101  	It("podman checkpoint a running container by name", func() {
   102  		localRunString := getRunString([]string{"--name", "test_name", ALPINE, "top"})
   103  		session := podmanTest.Podman(localRunString)
   104  		session.WaitWithDefaultTimeout()
   105  		Expect(session.ExitCode()).To(Equal(0))
   106  
   107  		result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"})
   108  		result.WaitWithDefaultTimeout()
   109  
   110  		Expect(result.ExitCode()).To(Equal(0))
   111  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   112  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   113  
   114  		result = podmanTest.Podman([]string{"container", "restore", "test_name"})
   115  		result.WaitWithDefaultTimeout()
   116  
   117  		Expect(result.ExitCode()).To(Equal(0))
   118  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   119  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   120  	})
   121  
   122  	It("podman pause a checkpointed container by id", func() {
   123  		localRunString := getRunString([]string{ALPINE, "top"})
   124  		session := podmanTest.Podman(localRunString)
   125  		session.WaitWithDefaultTimeout()
   126  		Expect(session.ExitCode()).To(Equal(0))
   127  		cid := session.OutputToString()
   128  
   129  		result := podmanTest.Podman([]string{"container", "checkpoint", cid})
   130  		result.WaitWithDefaultTimeout()
   131  
   132  		Expect(result.ExitCode()).To(Equal(0))
   133  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   134  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   135  
   136  		result = podmanTest.Podman([]string{"pause", cid})
   137  		result.WaitWithDefaultTimeout()
   138  
   139  		Expect(result.ExitCode()).To(Equal(125))
   140  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   141  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   142  
   143  		result = podmanTest.Podman([]string{"container", "restore", cid})
   144  		result.WaitWithDefaultTimeout()
   145  		Expect(result.ExitCode()).To(Equal(0))
   146  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   147  
   148  		result = podmanTest.Podman([]string{"rm", cid})
   149  		result.WaitWithDefaultTimeout()
   150  		Expect(result.ExitCode()).To(Equal(2))
   151  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   152  
   153  		result = podmanTest.Podman([]string{"rm", "-f", cid})
   154  		result.WaitWithDefaultTimeout()
   155  		Expect(result.ExitCode()).To(Equal(0))
   156  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   157  
   158  	})
   159  
   160  	It("podman checkpoint latest running container", func() {
   161  		localRunString := getRunString([]string{"--name", "first", ALPINE, "top"})
   162  		session1 := podmanTest.Podman(localRunString)
   163  		session1.WaitWithDefaultTimeout()
   164  		Expect(session1.ExitCode()).To(Equal(0))
   165  
   166  		localRunString = getRunString([]string{"--name", "second", ALPINE, "top"})
   167  		session2 := podmanTest.Podman(localRunString)
   168  		session2.WaitWithDefaultTimeout()
   169  		Expect(session2.ExitCode()).To(Equal(0))
   170  
   171  		result := podmanTest.Podman([]string{"container", "checkpoint", "-l"})
   172  		result.WaitWithDefaultTimeout()
   173  
   174  		Expect(result.ExitCode()).To(Equal(0))
   175  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   176  
   177  		ps := podmanTest.Podman([]string{"ps", "-q", "--no-trunc"})
   178  		ps.WaitWithDefaultTimeout()
   179  		Expect(ps.ExitCode()).To(Equal(0))
   180  		Expect(ps.LineInOutputContains(session1.OutputToString())).To(BeTrue())
   181  		Expect(ps.LineInOutputContains(session2.OutputToString())).To(BeFalse())
   182  
   183  		result = podmanTest.Podman([]string{"container", "restore", "-l"})
   184  		result.WaitWithDefaultTimeout()
   185  
   186  		Expect(result.ExitCode()).To(Equal(0))
   187  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
   188  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   189  		Expect(podmanTest.GetContainerStatus()).To(Not(ContainSubstring("Exited")))
   190  
   191  		result = podmanTest.Podman([]string{"rm", "-fa"})
   192  		result.WaitWithDefaultTimeout()
   193  		Expect(result.ExitCode()).To(Equal(0))
   194  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   195  	})
   196  
   197  	It("podman checkpoint all running container", func() {
   198  		localRunString := getRunString([]string{"--name", "first", ALPINE, "top"})
   199  		session1 := podmanTest.Podman(localRunString)
   200  		session1.WaitWithDefaultTimeout()
   201  		Expect(session1.ExitCode()).To(Equal(0))
   202  
   203  		localRunString = getRunString([]string{"--name", "second", ALPINE, "top"})
   204  		session2 := podmanTest.Podman(localRunString)
   205  		session2.WaitWithDefaultTimeout()
   206  		Expect(session2.ExitCode()).To(Equal(0))
   207  
   208  		result := podmanTest.Podman([]string{"container", "checkpoint", "-a"})
   209  		result.WaitWithDefaultTimeout()
   210  
   211  		Expect(result.ExitCode()).To(Equal(0))
   212  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   213  
   214  		ps := podmanTest.Podman([]string{"ps", "-q", "--no-trunc"})
   215  		ps.WaitWithDefaultTimeout()
   216  		Expect(ps.ExitCode()).To(Equal(0))
   217  		Expect(ps.LineInOutputContains(session1.OutputToString())).To(BeFalse())
   218  		Expect(ps.LineInOutputContains(session2.OutputToString())).To(BeFalse())
   219  
   220  		result = podmanTest.Podman([]string{"container", "restore", "-a"})
   221  		result.WaitWithDefaultTimeout()
   222  
   223  		Expect(result.ExitCode()).To(Equal(0))
   224  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
   225  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   226  		Expect(podmanTest.GetContainerStatus()).To(Not(ContainSubstring("Exited")))
   227  
   228  		result = podmanTest.Podman([]string{"rm", "-fa"})
   229  		result.WaitWithDefaultTimeout()
   230  		Expect(result.ExitCode()).To(Equal(0))
   231  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   232  	})
   233  
   234  	It("podman checkpoint container with established tcp connections", func() {
   235  		localRunString := getRunString([]string{redis})
   236  		session := podmanTest.Podman(localRunString)
   237  		session.WaitWithDefaultTimeout()
   238  		Expect(session.ExitCode()).To(Equal(0))
   239  
   240  		IP := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"})
   241  		IP.WaitWithDefaultTimeout()
   242  		Expect(IP.ExitCode()).To(Equal(0))
   243  
   244  		// Open a network connection to the redis server
   245  		conn, err := net.Dial("tcp", IP.OutputToString()+":6379")
   246  		if err != nil {
   247  			os.Exit(1)
   248  		}
   249  		// This should fail as the container has established TCP connections
   250  		result := podmanTest.Podman([]string{"container", "checkpoint", "-l"})
   251  		result.WaitWithDefaultTimeout()
   252  
   253  		Expect(result.ExitCode()).To(Equal(125))
   254  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   255  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   256  
   257  		// Now it should work thanks to "--tcp-established"
   258  		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "--tcp-established"})
   259  		result.WaitWithDefaultTimeout()
   260  
   261  		Expect(result.ExitCode()).To(Equal(0))
   262  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   263  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   264  
   265  		// Restore should fail as the checkpoint image contains established TCP connections
   266  		result = podmanTest.Podman([]string{"container", "restore", "-l"})
   267  		result.WaitWithDefaultTimeout()
   268  
   269  		Expect(result.ExitCode()).To(Equal(125))
   270  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   271  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   272  
   273  		// Now it should work thanks to "--tcp-established"
   274  		result = podmanTest.Podman([]string{"container", "restore", "-l", "--tcp-established"})
   275  		result.WaitWithDefaultTimeout()
   276  
   277  		Expect(result.ExitCode()).To(Equal(0))
   278  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   279  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   280  
   281  		result = podmanTest.Podman([]string{"rm", "-fa"})
   282  		result.WaitWithDefaultTimeout()
   283  		Expect(result.ExitCode()).To(Equal(0))
   284  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   285  
   286  		conn.Close()
   287  	})
   288  
   289  	It("podman checkpoint with --leave-running", func() {
   290  		localRunString := getRunString([]string{ALPINE, "top"})
   291  		session := podmanTest.Podman(localRunString)
   292  		session.WaitWithDefaultTimeout()
   293  		Expect(session.ExitCode()).To(Equal(0))
   294  		cid := session.OutputToString()
   295  
   296  		// Checkpoint container, but leave it running
   297  		result := podmanTest.Podman([]string{"container", "checkpoint", "--leave-running", cid})
   298  		result.WaitWithDefaultTimeout()
   299  
   300  		Expect(result.ExitCode()).To(Equal(0))
   301  		// Make sure it is still running
   302  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   303  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   304  
   305  		// Stop the container
   306  		result = podmanTest.Podman([]string{"container", "stop", cid})
   307  		result.WaitWithDefaultTimeout()
   308  
   309  		Expect(result.ExitCode()).To(Equal(0))
   310  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   311  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   312  
   313  		// Restore the stopped container from the previous checkpoint
   314  		result = podmanTest.Podman([]string{"container", "restore", cid})
   315  		result.WaitWithDefaultTimeout()
   316  
   317  		Expect(result.ExitCode()).To(Equal(0))
   318  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   319  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   320  
   321  		result = podmanTest.Podman([]string{"rm", "-fa"})
   322  		result.WaitWithDefaultTimeout()
   323  		Expect(result.ExitCode()).To(Equal(0))
   324  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   325  	})
   326  
   327  	It("podman checkpoint and restore container with same IP", func() {
   328  		localRunString := getRunString([]string{"--name", "test_name", ALPINE, "top"})
   329  		session := podmanTest.Podman(localRunString)
   330  		session.WaitWithDefaultTimeout()
   331  		Expect(session.ExitCode()).To(Equal(0))
   332  
   333  		IPBefore := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"})
   334  		IPBefore.WaitWithDefaultTimeout()
   335  		Expect(IPBefore.ExitCode()).To(Equal(0))
   336  
   337  		MACBefore := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.MacAddress}}"})
   338  		MACBefore.WaitWithDefaultTimeout()
   339  		Expect(MACBefore.ExitCode()).To(Equal(0))
   340  
   341  		result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"})
   342  		result.WaitWithDefaultTimeout()
   343  
   344  		Expect(result.ExitCode()).To(Equal(0))
   345  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   346  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited"))
   347  
   348  		result = podmanTest.Podman([]string{"container", "restore", "test_name"})
   349  		result.WaitWithDefaultTimeout()
   350  
   351  		IPAfter := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.IPAddress}}"})
   352  		IPAfter.WaitWithDefaultTimeout()
   353  		Expect(IPAfter.ExitCode()).To(Equal(0))
   354  
   355  		MACAfter := podmanTest.Podman([]string{"inspect", "-l", "--format={{.NetworkSettings.MacAddress}}"})
   356  		MACAfter.WaitWithDefaultTimeout()
   357  		Expect(MACAfter.ExitCode()).To(Equal(0))
   358  
   359  		// Check that IP address did not change between checkpointing and restoring
   360  		Expect(IPBefore.OutputToString()).To(Equal(IPAfter.OutputToString()))
   361  
   362  		// Check that MAC address did not change between checkpointing and restoring
   363  		Expect(MACBefore.OutputToString()).To(Equal(MACAfter.OutputToString()))
   364  
   365  		Expect(result.ExitCode()).To(Equal(0))
   366  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   367  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   368  
   369  		result = podmanTest.Podman([]string{"rm", "-fa"})
   370  		result.WaitWithDefaultTimeout()
   371  		Expect(result.ExitCode()).To(Equal(0))
   372  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   373  	})
   374  
   375  	// This test does the same steps which are necessary for migrating
   376  	// a container from one host to another
   377  	It("podman checkpoint container with export (migration)", func() {
   378  		localRunString := getRunString([]string{"--rm", ALPINE, "top"})
   379  		session := podmanTest.Podman(localRunString)
   380  		session.WaitWithDefaultTimeout()
   381  		Expect(session.ExitCode()).To(Equal(0))
   382  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   383  		cid := session.OutputToString()
   384  		fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
   385  
   386  		result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
   387  		result.WaitWithDefaultTimeout()
   388  
   389  		// As the container has been started with '--rm' it will be completely
   390  		// cleaned up after checkpointing.
   391  		Expect(result.ExitCode()).To(Equal(0))
   392  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   393  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   394  
   395  		// Restore container the first time with different name.
   396  		// Using '--ignore-static-ip' as for parallel test runs
   397  		// each containers gets a random IP address via '--ip'.
   398  		// '--ignore-static-ip' tells the restore to use the next
   399  		// available IP address.
   400  		// First restore the container with a new name/ID to make
   401  		// sure nothing in the restored container depends on the
   402  		// original container.
   403  		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName, "-n", "restore_again", "--ignore-static-ip"})
   404  		result.WaitWithDefaultTimeout()
   405  
   406  		Expect(result.ExitCode()).To(Equal(0))
   407  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   408  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   409  
   410  		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
   411  		result.WaitWithDefaultTimeout()
   412  
   413  		Expect(result.ExitCode()).To(Equal(0))
   414  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
   415  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   416  
   417  		result = podmanTest.Podman([]string{"rm", "-fa"})
   418  		result.WaitWithDefaultTimeout()
   419  		Expect(result.ExitCode()).To(Equal(0))
   420  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   421  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   422  
   423  		// Remove exported checkpoint
   424  		os.Remove(fileName)
   425  	})
   426  
   427  	It("podman checkpoint and restore container with root file-system changes", func() {
   428  		// Start the container
   429  		localRunString := getRunString([]string{"--rm", ALPINE, "top"})
   430  		session := podmanTest.Podman(localRunString)
   431  		session.WaitWithDefaultTimeout()
   432  		Expect(session.ExitCode()).To(Equal(0))
   433  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   434  		cid := session.OutputToString()
   435  		fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
   436  
   437  		// Change the container's root file-system
   438  		result := podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
   439  		result.WaitWithDefaultTimeout()
   440  		Expect(result.ExitCode()).To(Equal(0))
   441  
   442  		result = podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "rm /etc/motd"})
   443  		result.WaitWithDefaultTimeout()
   444  		Expect(result.ExitCode()).To(Equal(0))
   445  
   446  		result = podmanTest.Podman([]string{"diff", "-l"})
   447  		result.WaitWithDefaultTimeout()
   448  		Expect(result.ExitCode()).To(Equal(0))
   449  		Expect(result.OutputToString()).To(ContainSubstring("C /etc"))
   450  		Expect(result.OutputToString()).To(ContainSubstring("A /test.output"))
   451  		Expect(result.OutputToString()).To(ContainSubstring("D /etc/motd"))
   452  		Expect(len(result.OutputToStringArray())).To(Equal(3))
   453  
   454  		// Checkpoint the container
   455  		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
   456  		result.WaitWithDefaultTimeout()
   457  
   458  		Expect(result.ExitCode()).To(Equal(0))
   459  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   460  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   461  
   462  		// Restore the container
   463  		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
   464  		result.WaitWithDefaultTimeout()
   465  
   466  		Expect(result.ExitCode()).To(Equal(0))
   467  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   468  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   469  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   470  
   471  		// Verify the changes to the container's root file-system
   472  		result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
   473  		result.WaitWithDefaultTimeout()
   474  		Expect(result.ExitCode()).To(Equal(0))
   475  		Expect(result.OutputToString()).To(ContainSubstring("test" + cid + "test"))
   476  
   477  		result = podmanTest.Podman([]string{"diff", "-l"})
   478  		result.WaitWithDefaultTimeout()
   479  		Expect(result.ExitCode()).To(Equal(0))
   480  		Expect(result.OutputToString()).To(ContainSubstring("C /etc"))
   481  		Expect(result.OutputToString()).To(ContainSubstring("A /test.output"))
   482  		Expect(result.OutputToString()).To(ContainSubstring("D /etc/motd"))
   483  		Expect(len(result.OutputToStringArray())).To(Equal(3))
   484  
   485  		// Remove exported checkpoint
   486  		os.Remove(fileName)
   487  	})
   488  	It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during restore", func() {
   489  		// Start the container
   490  		localRunString := getRunString([]string{"--rm", ALPINE, "top"})
   491  		session := podmanTest.Podman(localRunString)
   492  		session.WaitWithDefaultTimeout()
   493  		Expect(session.ExitCode()).To(Equal(0))
   494  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   495  		cid := session.OutputToString()
   496  		fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
   497  
   498  		// Change the container's root file-system
   499  		result := podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
   500  		result.WaitWithDefaultTimeout()
   501  		Expect(result.ExitCode()).To(Equal(0))
   502  
   503  		// Checkpoint the container
   504  		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
   505  		result.WaitWithDefaultTimeout()
   506  
   507  		Expect(result.ExitCode()).To(Equal(0))
   508  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   509  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   510  
   511  		// Restore the container
   512  		result = podmanTest.Podman([]string{"container", "restore", "--ignore-rootfs", "-i", fileName})
   513  		result.WaitWithDefaultTimeout()
   514  
   515  		Expect(result.ExitCode()).To(Equal(0))
   516  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   517  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   518  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   519  
   520  		// Verify the changes to the container's root file-system
   521  		result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
   522  		result.WaitWithDefaultTimeout()
   523  		Expect(result.ExitCode()).To(Equal(1))
   524  		Expect(result.ErrorToString()).To(ContainSubstring("cat: can't open '/test.output': No such file or directory"))
   525  
   526  		// Remove exported checkpoint
   527  		os.Remove(fileName)
   528  	})
   529  	It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during checkpoint", func() {
   530  		// Start the container
   531  		localRunString := getRunString([]string{"--rm", ALPINE, "top"})
   532  		session := podmanTest.Podman(localRunString)
   533  		session.WaitWithDefaultTimeout()
   534  		Expect(session.ExitCode()).To(Equal(0))
   535  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   536  		cid := session.OutputToString()
   537  		fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
   538  
   539  		// Change the container's root file-system
   540  		result := podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo test" + cid + "test > /test.output"})
   541  		result.WaitWithDefaultTimeout()
   542  		Expect(result.ExitCode()).To(Equal(0))
   543  
   544  		// Checkpoint the container
   545  		result = podmanTest.Podman([]string{"container", "checkpoint", "--ignore-rootfs", "-l", "-e", fileName})
   546  		result.WaitWithDefaultTimeout()
   547  
   548  		Expect(result.ExitCode()).To(Equal(0))
   549  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   550  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   551  
   552  		// Restore the container
   553  		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
   554  		result.WaitWithDefaultTimeout()
   555  
   556  		Expect(result.ExitCode()).To(Equal(0))
   557  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   558  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   559  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   560  
   561  		// Verify the changes to the container's root file-system
   562  		result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
   563  		result.WaitWithDefaultTimeout()
   564  		Expect(result.ExitCode()).To(Equal(1))
   565  		Expect(result.ErrorToString()).To(ContainSubstring("cat: can't open '/test.output': No such file or directory"))
   566  
   567  		// Remove exported checkpoint
   568  		os.Remove(fileName)
   569  	})
   570  
   571  	It("podman checkpoint and run exec in restored container", func() {
   572  		// Start the container
   573  		localRunString := getRunString([]string{"--rm", ALPINE, "top"})
   574  		session := podmanTest.Podman(localRunString)
   575  		session.WaitWithDefaultTimeout()
   576  		Expect(session.ExitCode()).To(Equal(0))
   577  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   578  		cid := session.OutputToString()
   579  		fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
   580  
   581  		// Checkpoint the container
   582  		result := podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
   583  		result.WaitWithDefaultTimeout()
   584  
   585  		Expect(result.ExitCode()).To(Equal(0))
   586  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   587  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   588  
   589  		// Restore the container
   590  		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
   591  		result.WaitWithDefaultTimeout()
   592  
   593  		Expect(result.ExitCode()).To(Equal(0))
   594  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   595  		Expect(podmanTest.NumberOfContainers()).To(Equal(1))
   596  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   597  
   598  		// Exec in the container
   599  		result = podmanTest.Podman([]string{"exec", "-l", "/bin/sh", "-c", "echo " + cid + " > /test.output"})
   600  		result.WaitWithDefaultTimeout()
   601  		Expect(result.ExitCode()).To(Equal(0))
   602  
   603  		result = podmanTest.Podman([]string{"exec", "-l", "cat", "/test.output"})
   604  		result.WaitWithDefaultTimeout()
   605  		Expect(result.ExitCode()).To(Equal(0))
   606  		Expect(result.OutputToString()).To(ContainSubstring(cid))
   607  
   608  		// Remove exported checkpoint
   609  		os.Remove(fileName)
   610  	})
   611  
   612  	It("podman checkpoint a container started with --rm", func() {
   613  		// Start the container
   614  		localRunString := getRunString([]string{"--rm", ALPINE, "top"})
   615  		session := podmanTest.Podman(localRunString)
   616  		session.WaitWithDefaultTimeout()
   617  		cid := session.OutputToString()
   618  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   619  
   620  		// Checkpoint the container - this should fail as it was started with --rm
   621  		result := podmanTest.Podman([]string{"container", "checkpoint", "-l"})
   622  		result.WaitWithDefaultTimeout()
   623  		Expect(result).To(ExitWithError())
   624  		Expect(result.ErrorToString()).To(ContainSubstring("Cannot checkpoint containers that have been started with '--rm'"))
   625  
   626  		// Checkpointing with --export should still work
   627  		fileName := "/tmp/checkpoint-" + cid + ".tar.gz"
   628  
   629  		result = podmanTest.Podman([]string{"container", "checkpoint", "-l", "-e", fileName})
   630  		result.WaitWithDefaultTimeout()
   631  
   632  		// As the container has been started with '--rm' it will be completely
   633  		// cleaned up after checkpointing.
   634  		Expect(result.ExitCode()).To(Equal(0))
   635  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   636  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   637  
   638  		result = podmanTest.Podman([]string{"container", "restore", "-i", fileName})
   639  		result.WaitWithDefaultTimeout()
   640  
   641  		Expect(result.ExitCode()).To(Equal(0))
   642  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
   643  		Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
   644  
   645  		result = podmanTest.Podman([]string{"rm", "-fa"})
   646  		result.WaitWithDefaultTimeout()
   647  		Expect(result.ExitCode()).To(Equal(0))
   648  		Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
   649  		Expect(podmanTest.NumberOfContainers()).To(Equal(0))
   650  
   651  		// Remove exported checkpoint
   652  		os.Remove(fileName)
   653  	})
   654  })