github.com/lacework-dev/go-moby@v20.10.12+incompatible/integration/container/checkpoint_test.go (about)

     1  package container // import "github.com/docker/docker/integration/container"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os/exec"
     7  	"regexp"
     8  	"sort"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/docker/docker/api/types"
    13  	mounttypes "github.com/docker/docker/api/types/mount"
    14  	"github.com/docker/docker/client"
    15  	"github.com/docker/docker/integration/internal/container"
    16  	"github.com/docker/docker/testutil/request"
    17  	"gotest.tools/v3/assert"
    18  	is "gotest.tools/v3/assert/cmp"
    19  	"gotest.tools/v3/poll"
    20  	"gotest.tools/v3/skip"
    21  )
    22  
    23  func containerExec(t *testing.T, client client.APIClient, cID string, cmd []string) {
    24  	t.Logf("Exec: %s", cmd)
    25  	ctx := context.Background()
    26  	r, err := container.Exec(ctx, client, cID, cmd)
    27  	assert.NilError(t, err)
    28  	t.Log(r.Combined())
    29  	assert.Equal(t, r.ExitCode, 0)
    30  }
    31  
    32  func TestCheckpoint(t *testing.T) {
    33  	t.Skip("TestCheckpoint is broken; see https://github.com/moby/moby/issues/38963")
    34  	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
    35  	skip.If(t, !testEnv.DaemonInfo.ExperimentalBuild)
    36  
    37  	defer setupTest(t)()
    38  
    39  	cmd := exec.Command("criu", "check")
    40  	stdoutStderr, err := cmd.CombinedOutput()
    41  	t.Logf("%s", stdoutStderr)
    42  	assert.NilError(t, err)
    43  
    44  	ctx := context.Background()
    45  	client := request.NewAPIClient(t)
    46  
    47  	mnt := mounttypes.Mount{
    48  		Type:   mounttypes.TypeTmpfs,
    49  		Target: "/tmp",
    50  	}
    51  
    52  	t.Log("Start a container")
    53  	cID := container.Run(ctx, t, client, container.WithMount(mnt))
    54  	poll.WaitOn(t,
    55  		container.IsInState(ctx, client, cID, "running"),
    56  		poll.WithDelay(100*time.Millisecond),
    57  	)
    58  
    59  	cptOpt := types.CheckpointCreateOptions{
    60  		Exit:         false,
    61  		CheckpointID: "test",
    62  	}
    63  
    64  	{
    65  		// FIXME: ipv6 iptables modules are not uploaded in the test environment
    66  		cmd := exec.Command("bash", "-c", "set -x; "+
    67  			"mount --bind $(type -P true) $(type -P ip6tables-restore) && "+
    68  			"mount --bind $(type -P true) $(type -P ip6tables-save)")
    69  		stdoutStderr, err = cmd.CombinedOutput()
    70  		t.Logf("%s", stdoutStderr)
    71  		assert.NilError(t, err)
    72  
    73  		defer func() {
    74  			cmd := exec.Command("bash", "-c", "set -x; "+
    75  				"umount -c -i -l $(type -P ip6tables-restore); "+
    76  				"umount -c -i -l $(type -P ip6tables-save)")
    77  			stdoutStderr, err = cmd.CombinedOutput()
    78  			t.Logf("%s", stdoutStderr)
    79  			assert.NilError(t, err)
    80  		}()
    81  	}
    82  	t.Log("Do a checkpoint and leave the container running")
    83  	err = client.CheckpointCreate(ctx, cID, cptOpt)
    84  	if err != nil {
    85  		// An error can contain a path to a dump file
    86  		t.Logf("%s", err)
    87  		re := regexp.MustCompile("path= (.*): ")
    88  		m := re.FindStringSubmatch(fmt.Sprintf("%s", err))
    89  		if len(m) >= 2 {
    90  			dumpLog := m[1]
    91  			t.Logf("%s", dumpLog)
    92  			cmd := exec.Command("cat", dumpLog)
    93  			stdoutStderr, err = cmd.CombinedOutput()
    94  			t.Logf("%s", stdoutStderr)
    95  		}
    96  	}
    97  	assert.NilError(t, err)
    98  
    99  	inspect, err := client.ContainerInspect(ctx, cID)
   100  	assert.NilError(t, err)
   101  	assert.Check(t, is.Equal(true, inspect.State.Running))
   102  
   103  	checkpoints, err := client.CheckpointList(ctx, cID, types.CheckpointListOptions{})
   104  	assert.NilError(t, err)
   105  	assert.Equal(t, len(checkpoints), 1)
   106  	assert.Equal(t, checkpoints[0].Name, "test")
   107  
   108  	// Create a test file on a tmpfs mount.
   109  	containerExec(t, client, cID, []string{"touch", "/tmp/test-file"})
   110  
   111  	// Do a second checkpoint
   112  	cptOpt = types.CheckpointCreateOptions{
   113  		Exit:         true,
   114  		CheckpointID: "test2",
   115  	}
   116  	t.Log("Do a checkpoint and stop the container")
   117  	err = client.CheckpointCreate(ctx, cID, cptOpt)
   118  	assert.NilError(t, err)
   119  
   120  	poll.WaitOn(t,
   121  		container.IsInState(ctx, client, cID, "exited"),
   122  		poll.WithDelay(100*time.Millisecond),
   123  	)
   124  
   125  	inspect, err = client.ContainerInspect(ctx, cID)
   126  	assert.NilError(t, err)
   127  	assert.Check(t, is.Equal(false, inspect.State.Running))
   128  
   129  	// Check that both checkpoints are listed.
   130  	checkpoints, err = client.CheckpointList(ctx, cID, types.CheckpointListOptions{})
   131  	assert.NilError(t, err)
   132  	assert.Equal(t, len(checkpoints), 2)
   133  	cptNames := make([]string, 2)
   134  	for i, c := range checkpoints {
   135  		cptNames[i] = c.Name
   136  	}
   137  	sort.Strings(cptNames)
   138  	assert.Equal(t, cptNames[0], "test")
   139  	assert.Equal(t, cptNames[1], "test2")
   140  
   141  	// Restore the container from a second checkpoint.
   142  	startOpt := types.ContainerStartOptions{
   143  		CheckpointID: "test2",
   144  	}
   145  	t.Log("Restore the container")
   146  	err = client.ContainerStart(ctx, cID, startOpt)
   147  	assert.NilError(t, err)
   148  
   149  	inspect, err = client.ContainerInspect(ctx, cID)
   150  	assert.NilError(t, err)
   151  	assert.Check(t, is.Equal(true, inspect.State.Running))
   152  
   153  	// Check that the test file has been restored.
   154  	containerExec(t, client, cID, []string{"test", "-f", "/tmp/test-file"})
   155  
   156  	for _, id := range []string{"test", "test2"} {
   157  		cptDelOpt := types.CheckpointDeleteOptions{
   158  			CheckpointID: id,
   159  		}
   160  
   161  		err = client.CheckpointDelete(ctx, cID, cptDelOpt)
   162  		assert.NilError(t, err)
   163  	}
   164  }