github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/test/e2e/checkpoint_test.go (about)

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