mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 22:37:14 +08:00
3bc606e9d3
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>
191 lines
3.8 KiB
Go
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)
|
|
}
|
|
}
|