Files
runc/libcontainer/integration/checkpoint_test.go
Kir Kolyshkin 3bc606e9d3 libct/int: adapt to Go 1.15
1. Use t.TempDir instead of ioutil.TempDir. This means no need for an
   explicit cleanup, which removes some code, including newTestBundle
   and newTestRoot.

2. Move newRootfs invocation down to newTemplateConfig, removing a need
   for explicit rootfs creation. Also, remove rootfs from tParam as it
   is no longer needed (there was a since test case in which two
   containers shared the same rootfs, but it does not look like it's
   required for the test).

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2021-07-27 01:41:47 -07:00

191 lines
3.8 KiB
Go

package integration
import (
"bufio"
"bytes"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/opencontainers/runc/libcontainer"
"golang.org/x/sys/unix"
)
func showFile(t *testing.T, fname string) {
t.Helper()
t.Logf("=== %s ===\n", fname)
f, err := os.Open(fname)
if err != nil {
t.Log(err)
return
}
defer f.Close() //nolint: errcheck
scanner := bufio.NewScanner(f)
for scanner.Scan() {
t.Log(scanner.Text())
}
if err := scanner.Err(); err != nil {
t.Log(err)
return
}
t.Logf("=== END ===\n")
}
func TestUsernsCheckpoint(t *testing.T) {
if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
t.Skip("Test requires userns.")
}
cmd := exec.Command("criu", "check", "--feature", "userns")
if err := cmd.Run(); err != nil {
t.Skip("Unable to c/r a container with userns")
}
testCheckpoint(t, true)
}
func TestCheckpoint(t *testing.T) {
testCheckpoint(t, false)
}
func testCheckpoint(t *testing.T, userns bool) {
if testing.Short() {
return
}
if _, err := exec.LookPath("criu"); err != nil {
t.Skipf("criu binary not found: %v", err)
}
config := newTemplateConfig(t, &tParam{userns: userns})
factory, err := libcontainer.New(t.TempDir(), libcontainer.Cgroupfs)
ok(t, err)
container, err := factory.Create("test", config)
ok(t, err)
defer destroyContainer(container)
stdinR, stdinW, err := os.Pipe()
ok(t, err)
var stdout bytes.Buffer
pconfig := libcontainer.Process{
Cwd: "/",
Args: []string{"cat"},
Env: standardEnvironment,
Stdin: stdinR,
Stdout: &stdout,
Init: true,
}
err = container.Run(&pconfig)
_ = stdinR.Close()
defer stdinW.Close() //nolint: errcheck
ok(t, err)
pid, err := pconfig.Pid()
ok(t, err)
process, err := os.FindProcess(pid)
ok(t, err)
tmp := t.TempDir()
parentDir := filepath.Join(tmp, "criu-parent")
preDumpOpts := &libcontainer.CriuOpts{
ImagesDirectory: parentDir,
WorkDirectory: parentDir,
PreDump: true,
}
preDumpLog := filepath.Join(preDumpOpts.WorkDirectory, "dump.log")
if err := container.Checkpoint(preDumpOpts); err != nil {
showFile(t, preDumpLog)
t.Fatal(err)
}
state, err := container.Status()
ok(t, err)
if state != libcontainer.Running {
t.Fatal("Unexpected preDump state: ", state)
}
imagesDir := filepath.Join(tmp, "criu")
checkpointOpts := &libcontainer.CriuOpts{
ImagesDirectory: imagesDir,
WorkDirectory: imagesDir,
ParentImage: "../criu-parent",
}
dumpLog := filepath.Join(checkpointOpts.WorkDirectory, "dump.log")
restoreLog := filepath.Join(checkpointOpts.WorkDirectory, "restore.log")
if err := container.Checkpoint(checkpointOpts); err != nil {
showFile(t, dumpLog)
t.Fatal(err)
}
state, err = container.Status()
ok(t, err)
if state != libcontainer.Stopped {
t.Fatal("Unexpected state checkpoint: ", state)
}
_ = stdinW.Close()
_, err = process.Wait()
ok(t, err)
// reload the container
container, err = factory.Load("test")
ok(t, err)
restoreStdinR, restoreStdinW, err := os.Pipe()
ok(t, err)
var restoreStdout bytes.Buffer
restoreProcessConfig := &libcontainer.Process{
Cwd: "/",
Stdin: restoreStdinR,
Stdout: &restoreStdout,
Init: true,
}
err = container.Restore(restoreProcessConfig, checkpointOpts)
_ = restoreStdinR.Close()
defer restoreStdinW.Close() //nolint: errcheck
if err != nil {
showFile(t, restoreLog)
t.Fatal(err)
}
state, err = container.Status()
ok(t, err)
if state != libcontainer.Running {
t.Fatal("Unexpected restore state: ", state)
}
pid, err = restoreProcessConfig.Pid()
ok(t, err)
err = unix.Kill(pid, 0)
ok(t, err)
_, err = restoreStdinW.WriteString("Hello!")
ok(t, err)
_ = restoreStdinW.Close()
waitProcess(restoreProcessConfig, t)
output := restoreStdout.String()
if !strings.Contains(output, "Hello!") {
t.Fatal("Did not restore the pipe correctly:", output)
}
}