|
@@ -1,29 +1,67 @@
|
|
|
package daemon // import "github.com/docker/docker/daemon"
|
|
|
|
|
|
import (
|
|
|
+ "io/ioutil"
|
|
|
"os"
|
|
|
+ "path/filepath"
|
|
|
"testing"
|
|
|
|
|
|
containertypes "github.com/docker/docker/api/types/container"
|
|
|
"github.com/docker/docker/container"
|
|
|
"github.com/docker/docker/daemon/config"
|
|
|
- "github.com/docker/docker/oci"
|
|
|
+ "github.com/docker/docker/daemon/network"
|
|
|
+ "github.com/docker/docker/pkg/containerfs"
|
|
|
"github.com/docker/docker/pkg/idtools"
|
|
|
+ "github.com/docker/libnetwork"
|
|
|
"gotest.tools/assert"
|
|
|
is "gotest.tools/assert/cmp"
|
|
|
)
|
|
|
|
|
|
+func setupFakeDaemon(t *testing.T, c *container.Container) *Daemon {
|
|
|
+ root, err := ioutil.TempDir("", "oci_linux_test-root")
|
|
|
+ assert.NilError(t, err)
|
|
|
+
|
|
|
+ rootfs := filepath.Join(root, "rootfs")
|
|
|
+ err = os.MkdirAll(rootfs, 0755)
|
|
|
+ assert.NilError(t, err)
|
|
|
+
|
|
|
+ netController, err := libnetwork.New()
|
|
|
+ assert.NilError(t, err)
|
|
|
+
|
|
|
+ d := &Daemon{
|
|
|
+ // some empty structs to avoid getting a panic
|
|
|
+ // caused by a null pointer dereference
|
|
|
+ idMapping: &idtools.IdentityMapping{},
|
|
|
+ configStore: &config.Config{},
|
|
|
+ linkIndex: newLinkIndex(),
|
|
|
+ netController: netController,
|
|
|
+ }
|
|
|
+
|
|
|
+ c.Root = root
|
|
|
+ c.BaseFS = containerfs.NewLocalContainerFS(rootfs)
|
|
|
+
|
|
|
+ if c.Config == nil {
|
|
|
+ c.Config = new(containertypes.Config)
|
|
|
+ }
|
|
|
+ if c.HostConfig == nil {
|
|
|
+ c.HostConfig = new(containertypes.HostConfig)
|
|
|
+ }
|
|
|
+ if c.NetworkSettings == nil {
|
|
|
+ c.NetworkSettings = &network.Settings{Networks: make(map[string]*network.EndpointSettings)}
|
|
|
+ }
|
|
|
+
|
|
|
+ return d
|
|
|
+}
|
|
|
+
|
|
|
+func cleanupFakeContainer(c *container.Container) {
|
|
|
+ os.RemoveAll(c.Root)
|
|
|
+}
|
|
|
+
|
|
|
// TestTmpfsDevShmNoDupMount checks that a user-specified /dev/shm tmpfs
|
|
|
// mount (as in "docker run --tmpfs /dev/shm:rw,size=NNN") does not result
|
|
|
// in "Duplicate mount point" error from the engine.
|
|
|
// https://github.com/moby/moby/issues/35455
|
|
|
func TestTmpfsDevShmNoDupMount(t *testing.T) {
|
|
|
- d := Daemon{
|
|
|
- // some empty structs to avoid getting a panic
|
|
|
- // caused by a null pointer dereference
|
|
|
- idMapping: &idtools.IdentityMapping{},
|
|
|
- configStore: &config.Config{},
|
|
|
- }
|
|
|
c := &container.Container{
|
|
|
ShmPath: "foobar", // non-empty, for c.IpcMounts() to work
|
|
|
HostConfig: &containertypes.HostConfig{
|
|
@@ -34,19 +72,10 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
|
|
|
},
|
|
|
},
|
|
|
}
|
|
|
+ d := setupFakeDaemon(t, c)
|
|
|
+ defer cleanupFakeContainer(c)
|
|
|
|
|
|
- // Mimic the code flow of daemon.createSpec(), enough to reproduce the issue
|
|
|
- ms, err := d.setupMounts(c)
|
|
|
- assert.Check(t, err)
|
|
|
-
|
|
|
- ms = append(ms, c.IpcMounts()...)
|
|
|
-
|
|
|
- tmpfsMounts, err := c.TmpfsMounts()
|
|
|
- assert.Check(t, err)
|
|
|
- ms = append(ms, tmpfsMounts...)
|
|
|
-
|
|
|
- s := oci.DefaultSpec()
|
|
|
- err = setMounts(&d, &s, c, ms)
|
|
|
+ _, err := d.createSpec(c)
|
|
|
assert.Check(t, err)
|
|
|
}
|
|
|
|
|
@@ -55,28 +84,16 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) {
|
|
|
// the resulting /dev/shm mount is NOT made read-only.
|
|
|
// https://github.com/moby/moby/issues/36503
|
|
|
func TestIpcPrivateVsReadonly(t *testing.T) {
|
|
|
- d := Daemon{
|
|
|
- // some empty structs to avoid getting a panic
|
|
|
- // caused by a null pointer dereference
|
|
|
- idMapping: &idtools.IdentityMapping{},
|
|
|
- configStore: &config.Config{},
|
|
|
- }
|
|
|
c := &container.Container{
|
|
|
HostConfig: &containertypes.HostConfig{
|
|
|
IpcMode: containertypes.IpcMode("private"),
|
|
|
ReadonlyRootfs: true,
|
|
|
},
|
|
|
}
|
|
|
+ d := setupFakeDaemon(t, c)
|
|
|
+ defer cleanupFakeContainer(c)
|
|
|
|
|
|
- // We can't call createSpec() so mimick the minimal part
|
|
|
- // of its code flow, just enough to reproduce the issue.
|
|
|
- ms, err := d.setupMounts(c)
|
|
|
- assert.Check(t, err)
|
|
|
-
|
|
|
- s := oci.DefaultSpec()
|
|
|
- s.Root.Readonly = c.HostConfig.ReadonlyRootfs
|
|
|
-
|
|
|
- err = setMounts(&d, &s, c, ms)
|
|
|
+ s, err := d.createSpec(c)
|
|
|
assert.Check(t, err)
|
|
|
|
|
|
// Find the /dev/shm mount in ms, check it does not have ro
|
|
@@ -88,6 +105,37 @@ func TestIpcPrivateVsReadonly(t *testing.T) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// TestSysctlOverride ensures that any implicit sysctls (such as
|
|
|
+// Config.Domainname) are overridden by an explicit sysctl in the HostConfig.
|
|
|
+func TestSysctlOverride(t *testing.T) {
|
|
|
+ c := &container.Container{
|
|
|
+ Config: &containertypes.Config{
|
|
|
+ Hostname: "foobar",
|
|
|
+ Domainname: "baz.cyphar.com",
|
|
|
+ },
|
|
|
+ HostConfig: &containertypes.HostConfig{
|
|
|
+ Sysctls: map[string]string{},
|
|
|
+ },
|
|
|
+ }
|
|
|
+ d := setupFakeDaemon(t, c)
|
|
|
+ defer cleanupFakeContainer(c)
|
|
|
+
|
|
|
+ // Ensure that the implicit sysctl is set correctly.
|
|
|
+ s, err := d.createSpec(c)
|
|
|
+ assert.NilError(t, err)
|
|
|
+ assert.Equal(t, s.Hostname, "foobar")
|
|
|
+ assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.Config.Domainname)
|
|
|
+
|
|
|
+ // Set an explicit sysctl.
|
|
|
+ c.HostConfig.Sysctls["kernel.domainname"] = "foobar.net"
|
|
|
+ assert.Assert(t, c.HostConfig.Sysctls["kernel.domainname"] != c.Config.Domainname)
|
|
|
+
|
|
|
+ s, err = d.createSpec(c)
|
|
|
+ assert.NilError(t, err)
|
|
|
+ assert.Equal(t, s.Hostname, "foobar")
|
|
|
+ assert.Equal(t, s.Linux.Sysctl["kernel.domainname"], c.HostConfig.Sysctls["kernel.domainname"])
|
|
|
+}
|
|
|
+
|
|
|
func TestGetSourceMount(t *testing.T) {
|
|
|
// must be able to find source mount for /
|
|
|
mnt, _, err := getSourceMount("/")
|