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