diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 9799f220c7..0082706b6c 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -64,6 +64,10 @@ const ( cgroupSystemdDriver = "systemd" ) +type containerGetter interface { + GetContainer(string) (*container.Container, error) +} + func getMemoryResources(config containertypes.Resources) *specs.LinuxMemory { memory := specs.LinuxMemory{} @@ -281,6 +285,8 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf hostConfig.IpcMode = containertypes.IpcMode(m) } + adaptSharedNamespaceContainer(daemon, hostConfig) + var err error opts, err := daemon.generateSecurityOpt(hostConfig) if err != nil { @@ -295,6 +301,36 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf return nil } +// adaptSharedNamespaceContainer replaces container name with its ID in hostConfig. +// To be more precisely, it modifies `container:name` to `container:ID` of PidMode, IpcMode +// and NetworkMode. +// +// When a container shares its namespace with another container, use ID can keep the namespace +// sharing connection between the two containers even the another container is renamed. +func adaptSharedNamespaceContainer(daemon containerGetter, hostConfig *containertypes.HostConfig) { + containerPrefix := "container:" + if hostConfig.PidMode.IsContainer() { + pidContainer := hostConfig.PidMode.Container() + // if there is any error returned here, we just ignore it and leave it to be + // handled in the following logic + if c, err := daemon.GetContainer(pidContainer); err == nil { + hostConfig.PidMode = containertypes.PidMode(containerPrefix + c.ID) + } + } + if hostConfig.IpcMode.IsContainer() { + ipcContainer := hostConfig.IpcMode.Container() + if c, err := daemon.GetContainer(ipcContainer); err == nil { + hostConfig.IpcMode = containertypes.IpcMode(containerPrefix + c.ID) + } + } + if hostConfig.NetworkMode.IsContainer() { + netContainer := hostConfig.NetworkMode.ConnectedContainer() + if c, err := daemon.GetContainer(netContainer); err == nil { + hostConfig.NetworkMode = containertypes.NetworkMode(containerPrefix + c.ID) + } + } +} + func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo, update bool) ([]string, error) { warnings := []string{} fixMemorySwappiness(resources) diff --git a/daemon/daemon_unix_test.go b/daemon/daemon_unix_test.go index c3aa443e45..f3a7ce4ae8 100644 --- a/daemon/daemon_unix_test.go +++ b/daemon/daemon_unix_test.go @@ -3,6 +3,7 @@ package daemon import ( + "errors" "io/ioutil" "os" "path/filepath" @@ -18,6 +19,44 @@ import ( "github.com/docker/docker/volume/store" ) +type fakeContainerGetter struct { + containers map[string]*container.Container +} + +func (f *fakeContainerGetter) GetContainer(cid string) (*container.Container, error) { + container, ok := f.containers[cid] + if !ok { + return nil, errors.New("container not found") + } + return container, nil +} + +// Unix test as uses settings which are not available on Windows +func TestAdjustSharedNamespaceContainerName(t *testing.T) { + fakeID := "abcdef1234567890" + hostConfig := &containertypes.HostConfig{ + IpcMode: containertypes.IpcMode("container:base"), + PidMode: containertypes.PidMode("container:base"), + NetworkMode: containertypes.NetworkMode("container:base"), + } + containerStore := &fakeContainerGetter{} + containerStore.containers = make(map[string]*container.Container) + containerStore.containers["base"] = &container.Container{ + ID: fakeID, + } + + adaptSharedNamespaceContainer(containerStore, hostConfig) + if hostConfig.IpcMode != containertypes.IpcMode("container:"+fakeID) { + t.Errorf("Expected IpcMode to be container:%s", fakeID) + } + if hostConfig.PidMode != containertypes.PidMode("container:"+fakeID) { + t.Errorf("Expected PidMode to be container:%s", fakeID) + } + if hostConfig.NetworkMode != containertypes.NetworkMode("container:"+fakeID) { + t.Errorf("Expected NetworkMode to be container:%s", fakeID) + } +} + // Unix test as uses settings which are not available on Windows func TestAdjustCPUShares(t *testing.T) { tmp, err := ioutil.TempDir("", "docker-daemon-unix-test-")