gopkg.in/docker/docker.v20@v20.10.27/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  	skip.If(t, testEnv.DaemonInfo.CgroupVersion == "2", "on cgroup v2, privileged containers use private cgroupns")
    73  
    74  	// When the daemon defaults to private cgroup namespaces, privileged containers
    75  	// launched should not be inside their own cgroup namespaces
    76  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithPrivileged(true))
    77  	assert.Assert(t, daemonCgroup == containerCgroup)
    78  }
    79  
    80  func TestCgroupNamespacesRunDaemonHostMode(t *testing.T) {
    81  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    82  	skip.If(t, testEnv.IsRemoteDaemon())
    83  	skip.If(t, !requirement.CgroupNamespacesEnabled())
    84  
    85  	// When the daemon defaults to host cgroup namespaces, containers
    86  	// launched should not be inside their own cgroup namespaces
    87  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "host")
    88  	assert.Assert(t, daemonCgroup == containerCgroup)
    89  }
    90  
    91  func TestCgroupNamespacesRunHostMode(t *testing.T) {
    92  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    93  	skip.If(t, testEnv.IsRemoteDaemon())
    94  	skip.If(t, !requirement.CgroupNamespacesEnabled())
    95  
    96  	// When the daemon defaults to private cgroup namespaces, containers launched
    97  	// with a cgroup ns mode of "host" should not be inside their own cgroup namespaces
    98  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithCgroupnsMode("host"))
    99  	assert.Assert(t, daemonCgroup == containerCgroup)
   100  }
   101  
   102  func TestCgroupNamespacesRunPrivateMode(t *testing.T) {
   103  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   104  	skip.If(t, testEnv.IsRemoteDaemon())
   105  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   106  
   107  	// When the daemon defaults to private cgroup namespaces, containers launched
   108  	// with a cgroup ns mode of "private" should be inside their own cgroup namespaces
   109  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithCgroupnsMode("private"))
   110  	assert.Assert(t, daemonCgroup != containerCgroup)
   111  }
   112  
   113  func TestCgroupNamespacesRunPrivilegedAndPrivate(t *testing.T) {
   114  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   115  	skip.If(t, testEnv.IsRemoteDaemon())
   116  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   117  
   118  	containerCgroup, daemonCgroup := testRunWithCgroupNs(t, "private", container.WithPrivileged(true), container.WithCgroupnsMode("private"))
   119  	assert.Assert(t, daemonCgroup != containerCgroup)
   120  }
   121  
   122  func TestCgroupNamespacesRunInvalidMode(t *testing.T) {
   123  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   124  	skip.If(t, testEnv.IsRemoteDaemon())
   125  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   126  
   127  	// An invalid cgroup namespace mode should return an error on container creation
   128  	errStr := "invalid cgroup namespace mode: invalid"
   129  	testCreateFailureWithCgroupNs(t, "private", errStr, container.WithCgroupnsMode("invalid"))
   130  }
   131  
   132  // Clients before 1.40 expect containers to be created in the host cgroup namespace,
   133  // regardless of the default setting of the daemon, unless running with cgroup v2
   134  func TestCgroupNamespacesRunOlderClient(t *testing.T) {
   135  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
   136  	skip.If(t, testEnv.IsRemoteDaemon())
   137  	skip.If(t, !requirement.CgroupNamespacesEnabled())
   138  
   139  	d := daemon.New(t, daemon.WithDefaultCgroupNamespaceMode("private"))
   140  	client := d.NewClientT(t, client.WithVersion("1.39"))
   141  
   142  	ctx := context.Background()
   143  	d.StartWithBusybox(t)
   144  	defer d.Stop(t)
   145  
   146  	cID := container.Run(ctx, t, client)
   147  	poll.WaitOn(t, container.IsInState(ctx, client, cID, "running"), poll.WithDelay(100*time.Millisecond))
   148  
   149  	daemonCgroup := d.CgroupNamespace(t)
   150  	containerCgroup := containerCgroupNamespace(ctx, t, client, cID)
   151  	if testEnv.DaemonInfo.CgroupVersion != "2" {
   152  		assert.Assert(t, daemonCgroup == containerCgroup)
   153  	} else {
   154  		assert.Assert(t, daemonCgroup != containerCgroup)
   155  	}
   156  }