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 })