github.com/rish1988/moby@v25.0.2+incompatible/daemon/oci_linux_test.go (about)

     1  package daemon // import "github.com/docker/docker/daemon"
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path/filepath"
     7  	"testing"
     8  
     9  	containertypes "github.com/docker/docker/api/types/container"
    10  	"github.com/docker/docker/container"
    11  	"github.com/docker/docker/daemon/config"
    12  	"github.com/docker/docker/daemon/network"
    13  	"github.com/docker/docker/libnetwork"
    14  	"github.com/google/go-cmp/cmp/cmpopts"
    15  	"github.com/opencontainers/runtime-spec/specs-go"
    16  	"golang.org/x/sys/unix"
    17  	"gotest.tools/v3/assert"
    18  	is "gotest.tools/v3/assert/cmp"
    19  	"gotest.tools/v3/skip"
    20  )
    21  
    22  func setupFakeDaemon(t *testing.T, c *container.Container) *Daemon {
    23  	t.Helper()
    24  	root := t.TempDir()
    25  
    26  	rootfs := filepath.Join(root, "rootfs")
    27  	err := os.MkdirAll(rootfs, 0o755)
    28  	assert.NilError(t, err)
    29  
    30  	netController, err := libnetwork.New()
    31  	assert.NilError(t, err)
    32  
    33  	d := &Daemon{
    34  		// some empty structs to avoid getting a panic
    35  		// caused by a null pointer dereference
    36  		linkIndex:     newLinkIndex(),
    37  		netController: netController,
    38  		imageService:  &fakeImageService{},
    39  	}
    40  
    41  	c.Root = root
    42  	c.BaseFS = rootfs
    43  
    44  	if c.Config == nil {
    45  		c.Config = new(containertypes.Config)
    46  	}
    47  	if c.HostConfig == nil {
    48  		c.HostConfig = new(containertypes.HostConfig)
    49  	}
    50  	if c.NetworkSettings == nil {
    51  		c.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)}
    52  	}
    53  
    54  	// HORRIBLE HACK: clean up shm mounts leaked by some tests. Otherwise the
    55  	// offending tests would fail due to the mounts blocking the temporary
    56  	// directory from being cleaned up.
    57  	t.Cleanup(func() {
    58  		if c.ShmPath != "" {
    59  			var err error
    60  			for err == nil { // Some tests over-mount over the same path multiple times.
    61  				err = unix.Unmount(c.ShmPath, unix.MNT_DETACH)
    62  			}
    63  		}
    64  	})
    65  
    66  	return d
    67  }
    68  
    69  type fakeImageService struct {
    70  	ImageService
    71  }
    72  
    73  func (i *fakeImageService) StorageDriver() string {
    74  	return "overlay"
    75  }
    76  
    77  // TestTmpfsDevShmNoDupMount checks that a user-specified /dev/shm tmpfs
    78  // mount (as in "docker run --tmpfs /dev/shm:rw,size=NNN") does not result
    79  // in "Duplicate mount point" error from the engine.
    80  // https://github.com/moby/moby/issues/35455
    81  func TestTmpfsDevShmNoDupMount(t *testing.T) {
    82  	skip.If(t, os.Getuid() != 0, "skipping test that requires root")
    83  	c := &container.Container{
    84  		ShmPath: "foobar", // non-empty, for c.IpcMounts() to work
    85  		HostConfig: &containertypes.HostConfig{
    86  			IpcMode: containertypes.IPCModeShareable, // default mode
    87  			// --tmpfs /dev/shm:rw,exec,size=NNN
    88  			Tmpfs: map[string]string{
    89  				"/dev/shm": "rw,exec,size=1g",
    90  			},
    91  		},
    92  	}
    93  	d := setupFakeDaemon(t, c)
    94  
    95  	_, err := d.createSpec(context.TODO(), &configStore{}, c, nil)
    96  	assert.Check(t, err)
    97  }
    98  
    99  // TestIpcPrivateVsReadonly checks that in case of IpcMode: private
   100  // and ReadonlyRootfs: true (as in "docker run --ipc private --read-only")
   101  // the resulting /dev/shm mount is NOT made read-only.
   102  // https://github.com/moby/moby/issues/36503
   103  func TestIpcPrivateVsReadonly(t *testing.T) {
   104  	skip.If(t, os.Getuid() != 0, "skipping test that requires root")
   105  	c := &container.Container{
   106  		HostConfig: &containertypes.HostConfig{
   107  			IpcMode:        containertypes.IPCModePrivate,
   108  			ReadonlyRootfs: true,
   109  		},
   110  	}
   111  	d := setupFakeDaemon(t, c)
   112  
   113  	s, err := d.createSpec(context.TODO(), &configStore{}, c, nil)
   114  	assert.Check(t, err)
   115  
   116  	// Find the /dev/shm mount in ms, check it does not have ro
   117  	for _, m := range s.Mounts {
   118  		if m.Destination != "/dev/shm" {
   119  			continue
   120  		}
   121  		assert.Check(t, is.Equal(false, inSlice(m.Options, "ro")))
   122  	}
   123  }
   124  
   125  // TestSysctlOverride ensures that any implicit sysctls (such as
   126  // Config.Domainname) are overridden by an explicit sysctl in the HostConfig.
   127  func TestSysctlOverride(t *testing.T) {
   128  	skip.If(t, os.Getuid() != 0, "skipping test that requires root")
   129  	c := &container.Container{
   130  		Config: &containertypes.Config{
   131  			Hostname:   "foobar",
   132  			Domainname: "baz.cyphar.com",
   133  		},
   134  		HostConfig: &containertypes.HostConfig{
   135  			NetworkMode: "bridge",
   136  			Sysctls:     map[string]string{},
   137  		},
   138  	}
   139  	d := setupFakeDaemon(t, c)
   140  
   141  	// Ensure that the implicit sysctl is set correctly.
   142  	s, err := d.createSpec(context.TODO(), &configStore{}, c, nil)
   143  	assert.NilError(t, err)
   144  	assert.Equal(t, s.Hostname, "foobar")
   145  	assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.Config.Domainname)
   146  	if sysctlExists("net.ipv4.ip_unprivileged_port_start") {
   147  		assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], "0")
   148  	}
   149  	if sysctlExists("net.ipv4.ping_group_range") {
   150  		assert.Equal(t, s.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647")
   151  	}
   152  
   153  	// Set an explicit sysctl.
   154  	c.HostConfig.Sysctls["kernel.domainname"] = "foobar.net"
   155  	assert.Assert(t, c.HostConfig.Sysctls["kernel.domainname"] != c.Config.Domainname)
   156  	c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"] = "1024"
   157  
   158  	s, err = d.createSpec(context.TODO(), &configStore{}, c, nil)
   159  	assert.NilError(t, err)
   160  	assert.Equal(t, s.Hostname, "foobar")
   161  	assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.HostConfig.Sysctls["kernel.domainname"])
   162  	assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"])
   163  
   164  	// Ensure the ping_group_range is not set on a daemon with user-namespaces enabled
   165  	s, err = d.createSpec(context.TODO(), &configStore{Config: config.Config{RemappedRoot: "dummy:dummy"}}, c, nil)
   166  	assert.NilError(t, err)
   167  	_, ok := s.Linux.Sysctl["net.ipv4.ping_group_range"]
   168  	assert.Assert(t, !ok)
   169  
   170  	// Ensure the ping_group_range is set on a container in "host" userns mode
   171  	// on a daemon with user-namespaces enabled
   172  	c.HostConfig.UsernsMode = "host"
   173  	s, err = d.createSpec(context.TODO(), &configStore{Config: config.Config{RemappedRoot: "dummy:dummy"}}, c, nil)
   174  	assert.NilError(t, err)
   175  	assert.Equal(t, s.Linux.Sysctl["net.ipv4.ping_group_range"], "0 2147483647")
   176  }
   177  
   178  // TestSysctlOverrideHost ensures that any implicit network sysctls are not set
   179  // with host networking
   180  func TestSysctlOverrideHost(t *testing.T) {
   181  	skip.If(t, os.Getuid() != 0, "skipping test that requires root")
   182  	c := &container.Container{
   183  		Config: &containertypes.Config{},
   184  		HostConfig: &containertypes.HostConfig{
   185  			NetworkMode: "host",
   186  			Sysctls:     map[string]string{},
   187  		},
   188  	}
   189  	d := setupFakeDaemon(t, c)
   190  
   191  	// Ensure that the implicit sysctl is not set
   192  	s, err := d.createSpec(context.TODO(), &configStore{}, c, nil)
   193  	assert.NilError(t, err)
   194  	assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], "")
   195  	assert.Equal(t, s.Linux.Sysctl["net.ipv4.ping_group_range"], "")
   196  
   197  	// Set an explicit sysctl.
   198  	c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"] = "1024"
   199  
   200  	s, err = d.createSpec(context.TODO(), &configStore{}, c, nil)
   201  	assert.NilError(t, err)
   202  	assert.Equal(t, s.Linux.Sysctl["net.ipv4.ip_unprivileged_port_start"], c.HostConfig.Sysctls["net.ipv4.ip_unprivileged_port_start"])
   203  }
   204  
   205  func TestGetSourceMount(t *testing.T) {
   206  	// must be able to find source mount for /
   207  	mnt, _, err := getSourceMount("/")
   208  	assert.NilError(t, err)
   209  	assert.Equal(t, mnt, "/")
   210  
   211  	// must be able to find source mount for current directory
   212  	cwd, err := os.Getwd()
   213  	assert.NilError(t, err)
   214  	_, _, err = getSourceMount(cwd)
   215  	assert.NilError(t, err)
   216  }
   217  
   218  func TestDefaultResources(t *testing.T) {
   219  	skip.If(t, os.Getuid() != 0, "skipping test that requires root") // TODO: is this actually true? I'm guilty of following the cargo cult here.
   220  
   221  	c := &container.Container{
   222  		HostConfig: &containertypes.HostConfig{
   223  			IpcMode: containertypes.IPCModeNone,
   224  		},
   225  	}
   226  	d := setupFakeDaemon(t, c)
   227  
   228  	s, err := d.createSpec(context.Background(), &configStore{}, c, nil)
   229  	assert.NilError(t, err)
   230  	checkResourcesAreUnset(t, s.Linux.Resources)
   231  }
   232  
   233  func checkResourcesAreUnset(t *testing.T, r *specs.LinuxResources) {
   234  	t.Helper()
   235  
   236  	if r != nil {
   237  		if r.Memory != nil {
   238  			assert.Check(t, is.DeepEqual(r.Memory, &specs.LinuxMemory{}))
   239  		}
   240  		if r.CPU != nil {
   241  			assert.Check(t, is.DeepEqual(r.CPU, &specs.LinuxCPU{}))
   242  		}
   243  		assert.Check(t, is.Nil(r.Pids))
   244  		if r.BlockIO != nil {
   245  			assert.Check(t, is.DeepEqual(r.BlockIO, &specs.LinuxBlockIO{}, cmpopts.EquateEmpty()))
   246  		}
   247  		if r.Network != nil {
   248  			assert.Check(t, is.DeepEqual(r.Network, &specs.LinuxNetwork{}, cmpopts.EquateEmpty()))
   249  		}
   250  	}
   251  }