github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/checkpoint_test.go (about) 1 package integration 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "strings" 11 "time" 12 13 "github.com/checkpoint-restore/go-criu/v7/stats" 14 "github.com/containers/podman/v5/pkg/checkpoint/crutils" 15 "github.com/containers/podman/v5/pkg/criu" 16 "github.com/containers/podman/v5/pkg/domain/entities" 17 . "github.com/containers/podman/v5/test/utils" 18 "github.com/containers/podman/v5/utils" 19 . "github.com/onsi/ginkgo/v2" 20 . "github.com/onsi/gomega" 21 . "github.com/onsi/gomega/gexec" 22 ) 23 24 var netname string 25 26 func getRunString(input []string) []string { 27 runString := []string{"run", "-d", "--network", netname} 28 return append(runString, input...) 29 } 30 31 var _ = Describe("Podman checkpoint", func() { 32 33 BeforeEach(func() { 34 SkipIfRootless("checkpoint not supported in rootless mode") 35 36 // Check if the runtime implements checkpointing. Currently only 37 // runc's checkpoint/restore implementation is supported. 38 cmd := exec.Command(podmanTest.OCIRuntime, "checkpoint", "--help") 39 if err := cmd.Start(); err != nil { 40 Skip("OCI runtime does not support checkpoint/restore") 41 } 42 if err := cmd.Wait(); err != nil { 43 Skip("OCI runtime does not support checkpoint/restore") 44 } 45 46 if err := criu.CheckForCriu(criu.MinCriuVersion); err != nil { 47 Skip(fmt.Sprintf("check CRIU version error: %v", err)) 48 } 49 50 session := podmanTest.Podman([]string{"network", "create"}) 51 session.WaitWithDefaultTimeout() 52 Expect(session).Should(ExitCleanly()) 53 netname = session.OutputToString() 54 }) 55 56 AfterEach(func() { 57 if netname != "" { 58 session := podmanTest.Podman([]string{"network", "rm", "-f", netname}) 59 session.WaitWithDefaultTimeout() 60 Expect(session).Should(ExitCleanly()) 61 } 62 }) 63 64 It("podman checkpoint bogus container", func() { 65 session := podmanTest.Podman([]string{"container", "checkpoint", "foobar"}) 66 session.WaitWithDefaultTimeout() 67 Expect(session).Should(ExitWithError(125, "no such container")) 68 }) 69 70 It("podman restore bogus container", func() { 71 session := podmanTest.Podman([]string{"container", "restore", "foobar"}) 72 session.WaitWithDefaultTimeout() 73 Expect(session).Should(ExitWithError(125, "no such container or image")) 74 }) 75 76 It("podman checkpoint a running container by id", func() { 77 localRunString := getRunString([]string{ALPINE, "top"}) 78 session := podmanTest.Podman(localRunString) 79 session.WaitWithDefaultTimeout() 80 Expect(session).Should(ExitCleanly()) 81 cid := session.OutputToString() 82 83 // Check if none of the checkpoint/restore specific information is displayed 84 // for newly started containers. 85 inspect := podmanTest.Podman([]string{"inspect", cid}) 86 inspect.WaitWithDefaultTimeout() 87 Expect(inspect).Should(ExitCleanly()) 88 inspectOut := inspect.InspectContainerToJSON() 89 Expect(inspectOut[0].State.Checkpointed).To(BeFalse(), ".State.Checkpointed") 90 Expect(inspectOut[0].State.Restored).To(BeFalse(), ".State.Restored") 91 Expect(inspectOut[0].State).To(HaveField("CheckpointPath", "")) 92 Expect(inspectOut[0].State).To(HaveField("CheckpointLog", "")) 93 Expect(inspectOut[0].State).To(HaveField("RestoreLog", "")) 94 95 result := podmanTest.Podman([]string{ 96 "container", 97 "checkpoint", 98 "--keep", 99 cid, 100 }) 101 result.WaitWithDefaultTimeout() 102 103 Expect(result).Should(ExitCleanly()) 104 Expect(result.OutputToString()).To(Equal(cid)) 105 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 106 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 107 108 // For a checkpointed container we expect the checkpoint related information 109 // to be populated. 110 inspect = podmanTest.Podman([]string{"inspect", cid}) 111 inspect.WaitWithDefaultTimeout() 112 Expect(inspect).Should(ExitCleanly()) 113 inspectOut = inspect.InspectContainerToJSON() 114 Expect(inspectOut[0].State.Checkpointed).To(BeTrue(), ".State.Checkpointed") 115 Expect(inspectOut[0].State.Restored).To(BeFalse(), ".State.Restored") 116 Expect(inspectOut[0].State.CheckpointPath).To(ContainSubstring("userdata/checkpoint")) 117 Expect(inspectOut[0].State.CheckpointLog).To(ContainSubstring("userdata/dump.log")) 118 Expect(inspectOut[0].State).To(HaveField("RestoreLog", "")) 119 120 result = podmanTest.Podman([]string{ 121 "container", 122 "restore", 123 "--keep", 124 cid, 125 }) 126 result.WaitWithDefaultTimeout() 127 128 Expect(result).Should(ExitCleanly()) 129 Expect(result.OutputToString()).To(Equal(cid)) 130 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 131 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 132 133 inspect = podmanTest.Podman([]string{"inspect", cid}) 134 inspect.WaitWithDefaultTimeout() 135 Expect(inspect).Should(ExitCleanly()) 136 inspectOut = inspect.InspectContainerToJSON() 137 Expect(inspectOut[0].State.Restored).To(BeTrue(), ".State.Restored") 138 Expect(inspectOut[0].State.Checkpointed).To(BeFalse(), ".State.Checkpointed") 139 Expect(inspectOut[0].State.CheckpointPath).To(ContainSubstring("userdata/checkpoint")) 140 Expect(inspectOut[0].State.CheckpointLog).To(ContainSubstring("userdata/dump.log")) 141 Expect(inspectOut[0].State.RestoreLog).To(ContainSubstring("userdata/restore.log")) 142 143 podmanTest.StopContainer(cid) 144 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 145 146 result = podmanTest.Podman([]string{ 147 "container", 148 "start", 149 cid, 150 }) 151 result.WaitWithDefaultTimeout() 152 153 Expect(result).Should(ExitCleanly()) 154 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 155 156 // Stopping and starting the container should remove all checkpoint 157 // related information from inspect again. 158 inspect = podmanTest.Podman([]string{"inspect", cid}) 159 inspect.WaitWithDefaultTimeout() 160 Expect(inspect).Should(ExitCleanly()) 161 inspectOut = inspect.InspectContainerToJSON() 162 Expect(inspectOut[0].State.Checkpointed).To(BeFalse(), ".State.Checkpointed") 163 Expect(inspectOut[0].State.Restored).To(BeFalse(), ".State.Restored") 164 Expect(inspectOut[0].State).To(HaveField("CheckpointPath", "")) 165 Expect(inspectOut[0].State).To(HaveField("CheckpointLog", "")) 166 Expect(inspectOut[0].State).To(HaveField("RestoreLog", "")) 167 }) 168 169 It("podman checkpoint a running container by name", func() { 170 localRunString := getRunString([]string{"--name", "test_name", ALPINE, "top"}) 171 session := podmanTest.Podman(localRunString) 172 session.WaitWithDefaultTimeout() 173 Expect(session).Should(ExitCleanly()) 174 175 result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"}) 176 result.WaitWithDefaultTimeout() 177 178 Expect(result).Should(ExitCleanly()) 179 Expect(result.OutputToString()).To(Equal("test_name")) 180 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 181 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 182 183 result = podmanTest.Podman([]string{"container", "restore", "test_name"}) 184 result.WaitWithDefaultTimeout() 185 186 Expect(result).Should(ExitCleanly()) 187 Expect(result.OutputToString()).To(Equal("test_name")) 188 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 189 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 190 191 // Restore a container which name is equal to an image name (#15055) 192 localRunString = getRunString([]string{"--name", "alpine", "quay.io/libpod/alpine:latest", "top"}) 193 session = podmanTest.Podman(localRunString) 194 session.WaitWithDefaultTimeout() 195 Expect(session).Should(ExitCleanly()) 196 197 result = podmanTest.Podman([]string{"container", "checkpoint", "alpine"}) 198 result.WaitWithDefaultTimeout() 199 200 Expect(result).Should(ExitCleanly()) 201 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 202 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 203 204 result = podmanTest.Podman([]string{"container", "restore", "alpine"}) 205 result.WaitWithDefaultTimeout() 206 207 Expect(result).Should(ExitCleanly()) 208 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) 209 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 210 }) 211 212 It("podman pause a checkpointed container by id", func() { 213 localRunString := getRunString([]string{ALPINE, "top"}) 214 session := podmanTest.Podman(localRunString) 215 session.WaitWithDefaultTimeout() 216 Expect(session).Should(ExitCleanly()) 217 cid := session.OutputToString() 218 219 result := podmanTest.Podman([]string{"container", "checkpoint", cid}) 220 result.WaitWithDefaultTimeout() 221 222 Expect(result).Should(ExitCleanly()) 223 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 224 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 225 226 result = podmanTest.Podman([]string{"pause", cid}) 227 result.WaitWithDefaultTimeout() 228 229 Expect(result).Should(ExitWithError(125, `"exited" is not running, can't pause: container state improper`)) 230 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 231 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 232 233 result = podmanTest.Podman([]string{"container", "restore", cid}) 234 result.WaitWithDefaultTimeout() 235 Expect(result).Should(ExitCleanly()) 236 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 237 238 result = podmanTest.Podman([]string{"rm", cid}) 239 result.WaitWithDefaultTimeout() 240 Expect(result).Should(ExitWithError(2, " as it is running - running or paused containers cannot be removed without force: container state improper")) 241 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 242 243 result = podmanTest.Podman([]string{"rm", "-t", "1", "-f", cid}) 244 result.WaitWithDefaultTimeout() 245 Expect(result).Should(ExitCleanly()) 246 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 247 248 }) 249 250 It("podman checkpoint latest running container", func() { 251 localRunString := getRunString([]string{"--name", "first", ALPINE, "top"}) 252 session1 := podmanTest.Podman(localRunString) 253 session1.WaitWithDefaultTimeout() 254 Expect(session1).Should(ExitCleanly()) 255 256 localRunString = getRunString([]string{"--name", "second", ALPINE, "top"}) 257 session2 := podmanTest.Podman(localRunString) 258 session2.WaitWithDefaultTimeout() 259 Expect(session2).Should(ExitCleanly()) 260 261 result := podmanTest.Podman([]string{"container", "checkpoint", "second"}) 262 result.WaitWithDefaultTimeout() 263 264 Expect(result).Should(ExitCleanly()) 265 Expect(result.OutputToString()).To(Equal("second")) 266 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 267 268 ps := podmanTest.Podman([]string{"ps", "-q", "--no-trunc"}) 269 ps.WaitWithDefaultTimeout() 270 Expect(ps).Should(ExitCleanly()) 271 Expect(ps.OutputToString()).To(ContainSubstring(session1.OutputToString())) 272 Expect(ps.OutputToString()).To(Not(ContainSubstring(session2.OutputToString()))) 273 274 result = podmanTest.Podman([]string{"container", "restore", "second"}) 275 result.WaitWithDefaultTimeout() 276 277 Expect(result).Should(ExitCleanly()) 278 Expect(result.OutputToString()).To(Equal("second")) 279 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) 280 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 281 Expect(podmanTest.GetContainerStatus()).To(Not(ContainSubstring("Exited"))) 282 283 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 284 result.WaitWithDefaultTimeout() 285 Expect(result).Should(ExitCleanly()) 286 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 287 }) 288 289 It("podman checkpoint all running container", func() { 290 localRunString := getRunString([]string{"--name", "first", ALPINE, "top"}) 291 session1 := podmanTest.Podman(localRunString) 292 session1.WaitWithDefaultTimeout() 293 Expect(session1).Should(ExitCleanly()) 294 cid1 := session1.OutputToString() 295 296 localRunString = getRunString([]string{"--name", "second", ALPINE, "top"}) 297 session2 := podmanTest.Podman(localRunString) 298 session2.WaitWithDefaultTimeout() 299 Expect(session2).Should(ExitCleanly()) 300 cid2 := session2.OutputToString() 301 302 result := podmanTest.Podman([]string{"container", "checkpoint", "-a"}) 303 result.WaitWithDefaultTimeout() 304 305 Expect(result).Should(ExitCleanly()) 306 Expect(result.OutputToString()).To(ContainSubstring(cid1)) 307 Expect(result.OutputToString()).To(ContainSubstring(cid2)) 308 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 309 310 ps := podmanTest.Podman([]string{"ps", "-q", "--no-trunc"}) 311 ps.WaitWithDefaultTimeout() 312 Expect(ps).Should(ExitCleanly()) 313 Expect(ps.OutputToString()).To(Not(ContainSubstring(session1.OutputToString()))) 314 Expect(ps.OutputToString()).To(Not(ContainSubstring(session2.OutputToString()))) 315 316 result = podmanTest.Podman([]string{"container", "restore", "-a"}) 317 result.WaitWithDefaultTimeout() 318 319 Expect(result).Should(ExitCleanly()) 320 Expect(result.OutputToString()).To(ContainSubstring(cid1)) 321 Expect(result.OutputToString()).To(ContainSubstring(cid2)) 322 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) 323 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 324 Expect(podmanTest.GetContainerStatus()).To(Not(ContainSubstring("Exited"))) 325 326 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 327 result.WaitWithDefaultTimeout() 328 Expect(result).Should(ExitCleanly()) 329 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 330 }) 331 332 It("podman checkpoint container with established tcp connections", func() { 333 localRunString := getRunString([]string{REDIS_IMAGE}) 334 session := podmanTest.Podman(localRunString) 335 session.WaitWithDefaultTimeout() 336 Expect(session).Should(ExitCleanly()) 337 cid := session.OutputToString() 338 if !WaitContainerReady(podmanTest, cid, "Ready to accept connections", 20, 1) { 339 Fail("Container failed to get ready") 340 } 341 342 // clunky format needed because CNI uses dashes in net names 343 IP := podmanTest.Podman([]string{"inspect", cid, fmt.Sprintf("--format={{(index .NetworkSettings.Networks \"%s\").IPAddress}}", netname)}) 344 IP.WaitWithDefaultTimeout() 345 Expect(IP).Should(ExitCleanly()) 346 347 // Open a network connection to the redis server 348 conn, err := net.DialTimeout("tcp4", IP.OutputToString()+":6379", time.Duration(3)*time.Second) 349 Expect(err).ToNot(HaveOccurred()) 350 351 // This should fail as the container has established TCP connections 352 result := podmanTest.Podman([]string{"container", "checkpoint", cid}) 353 result.WaitWithDefaultTimeout() 354 355 // FIXME: criu emits an error message, but podman never sees it: 356 // "CRIU checkpointing failed -52. Please check CRIU logfile /...." 357 Expect(result).Should(ExitWithError(125, "failed: exit status 1")) 358 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 359 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 360 361 // Now it should work thanks to "--tcp-established" 362 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "--tcp-established"}) 363 result.WaitWithDefaultTimeout() 364 365 Expect(result).Should(ExitCleanly()) 366 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 367 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 368 369 // Restore should fail as the checkpoint image contains established TCP connections 370 result = podmanTest.Podman([]string{"container", "restore", cid}) 371 result.WaitWithDefaultTimeout() 372 373 // default message when using crun 374 expectStderr := "crun: CRIU restoring failed -52. Please check CRIU logfile" 375 if podmanTest.OCIRuntime == "runc" { 376 expectStderr = "runc: criu failed: type NOTIFY errno 0" 377 } 378 if !IsRemote() { 379 // This part is only seen with podman local, never remote 380 expectStderr = "OCI runtime error: " + expectStderr 381 } 382 Expect(result).Should(ExitWithError(125, expectStderr)) 383 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 384 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 385 386 // Now it should work thanks to "--tcp-established" 387 result = podmanTest.Podman([]string{"container", "restore", cid, "--tcp-established"}) 388 result.WaitWithDefaultTimeout() 389 390 Expect(result).Should(ExitCleanly()) 391 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 392 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 393 394 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 395 result.WaitWithDefaultTimeout() 396 Expect(result).Should(ExitCleanly()) 397 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 398 399 conn.Close() 400 }) 401 402 It("podman checkpoint with --leave-running", func() { 403 localRunString := getRunString([]string{ALPINE, "top"}) 404 session := podmanTest.Podman(localRunString) 405 session.WaitWithDefaultTimeout() 406 Expect(session).Should(ExitCleanly()) 407 cid := session.OutputToString() 408 409 // Checkpoint container, but leave it running 410 result := podmanTest.Podman([]string{"container", "checkpoint", "--leave-running", cid}) 411 result.WaitWithDefaultTimeout() 412 413 Expect(result).Should(ExitCleanly()) 414 // Make sure it is still running 415 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 416 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 417 418 // Stop the container 419 podmanTest.StopContainer(cid) 420 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 421 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 422 423 // Restore the stopped container from the previous checkpoint 424 result = podmanTest.Podman([]string{"container", "restore", cid}) 425 result.WaitWithDefaultTimeout() 426 427 Expect(result).Should(ExitCleanly()) 428 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 429 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 430 431 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 432 result.WaitWithDefaultTimeout() 433 Expect(result).Should(ExitCleanly()) 434 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 435 }) 436 437 It("podman checkpoint and restore container with same IP", func() { 438 localRunString := getRunString([]string{"--name", "test_name", ALPINE, "top"}) 439 session := podmanTest.Podman(localRunString) 440 session.WaitWithDefaultTimeout() 441 Expect(session).Should(ExitCleanly()) 442 443 // clunky format needed because CNI uses dashes in net names 444 IPBefore := podmanTest.Podman([]string{"inspect", "test_name", fmt.Sprintf("--format={{(index .NetworkSettings.Networks \"%s\").IPAddress}}", netname)}) 445 IPBefore.WaitWithDefaultTimeout() 446 Expect(IPBefore).Should(ExitCleanly()) 447 Expect(IPBefore.OutputToString()).To(MatchRegexp("^[0-9]+(\\.[0-9]+){3}$")) 448 449 MACBefore := podmanTest.Podman([]string{"inspect", "test_name", fmt.Sprintf("--format={{(index .NetworkSettings.Networks \"%s\").MacAddress}}", netname)}) 450 MACBefore.WaitWithDefaultTimeout() 451 Expect(MACBefore).Should(ExitCleanly()) 452 Expect(MACBefore.OutputToString()).To(MatchRegexp("^[0-9a-f]{2}(:[0-9a-f]{2}){5}$")) 453 454 result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"}) 455 result.WaitWithDefaultTimeout() 456 457 Expect(result).Should(ExitCleanly()) 458 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 459 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 460 461 result = podmanTest.Podman([]string{"container", "restore", "test_name"}) 462 result.WaitWithDefaultTimeout() 463 464 IPAfter := podmanTest.Podman([]string{"inspect", "test_name", fmt.Sprintf("--format={{(index .NetworkSettings.Networks \"%s\").IPAddress}}", netname)}) 465 IPAfter.WaitWithDefaultTimeout() 466 Expect(IPAfter).Should(ExitCleanly()) 467 468 MACAfter := podmanTest.Podman([]string{"inspect", "test_name", fmt.Sprintf("--format={{(index .NetworkSettings.Networks \"%s\").MacAddress}}", netname)}) 469 MACAfter.WaitWithDefaultTimeout() 470 Expect(MACAfter).Should(ExitCleanly()) 471 472 // Check that IP address did not change between checkpointing and restoring 473 Expect(IPAfter.OutputToString()).To(Equal(IPBefore.OutputToString())) 474 475 // Check that MAC address did not change between checkpointing and restoring 476 Expect(MACAfter.OutputToString()).To(Equal(MACBefore.OutputToString())) 477 478 Expect(result).Should(ExitCleanly()) 479 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 480 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 481 482 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 483 result.WaitWithDefaultTimeout() 484 Expect(result).Should(ExitCleanly()) 485 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 486 }) 487 488 // This test does the same steps which are necessary for migrating 489 // a container from one host to another 490 It("podman checkpoint container with export (migration)", func() { 491 localRunString := getRunString([]string{"--rm", ALPINE, "top"}) 492 session := podmanTest.Podman(localRunString) 493 session.WaitWithDefaultTimeout() 494 Expect(session).Should(ExitCleanly()) 495 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 496 cid := session.OutputToString() 497 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 498 499 result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 500 result.WaitWithDefaultTimeout() 501 502 // As the container has been started with '--rm' it will be completely 503 // cleaned up after checkpointing. 504 Expect(result).Should(ExitCleanly()) 505 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 506 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 507 508 // Restore container the first time with different name. 509 // Using '--ignore-static-ip' as for parallel test runs 510 // each containers gets a random IP address via '--ip'. 511 // '--ignore-static-ip' tells the restore to use the next 512 // available IP address. 513 // First restore the container with a new name/ID to make 514 // sure nothing in the restored container depends on the 515 // original container. 516 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName, "-n", "restore_again", "--ignore-static-ip"}) 517 result.WaitWithDefaultTimeout() 518 519 Expect(result).Should(ExitCleanly()) 520 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 521 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 522 523 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 524 result.WaitWithDefaultTimeout() 525 526 Expect(result).Should(ExitCleanly()) 527 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) 528 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 529 530 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 531 result.WaitWithDefaultTimeout() 532 Expect(result).Should(ExitCleanly()) 533 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 534 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 535 536 // Remove exported checkpoint 537 os.Remove(fileName) 538 }) 539 // This test does the same steps which are necessary for migrating 540 // a container from one host to another 541 It("podman checkpoint container with export and different compression algorithms", func() { 542 localRunString := getRunString([]string{"--rm", ALPINE, "top"}) 543 session := podmanTest.Podman(localRunString) 544 session.WaitWithDefaultTimeout() 545 Expect(session).Should(ExitCleanly()) 546 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 547 cid := session.OutputToString() 548 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 549 550 // Checkpoint with the default algorithm 551 result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 552 result.WaitWithDefaultTimeout() 553 554 // As the container has been started with '--rm' it will be completely 555 // cleaned up after checkpointing. 556 Expect(result).Should(ExitCleanly()) 557 Expect(result.OutputToString()).To(ContainSubstring(cid)) 558 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 559 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 560 561 // Restore container 562 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 563 result.WaitWithDefaultTimeout() 564 565 Expect(result).Should(ExitCleanly()) 566 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 567 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 568 569 // Checkpoint with the zstd algorithm 570 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "--compress", "zstd"}) 571 result.WaitWithDefaultTimeout() 572 573 // As the container has been started with '--rm' it will be completely 574 // cleaned up after checkpointing. 575 Expect(result).Should(ExitCleanly()) 576 Expect(result.OutputToString()).To(ContainSubstring(cid)) 577 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 578 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 579 580 // Restore container 581 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 582 result.WaitWithDefaultTimeout() 583 584 Expect(result).Should(ExitCleanly()) 585 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 586 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 587 588 // Checkpoint with the none algorithm 589 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "-c", "none"}) 590 result.WaitWithDefaultTimeout() 591 592 // As the container has been started with '--rm' it will be completely 593 // cleaned up after checkpointing. 594 Expect(result).Should(ExitCleanly()) 595 Expect(result.OutputToString()).To(ContainSubstring(cid)) 596 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 597 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 598 599 // Restore container 600 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 601 result.WaitWithDefaultTimeout() 602 603 Expect(result).Should(ExitCleanly()) 604 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 605 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 606 607 // Checkpoint with the gzip algorithm 608 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "-c", "gzip"}) 609 result.WaitWithDefaultTimeout() 610 611 // As the container has been started with '--rm' it will be completely 612 // cleaned up after checkpointing. 613 Expect(result).Should(ExitCleanly()) 614 Expect(result.OutputToString()).To(ContainSubstring(cid)) 615 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 616 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 617 618 // Restore container 619 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 620 result.WaitWithDefaultTimeout() 621 622 Expect(result).Should(ExitCleanly()) 623 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 624 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 625 626 // Checkpoint with the non-existing algorithm 627 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName, "-c", "non-existing"}) 628 result.WaitWithDefaultTimeout() 629 630 Expect(result).Should(ExitWithError(125, `selected compression algorithm ("non-existing") not supported. Please select one from`)) 631 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 632 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 633 634 result = podmanTest.Podman([]string{"rm", "--time", "0", "-fa"}) 635 result.WaitWithDefaultTimeout() 636 Expect(result).Should(ExitCleanly()) 637 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 638 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 639 640 // Remove exported checkpoint 641 os.Remove(fileName) 642 }) 643 644 It("podman checkpoint and restore container with root file-system changes", func() { 645 // Start the container 646 localRunString := getRunString([]string{"--rm", ALPINE, "top"}) 647 session := podmanTest.Podman(localRunString) 648 session.WaitWithDefaultTimeout() 649 Expect(session).Should(ExitCleanly()) 650 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 651 cid := session.OutputToString() 652 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 653 654 // Change the container's root file-system 655 result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /test.output"}) 656 result.WaitWithDefaultTimeout() 657 Expect(result).Should(ExitCleanly()) 658 659 result = podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "rm /etc/motd"}) 660 result.WaitWithDefaultTimeout() 661 Expect(result).Should(ExitCleanly()) 662 663 result = podmanTest.Podman([]string{"diff", cid}) 664 result.WaitWithDefaultTimeout() 665 Expect(result).Should(ExitCleanly()) 666 Expect(result.OutputToString()).To(ContainSubstring("C /etc")) 667 Expect(result.OutputToString()).To(ContainSubstring("A /test.output")) 668 Expect(result.OutputToString()).To(ContainSubstring("D /etc/motd")) 669 Expect(result.OutputToStringArray()).To(HaveLen(3)) 670 671 // Checkpoint the container 672 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 673 result.WaitWithDefaultTimeout() 674 675 Expect(result).Should(ExitCleanly()) 676 Expect(result.OutputToString()).To(ContainSubstring(cid)) 677 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 678 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 679 680 // Restore the container 681 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 682 result.WaitWithDefaultTimeout() 683 684 Expect(result).Should(ExitCleanly()) 685 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 686 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 687 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 688 689 // Verify the changes to the container's root file-system 690 result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"}) 691 result.WaitWithDefaultTimeout() 692 Expect(result).Should(ExitCleanly()) 693 Expect(result.OutputToString()).To(ContainSubstring("test" + cid + "test")) 694 695 result = podmanTest.Podman([]string{"diff", cid}) 696 result.WaitWithDefaultTimeout() 697 Expect(result).Should(ExitCleanly()) 698 Expect(result.OutputToString()).To(ContainSubstring("C /etc")) 699 Expect(result.OutputToString()).To(ContainSubstring("A /test.output")) 700 Expect(result.OutputToString()).To(ContainSubstring("D /etc/motd")) 701 Expect(result.OutputToStringArray()).To(HaveLen(3)) 702 703 // Remove exported checkpoint 704 os.Remove(fileName) 705 }) 706 It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during restore", func() { 707 // Start the container 708 // test that restore works without network namespace (https://github.com/containers/podman/issues/14389) 709 session := podmanTest.Podman([]string{"run", "--network=none", "-d", "--rm", ALPINE, "top"}) 710 session.WaitWithDefaultTimeout() 711 Expect(session).Should(ExitCleanly()) 712 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 713 cid := session.OutputToString() 714 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 715 716 // Change the container's root file-system 717 result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /test.output"}) 718 result.WaitWithDefaultTimeout() 719 Expect(result).Should(ExitCleanly()) 720 721 // Checkpoint the container 722 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 723 result.WaitWithDefaultTimeout() 724 725 Expect(result).Should(ExitCleanly()) 726 Expect(result.OutputToString()).To(ContainSubstring(cid)) 727 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 728 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 729 730 // Restore the container 731 result = podmanTest.Podman([]string{"container", "restore", "--ignore-rootfs", "-i", fileName}) 732 result.WaitWithDefaultTimeout() 733 734 Expect(result).Should(ExitCleanly()) 735 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 736 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 737 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 738 739 // Verify the changes to the container's root file-system 740 result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"}) 741 result.WaitWithDefaultTimeout() 742 Expect(result).Should(ExitWithError(1, "cat: can't open '/test.output': No such file or directory")) 743 744 // Remove exported checkpoint 745 os.Remove(fileName) 746 }) 747 It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during checkpoint", func() { 748 // Start the container 749 localRunString := getRunString([]string{"--rm", ALPINE, "top"}) 750 session := podmanTest.Podman(localRunString) 751 session.WaitWithDefaultTimeout() 752 Expect(session).Should(ExitCleanly()) 753 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 754 cid := session.OutputToString() 755 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 756 757 // Change the container's root file-system 758 result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /test.output"}) 759 result.WaitWithDefaultTimeout() 760 Expect(result).Should(ExitCleanly()) 761 762 // Checkpoint the container 763 result = podmanTest.Podman([]string{"container", "checkpoint", "--ignore-rootfs", cid, "-e", fileName}) 764 result.WaitWithDefaultTimeout() 765 766 Expect(result).Should(ExitCleanly()) 767 Expect(result.OutputToString()).To(ContainSubstring(cid)) 768 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 769 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 770 771 // Restore the container 772 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 773 result.WaitWithDefaultTimeout() 774 775 Expect(result).Should(ExitCleanly()) 776 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 777 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 778 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 779 780 // Verify the changes to the container's root file-system 781 result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"}) 782 result.WaitWithDefaultTimeout() 783 Expect(result).Should(ExitWithError(1, "cat: can't open '/test.output': No such file or directory")) 784 785 // Remove exported checkpoint 786 os.Remove(fileName) 787 }) 788 789 It("podman checkpoint and run exec in restored container", func() { 790 // Start the container 791 localRunString := getRunString([]string{"--rm", ALPINE, "top"}) 792 session := podmanTest.Podman(localRunString) 793 session.WaitWithDefaultTimeout() 794 Expect(session).Should(ExitCleanly()) 795 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 796 cid := session.OutputToString() 797 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 798 799 // Checkpoint the container 800 result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 801 result.WaitWithDefaultTimeout() 802 803 Expect(result).Should(ExitCleanly()) 804 Expect(result.OutputToString()).To(ContainSubstring(cid)) 805 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 806 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 807 808 // Restore the container 809 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 810 result.WaitWithDefaultTimeout() 811 812 Expect(result).Should(ExitCleanly()) 813 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 814 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 815 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 816 817 // Exec in the container 818 result = podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo " + cid + " > /test.output"}) 819 result.WaitWithDefaultTimeout() 820 Expect(result).Should(ExitCleanly()) 821 822 result = podmanTest.Podman([]string{"exec", cid, "cat", "/test.output"}) 823 result.WaitWithDefaultTimeout() 824 Expect(result).Should(ExitCleanly()) 825 Expect(result.OutputToString()).To(ContainSubstring(cid)) 826 827 // Remove exported checkpoint 828 os.Remove(fileName) 829 }) 830 831 It("podman checkpoint a container started with --rm", func() { 832 // Start the container 833 localRunString := getRunString([]string{"--rm", ALPINE, "top"}) 834 session := podmanTest.Podman(localRunString) 835 session.WaitWithDefaultTimeout() 836 cid := session.OutputToString() 837 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 838 839 // Checkpoint the container - this should fail as it was started with --rm 840 result := podmanTest.Podman([]string{"container", "checkpoint", cid}) 841 result.WaitWithDefaultTimeout() 842 Expect(result).To(ExitWithError(125, "cannot checkpoint containers that have been started with '--rm'")) 843 844 // Checkpointing with --export should still work 845 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 846 847 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 848 result.WaitWithDefaultTimeout() 849 850 // As the container has been started with '--rm' it will be completely 851 // cleaned up after checkpointing. 852 Expect(result).Should(ExitCleanly()) 853 Expect(result.OutputToString()).To(ContainSubstring(cid)) 854 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 855 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 856 857 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 858 result.WaitWithDefaultTimeout() 859 860 Expect(result).Should(ExitCleanly()) 861 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 862 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 863 864 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 865 result.WaitWithDefaultTimeout() 866 Expect(result).Should(ExitCleanly()) 867 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 868 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 869 870 // Remove exported checkpoint 871 os.Remove(fileName) 872 }) 873 874 It("podman checkpoint a container with volumes", func() { 875 session := podmanTest.Podman([]string{ 876 "build", "-f", "build/basicalpine/Containerfile.volume", "-t", "test-cr-volume", 877 }) 878 session.WaitWithDefaultTimeout() 879 Expect(session).Should(ExitCleanly()) 880 881 // Start the container 882 localRunString := getRunString([]string{ 883 "--rm", 884 "-v", "/volume1", 885 "-v", "my-test-vol:/volume2", 886 "test-cr-volume", 887 "top", 888 }) 889 session = podmanTest.Podman(localRunString) 890 session.WaitWithDefaultTimeout() 891 Expect(session).Should(ExitCleanly()) 892 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 893 894 cid := session.OutputToString() 895 896 // Add file in volume0 897 result := podmanTest.Podman([]string{ 898 "exec", cid, "/bin/sh", "-c", "echo " + cid + " > /volume0/test.output", 899 }) 900 result.WaitWithDefaultTimeout() 901 Expect(result).Should(ExitCleanly()) 902 903 // Add file in volume1 904 result = podmanTest.Podman([]string{ 905 "exec", cid, "/bin/sh", "-c", "echo " + cid + " > /volume1/test.output", 906 }) 907 result.WaitWithDefaultTimeout() 908 Expect(result).Should(ExitCleanly()) 909 910 // Add file in volume2 911 result = podmanTest.Podman([]string{ 912 "exec", cid, "/bin/sh", "-c", "echo " + cid + " > /volume2/test.output", 913 }) 914 result.WaitWithDefaultTimeout() 915 Expect(result).Should(ExitCleanly()) 916 917 checkpointFileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 918 919 // Checkpoint the container 920 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointFileName}) 921 result.WaitWithDefaultTimeout() 922 Expect(result).Should(ExitCleanly()) 923 Expect(result.OutputToString()).To(ContainSubstring(cid)) 924 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 925 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 926 927 // Restore container should fail because named volume still exists 928 result = podmanTest.Podman([]string{"container", "restore", "-i", checkpointFileName}) 929 result.WaitWithDefaultTimeout() 930 Expect(result).To(ExitWithError(125, "volume with name my-test-vol already exists. Use --ignore-volumes to not restore content of volumes")) 931 932 // Remove named volume 933 session = podmanTest.Podman([]string{"volume", "rm", "my-test-vol"}) 934 session.WaitWithDefaultTimeout() 935 Expect(session).Should(ExitCleanly()) 936 937 // Restoring container 938 result = podmanTest.Podman([]string{"container", "restore", "-i", checkpointFileName}) 939 result.WaitWithDefaultTimeout() 940 Expect(result).Should(ExitCleanly()) 941 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 942 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 943 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 944 945 // Validate volume0 content 946 result = podmanTest.Podman([]string{"exec", cid, "cat", "/volume0/test.output"}) 947 result.WaitWithDefaultTimeout() 948 Expect(result).Should(ExitCleanly()) 949 Expect(result.OutputToString()).To(ContainSubstring(cid)) 950 951 // Validate volume1 content 952 result = podmanTest.Podman([]string{"exec", cid, "cat", "/volume1/test.output"}) 953 result.WaitWithDefaultTimeout() 954 Expect(result).Should(ExitCleanly()) 955 Expect(result.OutputToString()).To(ContainSubstring(cid)) 956 957 // Validate volume2 content 958 result = podmanTest.Podman([]string{"exec", cid, "cat", "/volume2/test.output"}) 959 result.WaitWithDefaultTimeout() 960 Expect(result).Should(ExitCleanly()) 961 Expect(result.OutputToString()).To(ContainSubstring(cid)) 962 963 // Remove exported checkpoint 964 os.Remove(checkpointFileName) 965 }) 966 967 It("podman checkpoint container with --pre-checkpoint", func() { 968 if !criu.MemTrack() { 969 Skip("system (architecture/kernel/CRIU) does not support memory tracking") 970 } 971 localRunString := getRunString([]string{ALPINE, "top"}) 972 session := podmanTest.Podman(localRunString) 973 session.WaitWithDefaultTimeout() 974 Expect(session).Should(ExitCleanly()) 975 cid := session.OutputToString() 976 977 result := podmanTest.Podman([]string{"container", "checkpoint", "-P", cid}) 978 result.WaitWithDefaultTimeout() 979 980 Expect(result).Should(ExitCleanly()) 981 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 982 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 983 984 result = podmanTest.Podman([]string{"container", "checkpoint", "--with-previous", cid}) 985 result.WaitWithDefaultTimeout() 986 987 Expect(result).Should(ExitCleanly()) 988 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 989 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 990 991 result = podmanTest.Podman([]string{"container", "restore", cid}) 992 result.WaitWithDefaultTimeout() 993 994 Expect(result).Should(ExitCleanly()) 995 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 996 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 997 }) 998 999 It("podman checkpoint container with --pre-checkpoint and export (migration)", func() { 1000 SkipIfRemote("--import-previous is not yet supported on the remote client") 1001 if !criu.MemTrack() { 1002 Skip("system (architecture/kernel/CRIU) does not support memory tracking") 1003 } 1004 localRunString := getRunString([]string{ALPINE, "top"}) 1005 session := podmanTest.Podman(localRunString) 1006 session.WaitWithDefaultTimeout() 1007 Expect(session).Should(ExitCleanly()) 1008 cid := session.OutputToString() 1009 preCheckpointFileName := filepath.Join(podmanTest.TempDir, "/pre-checkpoint-"+cid+".tar.gz") 1010 checkpointFileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1011 1012 result := podmanTest.Podman([]string{"container", "checkpoint", "-P", "-e", preCheckpointFileName, cid}) 1013 result.WaitWithDefaultTimeout() 1014 1015 Expect(result).Should(ExitCleanly()) 1016 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1017 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1018 1019 result = podmanTest.Podman([]string{"container", "checkpoint", "--with-previous", "-e", checkpointFileName, cid}) 1020 result.WaitWithDefaultTimeout() 1021 1022 Expect(result).Should(ExitCleanly()) 1023 Expect(result.OutputToString()).To(ContainSubstring(cid)) 1024 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1025 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 1026 1027 result = podmanTest.Podman([]string{"rm", "-t", "0", "-f", cid}) 1028 result.WaitWithDefaultTimeout() 1029 Expect(result).Should(ExitCleanly()) 1030 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1031 1032 result = podmanTest.Podman([]string{"container", "restore", "-i", checkpointFileName, "--import-previous", preCheckpointFileName}) 1033 result.WaitWithDefaultTimeout() 1034 1035 Expect(result).Should(ExitCleanly()) 1036 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1037 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1038 1039 os.Remove(checkpointFileName) 1040 os.Remove(preCheckpointFileName) 1041 }) 1042 1043 It("podman checkpoint and restore container with different port mappings", func() { 1044 randomPort, err := utils.GetRandomPort() 1045 Expect(err).ShouldNot(HaveOccurred()) 1046 localRunString := getRunString([]string{"-p", fmt.Sprintf("%d:6379", randomPort), "--rm", REDIS_IMAGE}) 1047 session := podmanTest.Podman(localRunString) 1048 session.WaitWithDefaultTimeout() 1049 Expect(session).Should(ExitCleanly()) 1050 cid := session.OutputToString() 1051 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1052 1053 if !WaitContainerReady(podmanTest, cid, "Ready to accept connections", 20, 1) { 1054 Fail("Container failed to get ready") 1055 } 1056 1057 GinkgoWriter.Printf("Trying to connect to redis server at localhost:%d\n", randomPort) 1058 // Open a network connection to the redis server via initial port mapping 1059 conn, err := net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", randomPort), time.Duration(3)*time.Second) 1060 Expect(err).ShouldNot(HaveOccurred()) 1061 conn.Close() 1062 1063 // Checkpoint the container 1064 result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 1065 result.WaitWithDefaultTimeout() 1066 1067 // As the container has been started with '--rm' it will be completely 1068 // cleaned up after checkpointing. 1069 Expect(result).Should(ExitCleanly()) 1070 Expect(result.OutputToString()).To(ContainSubstring(cid)) 1071 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1072 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1073 1074 // Restore container with different port mapping 1075 newRandomPort, err := utils.GetRandomPort() 1076 Expect(err).ShouldNot(HaveOccurred()) 1077 result = podmanTest.Podman([]string{"container", "restore", "-p", fmt.Sprintf("%d:6379", newRandomPort), "-i", fileName}) 1078 result.WaitWithDefaultTimeout() 1079 1080 Expect(result).Should(ExitCleanly()) 1081 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1082 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1083 1084 // Open a network connection to the redis server via initial port mapping 1085 // This should fail 1086 _, err = net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", randomPort), time.Duration(3)*time.Second) 1087 Expect(err).To(HaveOccurred()) 1088 Expect(err.Error()).To(ContainSubstring("connection refused")) 1089 // Open a network connection to the redis server via new port mapping 1090 GinkgoWriter.Printf("Trying to reconnect to redis server at localhost:%d\n", newRandomPort) 1091 conn, err = net.DialTimeout("tcp4", fmt.Sprintf("localhost:%d", newRandomPort), time.Duration(3)*time.Second) 1092 Expect(err).ShouldNot(HaveOccurred()) 1093 conn.Close() 1094 1095 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 1096 result.WaitWithDefaultTimeout() 1097 Expect(result).Should(ExitCleanly()) 1098 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1099 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1100 1101 // Remove exported checkpoint 1102 os.Remove(fileName) 1103 }) 1104 1105 namespaceCombination := []string{ 1106 "ipc,net,uts,pid", 1107 "ipc,net,uts", 1108 "ipc,net", 1109 "net,uts,pid", 1110 "net,uts", 1111 "uts,pid", 1112 } 1113 for _, share := range namespaceCombination { 1114 testName := fmt.Sprintf( 1115 "podman checkpoint and restore container out of and into pod (%s)", 1116 share, 1117 ) 1118 1119 share := share // copy into local scope, for use inside function 1120 1121 It(testName, func() { 1122 if err := criu.CheckForCriu(criu.PodCriuVersion); err != nil { 1123 Skip(fmt.Sprintf("check CRIU pod version error: %v", err)) 1124 } 1125 if !crutils.CRRuntimeSupportsPodCheckpointRestore(podmanTest.OCIRuntime) { 1126 Skip("runtime does not support pod restore: " + podmanTest.OCIRuntime) 1127 } 1128 // Create a pod 1129 session := podmanTest.Podman([]string{ 1130 "pod", 1131 "create", 1132 "--share", 1133 share, 1134 }) 1135 session.WaitWithDefaultTimeout() 1136 Expect(session).To(ExitCleanly()) 1137 podID := session.OutputToString() 1138 1139 session = podmanTest.Podman([]string{ 1140 "run", 1141 "-d", 1142 "--rm", 1143 "--pod", 1144 podID, 1145 ALPINE, 1146 "top", 1147 }) 1148 session.WaitWithDefaultTimeout() 1149 Expect(session).To(ExitCleanly()) 1150 cid := session.OutputToString() 1151 1152 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1153 1154 // Checkpoint the container 1155 result := podmanTest.Podman([]string{ 1156 "container", 1157 "checkpoint", 1158 "-e", 1159 fileName, 1160 cid, 1161 }) 1162 result.WaitWithDefaultTimeout() 1163 1164 // As the container has been started with '--rm' it will be completely 1165 // cleaned up after checkpointing. 1166 // #11784 (closed wontfix): runc warns "lstat /sys/.../machine.slice/...: ENOENT" 1167 // so we can't use ExitCleanly() 1168 if podmanTest.OCIRuntime == "runc" { 1169 Expect(result).To(Exit(0)) 1170 } else { 1171 Expect(result).To(ExitCleanly()) 1172 } 1173 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1174 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 1175 1176 // Remove the pod and create a new pod 1177 result = podmanTest.Podman([]string{ 1178 "pod", 1179 "rm", 1180 podID, 1181 }) 1182 result.WaitWithDefaultTimeout() 1183 Expect(result).To(ExitCleanly()) 1184 1185 // First create a pod with different shared namespaces. 1186 // Restore should fail 1187 1188 wrongShare := share[:strings.LastIndex(share, ",")] 1189 1190 session = podmanTest.Podman([]string{ 1191 "pod", 1192 "create", 1193 "--share", 1194 wrongShare, 1195 }) 1196 session.WaitWithDefaultTimeout() 1197 Expect(session).To(ExitCleanly()) 1198 podID = session.OutputToString() 1199 1200 // Restore container with different port mapping 1201 result = podmanTest.Podman([]string{ 1202 "container", 1203 "restore", 1204 "--pod", 1205 podID, 1206 "-i", 1207 fileName, 1208 }) 1209 result.WaitWithDefaultTimeout() 1210 Expect(result).To(ExitWithError(125, "does not share the ")) 1211 1212 // Remove the pod and create a new pod 1213 result = podmanTest.Podman([]string{ 1214 "pod", 1215 "rm", 1216 podID, 1217 }) 1218 result.WaitWithDefaultTimeout() 1219 Expect(result).To(ExitCleanly()) 1220 1221 session = podmanTest.Podman([]string{ 1222 "pod", 1223 "create", 1224 "--share", 1225 share, 1226 }) 1227 session.WaitWithDefaultTimeout() 1228 Expect(session).To(ExitCleanly()) 1229 podID = session.OutputToString() 1230 1231 // Restore container with different port mapping 1232 result = podmanTest.Podman([]string{ 1233 "container", 1234 "restore", 1235 "--pod", 1236 podID, 1237 "-i", 1238 fileName, 1239 }) 1240 result.WaitWithDefaultTimeout() 1241 1242 Expect(result).To(ExitCleanly()) 1243 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) 1244 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1245 1246 result = podmanTest.Podman([]string{ 1247 "rm", 1248 "-f", 1249 result.OutputToString(), 1250 }) 1251 result.WaitWithDefaultTimeout() 1252 // #11784 (closed wontfix): runc warns "lstat /sys/.../machine.slice/...: ENOENT" 1253 // so we can't use ExitCleanly() 1254 if podmanTest.OCIRuntime == "runc" { 1255 Expect(result).To(Exit(0)) 1256 } else { 1257 Expect(result).To(ExitCleanly()) 1258 } 1259 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1260 Expect(podmanTest.NumberOfContainers()).To(Equal(1)) 1261 1262 result = podmanTest.Podman([]string{ 1263 "pod", 1264 "rm", 1265 "-fa", 1266 }) 1267 result.WaitWithDefaultTimeout() 1268 Expect(result).To(ExitCleanly()) 1269 1270 // Remove exported checkpoint 1271 os.Remove(fileName) 1272 }) 1273 } 1274 1275 It("podman checkpoint container with export (migration) and --ipc host", func() { 1276 localRunString := getRunString([]string{"--rm", "--ipc", "host", ALPINE, "top"}) 1277 session := podmanTest.Podman(localRunString) 1278 session.WaitWithDefaultTimeout() 1279 Expect(session).Should(ExitCleanly()) 1280 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1281 cid := session.OutputToString() 1282 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1283 1284 result := podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", fileName}) 1285 result.WaitWithDefaultTimeout() 1286 1287 // As the container has been started with '--rm' it will be completely 1288 // cleaned up after checkpointing. 1289 // Cannot use ExitCleanly() because "skipping [ssh-agent-path] since it is a socket" 1290 Expect(result).Should(Exit(0)) 1291 Expect(result.OutputToString()).To(ContainSubstring(cid)) 1292 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1293 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1294 1295 result = podmanTest.Podman([]string{"container", "restore", "-i", fileName}) 1296 result.WaitWithDefaultTimeout() 1297 1298 Expect(result).Should(ExitCleanly()) 1299 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1300 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1301 1302 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 1303 result.WaitWithDefaultTimeout() 1304 Expect(result).Should(ExitCleanly()) 1305 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1306 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1307 1308 // Remove exported checkpoint 1309 os.Remove(fileName) 1310 }) 1311 1312 It("podman checkpoint container with export and statistics", func() { 1313 localRunString := getRunString([]string{ 1314 "--rm", 1315 ALPINE, 1316 "top", 1317 }) 1318 session := podmanTest.Podman(localRunString) 1319 session.WaitWithDefaultTimeout() 1320 Expect(session).Should(ExitCleanly()) 1321 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1322 cid := session.OutputToString() 1323 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1324 defer os.Remove(fileName) 1325 1326 result := podmanTest.Podman([]string{ 1327 "container", 1328 "checkpoint", 1329 cid, "-e", 1330 fileName, 1331 }) 1332 result.WaitWithDefaultTimeout() 1333 1334 // As the container has been started with '--rm' it will be completely 1335 // cleaned up after checkpointing. 1336 Expect(result).Should(ExitCleanly()) 1337 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1338 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1339 1340 // Extract checkpoint archive 1341 destinationDirectory := filepath.Join(podmanTest.TempDir, "dest") 1342 err = os.MkdirAll(destinationDirectory, os.ModePerm) 1343 Expect(err).ToNot(HaveOccurred()) 1344 1345 tarsession := SystemExec( 1346 "tar", 1347 []string{ 1348 "xf", 1349 fileName, 1350 "-C", 1351 destinationDirectory, 1352 }, 1353 ) 1354 Expect(tarsession).Should(ExitCleanly()) 1355 1356 _, err = os.Stat(filepath.Join(destinationDirectory, stats.StatsDump)) 1357 Expect(err).ShouldNot(HaveOccurred()) 1358 }) 1359 1360 It("podman checkpoint and restore containers with --print-stats", func() { 1361 session1 := podmanTest.Podman(getRunString([]string{REDIS_IMAGE})) 1362 session1.WaitWithDefaultTimeout() 1363 Expect(session1).Should(ExitCleanly()) 1364 1365 session2 := podmanTest.Podman(getRunString([]string{REDIS_IMAGE, "top"})) 1366 session2.WaitWithDefaultTimeout() 1367 Expect(session2).Should(ExitCleanly()) 1368 1369 result := podmanTest.Podman([]string{ 1370 "container", 1371 "checkpoint", 1372 "-a", 1373 "--print-stats", 1374 }) 1375 result.WaitWithDefaultTimeout() 1376 1377 Expect(result).Should(ExitCleanly()) 1378 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1379 1380 type checkpointStatistics struct { 1381 PodmanDuration int64 `json:"podman_checkpoint_duration"` 1382 ContainerStatistics []*entities.CheckpointReport `json:"container_statistics"` 1383 } 1384 1385 cS := new(checkpointStatistics) 1386 err := json.Unmarshal([]byte(result.OutputToString()), cS) 1387 Expect(err).ShouldNot(HaveOccurred()) 1388 1389 Expect(cS.ContainerStatistics).To(HaveLen(2)) 1390 Expect(cS.PodmanDuration).To(BeNumerically(">", cS.ContainerStatistics[0].RuntimeDuration)) 1391 Expect(cS.PodmanDuration).To(BeNumerically(">", cS.ContainerStatistics[1].RuntimeDuration)) 1392 Expect(cS.ContainerStatistics[0].RuntimeDuration).To( 1393 BeNumerically(">", cS.ContainerStatistics[0].CRIUStatistics.FrozenTime), 1394 ) 1395 Expect(cS.ContainerStatistics[1].RuntimeDuration).To( 1396 BeNumerically(">", cS.ContainerStatistics[1].CRIUStatistics.FrozenTime), 1397 ) 1398 1399 ps := podmanTest.Podman([]string{ 1400 "ps", 1401 "-q", 1402 "--no-trunc", 1403 }) 1404 ps.WaitWithDefaultTimeout() 1405 Expect(ps).Should(ExitCleanly()) 1406 Expect(ps.OutputToString()).To(Not(ContainSubstring(session1.OutputToString()))) 1407 Expect(ps.OutputToString()).To(Not(ContainSubstring(session2.OutputToString()))) 1408 1409 result = podmanTest.Podman([]string{ 1410 "container", 1411 "restore", 1412 "-a", 1413 "--print-stats", 1414 }) 1415 result.WaitWithDefaultTimeout() 1416 1417 Expect(result).Should(ExitCleanly()) 1418 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2)) 1419 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1420 Expect(podmanTest.GetContainerStatus()).To(Not(ContainSubstring("Exited"))) 1421 1422 type restoreStatistics struct { 1423 PodmanDuration int64 `json:"podman_restore_duration"` 1424 ContainerStatistics []*entities.RestoreReport `json:"container_statistics"` 1425 } 1426 1427 rS := new(restoreStatistics) 1428 err = json.Unmarshal([]byte(result.OutputToString()), rS) 1429 Expect(err).ShouldNot(HaveOccurred()) 1430 1431 Expect(cS.ContainerStatistics).To(HaveLen(2)) 1432 Expect(cS.PodmanDuration).To(BeNumerically(">", cS.ContainerStatistics[0].RuntimeDuration)) 1433 Expect(cS.PodmanDuration).To(BeNumerically(">", cS.ContainerStatistics[1].RuntimeDuration)) 1434 Expect(cS.ContainerStatistics[0].RuntimeDuration).To( 1435 BeNumerically(">", cS.ContainerStatistics[0].CRIUStatistics.RestoreTime), 1436 ) 1437 Expect(cS.ContainerStatistics[1].RuntimeDuration).To( 1438 BeNumerically(">", cS.ContainerStatistics[1].CRIUStatistics.RestoreTime), 1439 ) 1440 1441 result = podmanTest.Podman([]string{ 1442 "rm", 1443 "-t", 1444 "0", 1445 "-fa", 1446 }) 1447 result.WaitWithDefaultTimeout() 1448 Expect(result).Should(ExitCleanly()) 1449 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1450 }) 1451 1452 It("podman checkpoint and restore container with --file-locks", func() { 1453 localRunString := getRunString([]string{"--name", "test_name", ALPINE, "flock", "test.lock", "sh", "-c", "echo READY;sleep 100"}) 1454 session := podmanTest.Podman(localRunString) 1455 session.WaitWithDefaultTimeout() 1456 Expect(session).Should(ExitCleanly()) 1457 Expect(WaitContainerReady(podmanTest, "test_name", "READY", 5, 1)).To(BeTrue(), "Timed out waiting for READY") 1458 1459 // Checkpoint is expected to fail without --file-locks 1460 result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"}) 1461 result.WaitWithDefaultTimeout() 1462 Expect(result).Should(ExitWithError(125, "failed: exit status 1")) 1463 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1464 1465 // Checkpoint is expected to succeed with --file-locks 1466 result = podmanTest.Podman([]string{"container", "checkpoint", "--file-locks", "test_name"}) 1467 result.WaitWithDefaultTimeout() 1468 Expect(result).Should(ExitCleanly()) 1469 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1470 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 1471 1472 result = podmanTest.Podman([]string{"container", "restore", "--file-locks", "test_name"}) 1473 result.WaitWithDefaultTimeout() 1474 1475 Expect(result).Should(ExitCleanly()) 1476 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1477 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1478 1479 result = podmanTest.Podman([]string{"rm", "-t", "0", "-f", "test_name"}) 1480 result.WaitWithDefaultTimeout() 1481 Expect(result).Should(ExitCleanly()) 1482 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1483 }) 1484 1485 It("podman checkpoint container with export and verify runtime", func() { 1486 SkipIfRemote("podman-remote does not support --runtime flag") 1487 localRunString := getRunString([]string{ 1488 "--rm", 1489 ALPINE, 1490 "top", 1491 }) 1492 session := podmanTest.Podman(localRunString) 1493 session.WaitWithDefaultTimeout() 1494 Expect(session).Should(ExitCleanly()) 1495 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1496 cid := session.OutputToString() 1497 1498 session = podmanTest.Podman([]string{ 1499 "inspect", 1500 "--format", 1501 "{{.OCIRuntime}}", 1502 cid, 1503 }) 1504 session.WaitWithDefaultTimeout() 1505 Expect(session).Should(ExitCleanly()) 1506 runtime := session.OutputToString() 1507 1508 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1509 1510 result := podmanTest.Podman([]string{ 1511 "container", 1512 "checkpoint", 1513 cid, "-e", 1514 fileName, 1515 }) 1516 result.WaitWithDefaultTimeout() 1517 1518 // As the container has been started with '--rm' it will be completely 1519 // cleaned up after checkpointing. 1520 Expect(result).Should(ExitCleanly()) 1521 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1522 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1523 1524 result = podmanTest.Podman([]string{ 1525 "container", 1526 "restore", 1527 "-i", 1528 fileName, 1529 }) 1530 result.WaitWithDefaultTimeout() 1531 Expect(result).Should(ExitCleanly()) 1532 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1533 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1534 1535 // The restored container should have the same runtime as the original container 1536 result = podmanTest.Podman([]string{ 1537 "inspect", 1538 "--format", 1539 "{{.OCIRuntime}}", 1540 cid, 1541 }) 1542 result.WaitWithDefaultTimeout() 1543 Expect(result).Should(ExitCleanly()) 1544 Expect(session.OutputToString()).To(Equal(runtime)) 1545 1546 // Remove exported checkpoint 1547 os.Remove(fileName) 1548 }) 1549 1550 It("podman checkpoint container with export and verify non-default runtime", func() { 1551 SkipIfRemote("podman-remote does not support --runtime flag") 1552 // This test triggers the edge case where: 1553 // 1. Default runtime is crun 1554 // 2. Container is created with runc 1555 // 3. Checkpoint without setting --runtime into archive 1556 // 4. Restore without setting --runtime from archive 1557 // It should be expected that podman identifies runtime 1558 // from the checkpoint archive. 1559 1560 // Prevent --runtime arg from being set to force using default 1561 // runtime unless explicitly set through passed args. 1562 preservedMakeOptions := podmanTest.PodmanMakeOptions 1563 podmanTest.PodmanMakeOptions = func(args []string, noEvents, noCache bool) []string { 1564 defaultArgs := preservedMakeOptions(args, noEvents, noCache) 1565 for i := range args { 1566 // Runtime is set explicitly, so we should keep --runtime arg. 1567 if args[i] == "--runtime" { 1568 return defaultArgs 1569 } 1570 } 1571 updatedArgs := make([]string, 0) 1572 for i := 0; i < len(defaultArgs); i++ { 1573 // Remove --runtime arg, letting podman fall back to its default 1574 if defaultArgs[i] == "--runtime" { 1575 i++ 1576 } else { 1577 updatedArgs = append(updatedArgs, defaultArgs[i]) 1578 } 1579 } 1580 return updatedArgs 1581 } 1582 1583 for _, runtime := range []string{"runc", "crun"} { 1584 if err := exec.Command(runtime, "--help").Run(); err != nil { 1585 Skip(fmt.Sprintf("%s not found in PATH; this test requires both runc and crun", runtime)) 1586 } 1587 } 1588 1589 // Detect default runtime 1590 session := podmanTest.Podman([]string{"info", "--format", "{{.Host.OCIRuntime.Name}}"}) 1591 session.WaitWithDefaultTimeout() 1592 Expect(session).Should(ExitCleanly()) 1593 if defaultRuntime := session.OutputToString(); defaultRuntime != "crun" { 1594 Skip(fmt.Sprintf("Default runtime is %q; this test requires crun to be default", defaultRuntime)) 1595 } 1596 1597 // Force non-default runtime "runc" 1598 localRunString := getRunString([]string{"--runtime", "runc", "--rm", ALPINE, "top"}) 1599 session = podmanTest.Podman(localRunString) 1600 session.WaitWithDefaultTimeout() 1601 Expect(session).Should(ExitCleanly()) 1602 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1603 cid := session.OutputToString() 1604 1605 session = podmanTest.Podman([]string{"inspect", "--format", "{{.OCIRuntime}}", cid}) 1606 session.WaitWithDefaultTimeout() 1607 Expect(session).Should(ExitCleanly()) 1608 Expect(session.OutputToString()).To(Equal("runc")) 1609 1610 checkpointExportPath := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1611 1612 session = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointExportPath}) 1613 session.WaitWithDefaultTimeout() 1614 // As the container has been started with '--rm' it will be completely 1615 // cleaned up after checkpointing. 1616 Expect(session).Should(ExitCleanly()) 1617 Expect(session.OutputToString()).To(ContainSubstring(cid)) 1618 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1619 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1620 1621 session = podmanTest.Podman([]string{"container", "restore", "-i", checkpointExportPath}) 1622 session.WaitWithDefaultTimeout() 1623 Expect(session).Should(ExitCleanly()) 1624 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1625 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1626 1627 // The restored container should have the same runtime as the original container 1628 session = podmanTest.Podman([]string{"inspect", "--format", "{{.OCIRuntime}}", cid}) 1629 session.WaitWithDefaultTimeout() 1630 Expect(session).Should(ExitCleanly()) 1631 Expect(session.OutputToString()).To(Equal("runc")) 1632 1633 // Remove exported checkpoint 1634 os.Remove(checkpointExportPath) 1635 }) 1636 1637 It("podman checkpoint container with export and try to change the runtime", func() { 1638 SkipIfRemote("podman-remote does not support --runtime flag") 1639 // This test will only run if runc and crun both exist 1640 if !strings.Contains(podmanTest.OCIRuntime, "crun") { 1641 Skip("Test requires crun and runc") 1642 } 1643 cmd := exec.Command("runc") 1644 if err := cmd.Start(); err != nil { 1645 Skip("Test requires crun and runc") 1646 } 1647 if err := cmd.Wait(); err != nil { 1648 Skip("Test requires crun and runc") 1649 } 1650 localRunString := getRunString([]string{ 1651 "--rm", 1652 ALPINE, 1653 "top", 1654 }) 1655 // Let's start a container with runc and try to restore it with crun (expected to fail) 1656 localRunString = append( 1657 []string{ 1658 "--runtime", 1659 "runc", 1660 }, 1661 localRunString..., 1662 ) 1663 session := podmanTest.Podman(localRunString) 1664 session.WaitWithDefaultTimeout() 1665 Expect(session).Should(ExitCleanly()) 1666 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1667 cid := session.OutputToString() 1668 1669 session = podmanTest.Podman([]string{ 1670 "inspect", 1671 "--format", 1672 "{{.OCIRuntime}}", 1673 cid, 1674 }) 1675 session.WaitWithDefaultTimeout() 1676 Expect(session).Should(ExitCleanly()) 1677 runtime := session.OutputToString() 1678 1679 fileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1680 1681 result := podmanTest.Podman([]string{ 1682 "container", 1683 "checkpoint", 1684 cid, "-e", 1685 fileName, 1686 }) 1687 result.WaitWithDefaultTimeout() 1688 1689 // As the container has been started with '--rm' it will be completely 1690 // cleaned up after checkpointing. 1691 Expect(result).Should(ExitCleanly()) 1692 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1693 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1694 1695 // This should fail as the container was checkpointed with runc 1696 result = podmanTest.Podman([]string{ 1697 "--runtime", 1698 "crun", 1699 "container", 1700 "restore", 1701 "-i", 1702 fileName, 1703 }) 1704 result.WaitWithDefaultTimeout() 1705 1706 Expect(result).Should(ExitWithError(125, "and cannot be restored with runtime")) 1707 1708 result = podmanTest.Podman([]string{ 1709 "--runtime", 1710 "runc", 1711 "container", 1712 "restore", 1713 "-i", 1714 fileName, 1715 }) 1716 result.WaitWithDefaultTimeout() 1717 Expect(result).Should(ExitCleanly()) 1718 1719 result = podmanTest.Podman([]string{ 1720 "inspect", 1721 "--format", 1722 "{{.OCIRuntime}}", 1723 cid, 1724 }) 1725 result.WaitWithDefaultTimeout() 1726 Expect(result).Should(ExitCleanly()) 1727 Expect(result.OutputToString()).To(Equal(runtime)) 1728 1729 result = podmanTest.Podman([]string{ 1730 "--runtime", 1731 "runc", 1732 "rm", 1733 "-fa", 1734 }) 1735 result.WaitWithDefaultTimeout() 1736 Expect(result).Should(ExitCleanly()) 1737 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1738 // Remove exported checkpoint 1739 os.Remove(fileName) 1740 }) 1741 1742 It("podman checkpoint and restore dev/shm content with --export and --import", func() { 1743 localRunString := getRunString([]string{"--rm", ALPINE, "top"}) 1744 session := podmanTest.Podman(localRunString) 1745 session.WaitWithDefaultTimeout() 1746 Expect(session).Should(ExitCleanly()) 1747 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1748 cid := session.OutputToString() 1749 1750 // Add test file in dev/shm 1751 result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /dev/shm/test.output"}) 1752 result.WaitWithDefaultTimeout() 1753 Expect(result).Should(ExitCleanly()) 1754 1755 session = podmanTest.Podman([]string{"inspect", "--format", "{{.OCIRuntime}}", cid}) 1756 session.WaitWithDefaultTimeout() 1757 Expect(session).Should(ExitCleanly()) 1758 runtime := session.OutputToString() 1759 1760 checkpointFileName := filepath.Join(podmanTest.TempDir, "/checkpoint-"+cid+".tar.gz") 1761 result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointFileName}) 1762 result.WaitWithDefaultTimeout() 1763 1764 // As the container has been started with '--rm' it will be completely 1765 // cleaned up after checkpointing. 1766 Expect(result).Should(ExitCleanly()) 1767 Expect(result.OutputToString()).To(ContainSubstring(cid)) 1768 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1769 Expect(podmanTest.NumberOfContainers()).To(Equal(0)) 1770 1771 result = podmanTest.Podman([]string{"container", "restore", "-i", checkpointFileName}) 1772 result.WaitWithDefaultTimeout() 1773 Expect(result).Should(ExitCleanly()) 1774 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1775 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1776 1777 // The restored container should have the same runtime as the original container 1778 result = podmanTest.Podman([]string{"inspect", "--format", "{{.OCIRuntime}}", cid}) 1779 result.WaitWithDefaultTimeout() 1780 Expect(result).Should(ExitCleanly()) 1781 Expect(session.OutputToString()).To(Equal(runtime)) 1782 1783 // Verify the test file content in dev/shm 1784 result = podmanTest.Podman([]string{"exec", cid, "cat", "/dev/shm/test.output"}) 1785 result.WaitWithDefaultTimeout() 1786 Expect(result).Should(ExitCleanly()) 1787 Expect(result.OutputToString()).To(ContainSubstring("test" + cid + "test")) 1788 1789 // Remove exported checkpoint 1790 os.Remove(checkpointFileName) 1791 }) 1792 1793 It("podman checkpoint and restore dev/shm content", func() { 1794 localRunString := getRunString([]string{ALPINE, "top"}) 1795 session := podmanTest.Podman(localRunString) 1796 session.WaitWithDefaultTimeout() 1797 Expect(session).Should(ExitCleanly()) 1798 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1799 cid := session.OutputToString() 1800 1801 // Add test file in dev/shm 1802 result := podmanTest.Podman([]string{"exec", cid, "/bin/sh", "-c", "echo test" + cid + "test > /dev/shm/test.output"}) 1803 result.WaitWithDefaultTimeout() 1804 Expect(result).Should(ExitCleanly()) 1805 1806 result = podmanTest.Podman([]string{"container", "checkpoint", cid}) 1807 result.WaitWithDefaultTimeout() 1808 Expect(result).Should(ExitCleanly()) 1809 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1810 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) 1811 1812 result = podmanTest.Podman([]string{"container", "restore", cid}) 1813 result.WaitWithDefaultTimeout() 1814 Expect(result).Should(ExitCleanly()) 1815 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) 1816 Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) 1817 1818 // Verify the test file content in dev/shm 1819 result = podmanTest.Podman([]string{"exec", cid, "cat", "/dev/shm/test.output"}) 1820 result.WaitWithDefaultTimeout() 1821 Expect(result).Should(ExitCleanly()) 1822 Expect(result.OutputToString()).To(ContainSubstring("test" + cid + "test")) 1823 1824 result = podmanTest.Podman([]string{"rm", "-t", "0", "-fa"}) 1825 result.WaitWithDefaultTimeout() 1826 Expect(result).Should(ExitCleanly()) 1827 Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) 1828 }) 1829 })