diff --git a/Dockerfile b/Dockerfile index 749c5edb97..2c43cb0461 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,8 @@ RUN apt-get update && apt-get install -y \ libaio-dev \ libcap-dev \ libfuse-dev \ + libnet-dev \ + libnl-3-dev \ libostree-dev \ libprotobuf-dev \ libprotobuf-c0-dev \ @@ -110,6 +112,16 @@ RUN set -x \ && go get -u github.com/mailru/easyjson/... \ && install -D -m 755 "$GOPATH"/bin/easyjson /usr/bin/ +# Install criu +ENV CRIU_COMMIT 584cbe4643c3fc7dc901ff08bf923ca0fe7326f9 +RUN set -x \ + && cd /tmp \ + && git clone https://github.com/checkpoint-restore/criu.git \ + && cd criu \ + && make \ + && install -D -m 755 criu/criu /usr/sbin/ \ + && rm -rf /tmp/criu + # Install cni config #RUN make install.cni RUN mkdir -p /etc/cni/net.d/ diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go new file mode 100644 index 0000000000..6c5d891a0f --- /dev/null +++ b/test/e2e/checkpoint_test.go @@ -0,0 +1,129 @@ +package integration + +import ( + "fmt" + "os" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman checkpoint", func() { + var ( + tempdir string + err error + podmanTest PodmanTest + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanCreate(tempdir) + podmanTest.RestoreAllArtifacts() + // At least CRIU 3.11 is needed + skip, err := podmanTest.isCriuAtLeast(31100) + if err != nil || skip { + Skip("CRIU missing or too old.") + } + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()) + GinkgoWriter.Write([]byte(timedResult)) + }) + + It("podman checkpoint bogus container", func() { + session := podmanTest.Podman([]string{"container", "checkpoint", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("podman restore bogus container", func() { + session := podmanTest.Podman([]string{"container", "restore", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) + + It("podman checkpoint a running container by id", func() { + // CRIU does not work with seccomp correctly on RHEL7 + session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToString() + + result := podmanTest.Podman([]string{"container", "checkpoint", cid}) + result.WaitWithDefaultTimeout() + + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) + + result = podmanTest.Podman([]string{"container", "restore", cid}) + result.WaitWithDefaultTimeout() + + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) + }) + + It("podman checkpoint a running container by name", func() { + session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "--name", "test_name", "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + result := podmanTest.Podman([]string{"container", "checkpoint", "test_name"}) + result.WaitWithDefaultTimeout() + + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) + + result = podmanTest.Podman([]string{"container", "restore", "test_name"}) + result.WaitWithDefaultTimeout() + + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up")) + }) + + It("podman pause a checkpointed container by id", func() { + session := podmanTest.Podman([]string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", ALPINE, "top"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + cid := session.OutputToString() + + result := podmanTest.Podman([]string{"container", "checkpoint", cid}) + result.WaitWithDefaultTimeout() + + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) + + result = podmanTest.Podman([]string{"pause", cid}) + result.WaitWithDefaultTimeout() + + Expect(result.ExitCode()).To(Equal(125)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Exited")) + + result = podmanTest.Podman([]string{"container", "restore", cid}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + + result = podmanTest.Podman([]string{"rm", cid}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(125)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) + + result = podmanTest.Podman([]string{"rm", "-f", cid}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) + + }) +}) diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index d521632d72..a032b0e885 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -2,6 +2,7 @@ package integration import ( "bufio" + "bytes" "context" "encoding/json" "fmt" @@ -64,6 +65,7 @@ type PodmanTest struct { TempDir string CgroupManager string Host HostOS + CriuBinary string } // HostOS is a simple struct for the test os @@ -164,6 +166,7 @@ func PodmanCreate(tempDir string) PodmanTest { runCBinary = "/usr/bin/runc" } + criuBinary := "/usr/sbin/criu" CNIConfigDir := "/etc/cni/net.d" p := PodmanTest{ @@ -179,6 +182,7 @@ func PodmanCreate(tempDir string) PodmanTest { TempDir: tempDir, CgroupManager: cgroupManager, Host: host, + CriuBinary: criuBinary, } // Setup registries.conf ENV variable @@ -678,6 +682,39 @@ func (p *PodmanTest) setRegistriesConfigEnv(b []byte) { ioutil.WriteFile(outfile, b, 0644) } +func (p *PodmanTest) isCriuAtLeast(version int) (bool, error) { + cmd := exec.Command(p.CriuBinary, "-V") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return false, err + } + + var x int + var y int + var z int + + fmt.Sscanf(out.String(), "Version: %d.%d.%d", &x, &y, &z) + + if strings.Contains(out.String(), "GitID") { + // If CRIU is built from git it contains a git ID. + // If that is the case, increase minor by one as this + // could mean we are running a development version. + y = y + 1 + } + + parsed_version := x*10000 + y*100 + z + + fmt.Println(parsed_version) + + if parsed_version >= version { + return false, nil + } else { + return true, nil + } +} + func resetRegistriesConfigEnv() { os.Setenv("REGISTRIES_CONFIG_PATH", "") }