Skip to content

Commit

Permalink
[test] Checking if criu cgroup v1 kludges help
Browse files Browse the repository at this point in the history
Testing criu PR 2545.

Signed-off-by: Kir Kolyshkin <[email protected]>
  • Loading branch information
kolyshkin committed Dec 17, 2024
1 parent 3ddaa91 commit 6f5c745
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 136 deletions.
8 changes: 6 additions & 2 deletions .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ task:
CIRRUS_WORKING_DIR: /home/runc
GO_VERSION: "1.23"
BATS_VERSION: "v1.9.0"
RPMS: gcc git iptables jq glibc-static libseccomp-devel make criu fuse-sshfs container-selinux
RPMS: gcc git iptables jq glibc-static libseccomp-devel make fuse-sshfs container-selinux asciidoc gnutls-devel libaio-devel libasan libcap-devel libnet-devel libnl3-devel libselinux-devel make protobuf-c-devel protobuf-devel xmlto libdrm-devel
# yamllint disable rule:key-duplicates
matrix:
DISTRO: almalinux-8
Expand Down Expand Up @@ -121,13 +121,17 @@ task:
# Find out the latest minor release URL.
filename=$(curl -fsSL "${PREFIX}?mode=json&include=all" | jq -r --arg Ver "go$GO_VERSION." '. | map(select(.version | contains($Ver))) | first | .files[] | select(.os == "linux" and .arch == "amd64" and .kind == "archive") | .filename')
curl -fsSL "$PREFIX$filename" | tar Cxz /usr/local
# install bats
# Install bats
cd /tmp
git clone https://github.com/bats-core/bats-core
cd bats-core
git checkout $BATS_VERSION
./install.sh /usr/local
cd -
# Testing https://github.com/checkpoint-restore/criu/pull/2545
git clone https://github.com/kolyshkin/criu.git ~/criu
(cd ~/criu && git checkout freeze-kludges && sudo make install-criu)
rm -rf ~/criu
# Add a user for rootless tests
useradd -u2000 -m -d/home/rootless -s/bin/bash rootless
# Allow root and rootless itself to execute `ssh rootless@localhost` in tests/rootless.sh
Expand Down
13 changes: 3 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,6 @@ jobs:
race: ["-race", ""]
criu: ["", "criu-dev"]
exclude:
# Disable most of criu-dev jobs, as they are expensive
# (need to compile criu) and don't add much value/coverage.
- criu: criu-dev
go-version: 1.22.x
- criu: criu-dev
rootless: rootless
- criu: criu-dev
race: -race
- go-version: 1.22.x
os: actuated-arm64-6cpu-8gb
- race: "-race"
Expand Down Expand Up @@ -124,8 +116,9 @@ jobs:
sudo apt -qy install \
libcap-dev libnet1-dev libnl-3-dev \
libprotobuf-c-dev libprotobuf-dev protobuf-c-compiler protobuf-compiler
git clone https://github.com/checkpoint-restore/criu.git ~/criu
(cd ~/criu && git checkout ${{ matrix.criu }} && sudo make install-criu)
# Testing https://github.com/checkpoint-restore/criu/pull/2545
git clone https://github.com/kolyshkin/criu.git ~/criu
(cd ~/criu && git checkout freeze-kludges && sudo make install-criu)
rm -rf ~/criu
- name: install go ${{ matrix.go-version }}
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ unittest: runcimage

.PHONY: localunittest
localunittest: test-binaries
$(GO) test -timeout 3m -tags "$(BUILDTAGS)" $(TESTFLAGS) -v ./...
$(GO) test -timeout 10m -tags "$(BUILDTAGS)" $(TESTFLAGS) -v ./...

.PHONY: integration
integration: runcimage
Expand Down
253 changes: 130 additions & 123 deletions libcontainer/integration/checkpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os/exec"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"

Expand All @@ -17,6 +18,8 @@ func criuFeature(feature string) bool {
return exec.Command("criu", "check", "--feature", feature).Run() == nil
}

const iter = 150

func TestUsernsCheckpoint(t *testing.T) {
testCheckpoint(t, true)
}
Expand Down Expand Up @@ -44,128 +47,132 @@ func testCheckpoint(t *testing.T, userns bool) {
t.Skip("Test requires userns")
}

config := newTemplateConfig(t, &tParam{userns: userns})
stateDir := t.TempDir()

container, err := libcontainer.Create(stateDir, "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()
var parentImage string

// Test pre-dump if mem_dirty_track is available.
if criuFeature("mem_dirty_track") {
parentImage = "../criu-parent"
parentDir := filepath.Join(tmp, "criu-parent")
preDumpOpts := &libcontainer.CriuOpts{
ImagesDirectory: parentDir,
WorkDirectory: parentDir,
PreDump: true,
}

if err := container.Checkpoint(preDumpOpts); err != nil {
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: parentImage,
}

if err := container.Checkpoint(checkpointOpts); err != nil {
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 = libcontainer.Load(stateDir, "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 {
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)
for i := range iter {
t.Run(strconv.Itoa(i), func(t *testing.T) {
config := newTemplateConfig(t, &tParam{userns: userns})
stateDir := t.TempDir()

container, err := libcontainer.Create(stateDir, "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()
var parentImage string

// Test pre-dump if mem_dirty_track is available.
if criuFeature("mem_dirty_track") {
parentImage = "../criu-parent"
parentDir := filepath.Join(tmp, "criu-parent")
preDumpOpts := &libcontainer.CriuOpts{
ImagesDirectory: parentDir,
WorkDirectory: parentDir,
PreDump: true,
}

if err := container.Checkpoint(preDumpOpts); err != nil {
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: parentImage,
}

if err := container.Checkpoint(checkpointOpts); err != nil {
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 = libcontainer.Load(stateDir, "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 {
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)
}
})
}
}

0 comments on commit 6f5c745

Please sign in to comment.