github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/integration/container/run_cgroupns_linux_test.go (about)

     1  package container // import "github.com/docker/docker/integration/container"
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/docker/docker/client"
    10  	"github.com/docker/docker/integration/internal/container"
    11  	"github.com/docker/docker/integration/internal/requirement"
    12  	"github.com/docker/docker/testutil/daemon"
    13  	"gotest.tools/v3/assert"
    14  	is "gotest.tools/v3/assert/cmp"
    15  	"gotest.tools/v3/poll"
    16  	"gotest.tools/v3/skip"
    17  )
    18  
    19  // Gets the value of the cgroup namespace for pid 1 of a container
    20  func containerCgroupNamespace(ctx context.Context, t *testing.T, client *client.Client, cID string) string {
    21  	res, err := container.Exec(ctx, client, cID, []string{"readlink", "/proc/1/ns/cgroup"})
    22  	assert.NilError(t, err)
    23  	assert.Assert(t, is.Len(res.Stderr(), 0))
    24  	assert.Equal(t, 0, res.ExitCode)
    25  	return strings.TrimSpace(res.Stdout())
    26  }
    27  
    28  // Bring up a daemon with the specified default cgroup namespace mode, and then create a container with the container options
    29  func testRunWithCgroupNs(t *testing.T, daemonNsMode string, containerOpts ...func(*container.TestContainerConfig)) (string, string) {
    30  	d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode(daemonNsMode))
    31  	client := d.NewClientT(t)
    32  	ctx := context.Background()
    33  
    34  	d.StartWithBusybox(t)
    35  	defer d.Stop(t)
    36  
    37  	cID := container.Run(ctx, t, client, containerOpts...)
    38  	poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
    39  
    40  	daemonCgroup := d.CgroupNamespace(t)
    41  	containerCgroup := containerCgroupNamespace(ctx, t, client, cID)
    42  	return containerCgroup, daemonCgroup
    43  }
    44  
    45  // Bring up a daemon with the specified default cgroup namespace mode. Create a container with the container options,
    46  // expecting an error with the specified string
    47  func testCreateFailureWithCgroupNs(t *testing.T, daemonNsMode string, errStr string, containerOpts ...func(*container.TestContainerConfig)) {
    48  	d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode(daemonNsMode))
    49  	client := d.NewClientT(t)
    50  	ctx := context.Background()
    51  
    52  	d.StartWithBusybox(t)
    53  	defer d.Stop(t)
    54  	container.CreateExpectingErr(ctx, t, client, errStr, containerOpts...)
    55  }
    56  
    57  func TestCgroupNamespacesRun(t *testing.T) {
    58  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    59  	skip.If(t, testEnv.IsRemoteDaemon())
    60  	skip.If(t, !requirement.CgroupNamespacesEnabled())
    61  
    62  	// When the daemon defaults to private cgroup namespaces, containers launched
    63  	// should be in their own private cgroup namespace by default
    64  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private")
    65  	assert.Assert(t, daemonCgroup != containerCgroup)
    66  }
    67  
    68  func TestCgroupNamespacesRunPrivileged(t *testing.T) {
    69  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    70  	skip.If(t, testEnv.IsRemoteDaemon())
    71  	skip.If(t, !requirement.CgroupNamespacesEnabled())
    72  
    73  	// When the daemon defaults to private cgroup namespaces, privileged containers
    74  	// launched should not be inside their own cgroup namespaces
    75  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithPrivileged(true))
    76  	assert.Assert(t, daemonCgroup == containerCgroup)
    77  }
    78  
    79  func TestCgroupNamespacesRunDaemonHostMode(t *testing.T) {
    80  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    81  	skip.If(t, testEnv.IsRemoteDaemon())
    82  	skip.If(t, !requirement.CgroupNamespacesEnabled())
    83  
    84  	// When the daemon defaults to host cgroup namespaces, containers
    85  	// launched should not be inside their own cgroup namespaces
    86  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "host")
    87  	assert.Assert(t, daemonCgroup == containerCgroup)
    88  }
    89  
    90  func TestCgroupNamespacesRunHostMode(t *testing.T) {
    91  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    92  	skip.If(t, testEnv.IsRemoteDaemon())
    93  	skip.If(t, !requirement.CgroupNamespacesEnabled())
    94  
    95  	// When the daemon defaults to private cgroup namespaces, containers launched
    96  	// with a cgroup ns mode of "host" should not be inside their own cgroup namespaces
    97  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithCgroupnsMode("host"))
    98  	assert.Assert(t, daemonCgroup == containerCgroup)
    99  }
   100  
   101  func TestCgroupNamespacesRunPrivateMode(t *testing.T) {
   102  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   103  	skip.If(t, testEnv.IsRemoteDaemon())
   104  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   105  
   106  	// When the daemon defaults to private cgroup namespaces, containers launched
   107  	// with a cgroup ns mode of "private" should be inside their own cgroup namespaces
   108  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithCgroupnsMode("private"))
   109  	assert.Assert(t, daemonCgroup != containerCgroup)
   110  }
   111  
   112  func TestCgroupNamespacesRunPrivilegedAndPrivate(t *testing.T) {
   113  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   114  	skip.If(t, testEnv.IsRemoteDaemon())
   115  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   116  
   117  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithPrivileged(true), container.WithCgroupnsMode("private"))
   118  	assert.Assert(t, daemonCgroup != containerCgroup)
   119  }
   120  
   121  func TestCgroupNamespacesRunInvalidMode(t *testing.T) {
   122  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   123  	skip.If(t, testEnv.IsRemoteDaemon())
   124  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   125  
   126  	// An invalid cgroup namespace mode should return an error on container creation
   127  	errStr := "invalid cgroup namespace mode: invalid"
   128  	testCreateFailureWithCgroupNs(t, "private", errStr, container.WithCgroupnsMode("invalid"))
   129  }
   130  
   131  // Clients before 1.40 expect containers to be created in the host cgroup namespace,
   132  // regardless of the default setting of the daemon
   133  func TestCgroupNamespacesRunOlderClient(t *testing.T) {
   134  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   135  	skip.If(t, testEnv.IsRemoteDaemon())
   136  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   137  
   138  	d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode("private"))
   139  	client := d.NewClientT(t, client.WithVersion("1.39"))
   140  
   141  	ctx := context.Background()
   142  	d.StartWithBusybox(t)
   143  	defer d.Stop(t)
   144  
   145  	cID := container.Run(ctx, t, client)
   146  	poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
   147  
   148  	daemonCgroup := d.CgroupNamespace(t)
   149  	containerCgroup := containerCgroupNamespace(ctx, t, client, cID)
   150  	assert.Assert(t, daemonCgroup == containerCgroup)
   151  }