diff --git a/api/server/router/container/container_routes.go b/api/server/router/container/container_routes.go index e0e6d5714b..c3074aa3a0 100644 --- a/api/server/router/container/container_routes.go +++ b/api/server/router/container/container_routes.go @@ -491,13 +491,13 @@ func (s *containerRouter) postContainersCreate(ctx context.Context, w http.Respo // Older clients (API < 1.40) expects the default to be shareable, make them happy if hostConfig.IpcMode.IsEmpty() { - hostConfig.IpcMode = container.IpcMode("shareable") + hostConfig.IpcMode = container.IPCModeShareable } } if hostConfig != nil && versions.LessThan(version, "1.41") && !s.cgroup2 { // Older clients expect the default to be "host" on cgroup v1 hosts if hostConfig.CgroupnsMode.IsEmpty() { - hostConfig.CgroupnsMode = container.CgroupnsMode("host") + hostConfig.CgroupnsMode = container.CgroupnsModeHost } } diff --git a/api/types/container/host_config.go b/api/types/container/host_config.go index 2d1cbaa9ab..dcea6c8a5a 100644 --- a/api/types/container/host_config.go +++ b/api/types/container/host_config.go @@ -13,19 +13,26 @@ import ( // CgroupnsMode represents the cgroup namespace mode of the container type CgroupnsMode string +// cgroup namespace modes for containers +const ( + CgroupnsModeEmpty CgroupnsMode = "" + CgroupnsModePrivate CgroupnsMode = "private" + CgroupnsModeHost CgroupnsMode = "host" +) + // IsPrivate indicates whether the container uses its own private cgroup namespace func (c CgroupnsMode) IsPrivate() bool { - return c == "private" + return c == CgroupnsModePrivate } // IsHost indicates whether the container shares the host's cgroup namespace func (c CgroupnsMode) IsHost() bool { - return c == "host" + return c == CgroupnsModeHost } // IsEmpty indicates whether the container cgroup namespace mode is unset func (c CgroupnsMode) IsEmpty() bool { - return c == "" + return c == CgroupnsModeEmpty } // Valid indicates whether the cgroup namespace mode is valid @@ -37,60 +44,69 @@ func (c CgroupnsMode) Valid() bool { // values are platform specific type Isolation string +// Isolation modes for containers +const ( + IsolationEmpty Isolation = "" // IsolationEmpty is unspecified (same behavior as default) + IsolationDefault Isolation = "default" // IsolationDefault is the default isolation mode on current daemon + IsolationProcess Isolation = "process" // IsolationProcess is process isolation mode + IsolationHyperV Isolation = "hyperv" // IsolationHyperV is HyperV isolation mode +) + // IsDefault indicates the default isolation technology of a container. On Linux this // is the native driver. On Windows, this is a Windows Server Container. func (i Isolation) IsDefault() bool { - return strings.ToLower(string(i)) == "default" || string(i) == "" + // TODO consider making isolation-mode strict (case-sensitive) + v := Isolation(strings.ToLower(string(i))) + return v == IsolationDefault || v == IsolationEmpty } // IsHyperV indicates the use of a Hyper-V partition for isolation func (i Isolation) IsHyperV() bool { - return strings.ToLower(string(i)) == "hyperv" + // TODO consider making isolation-mode strict (case-sensitive) + return Isolation(strings.ToLower(string(i))) == IsolationHyperV } // IsProcess indicates the use of process isolation func (i Isolation) IsProcess() bool { - return strings.ToLower(string(i)) == "process" + // TODO consider making isolation-mode strict (case-sensitive) + return Isolation(strings.ToLower(string(i))) == IsolationProcess } -const ( - // IsolationEmpty is unspecified (same behavior as default) - IsolationEmpty = Isolation("") - // IsolationDefault is the default isolation mode on current daemon - IsolationDefault = Isolation("default") - // IsolationProcess is process isolation mode - IsolationProcess = Isolation("process") - // IsolationHyperV is HyperV isolation mode - IsolationHyperV = Isolation("hyperv") -) - // IpcMode represents the container ipc stack. type IpcMode string +// IpcMode constants +const ( + IPCModeNone IpcMode = "none" + IPCModeHost IpcMode = "host" + IPCModeContainer IpcMode = "container" + IPCModePrivate IpcMode = "private" + IPCModeShareable IpcMode = "shareable" +) + // IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared. func (n IpcMode) IsPrivate() bool { - return n == "private" + return n == IPCModePrivate } // IsHost indicates whether the container shares the host's ipc namespace. func (n IpcMode) IsHost() bool { - return n == "host" + return n == IPCModeHost } // IsShareable indicates whether the container's ipc namespace can be shared with another container. func (n IpcMode) IsShareable() bool { - return n == "shareable" + return n == IPCModeShareable } // IsContainer indicates whether the container uses another container's ipc namespace. func (n IpcMode) IsContainer() bool { - parts := strings.SplitN(string(n), ":", 2) - return len(parts) > 1 && parts[0] == "container" + return strings.HasPrefix(string(n), string(IPCModeContainer)+":") } // IsNone indicates whether container IpcMode is set to "none". func (n IpcMode) IsNone() bool { - return n == "none" + return n == IPCModeNone } // IsEmpty indicates whether container IpcMode is empty @@ -105,9 +121,8 @@ func (n IpcMode) Valid() bool { // Container returns the name of the container ipc stack is going to be used. func (n IpcMode) Container() string { - parts := strings.SplitN(string(n), ":", 2) - if len(parts) > 1 && parts[0] == "container" { - return parts[1] + if n.IsContainer() { + return strings.TrimPrefix(string(n), string(IPCModeContainer)+":") } return "" } @@ -326,7 +341,7 @@ type LogMode string // Available logging modes const ( - LogModeUnset = "" + LogModeUnset LogMode = "" LogModeBlocking LogMode = "blocking" LogModeNonBlock LogMode = "non-blocking" ) diff --git a/cmd/dockerd/config_unix.go b/cmd/dockerd/config_unix.go index 8d0e8b8d46..354d5da196 100644 --- a/cmd/dockerd/config_unix.go +++ b/cmd/dockerd/config_unix.go @@ -62,15 +62,15 @@ func installConfigFlags(conf *config.Config, flags *pflag.FlagSet) error { flags.StringVar(&conf.SeccompProfile, "seccomp-profile", config.SeccompProfileDefault, `Path to seccomp profile. Use "unconfined" to disable the default seccomp profile`) flags.Var(&conf.ShmSize, "default-shm-size", "Default shm size for containers") flags.BoolVar(&conf.NoNewPrivileges, "no-new-privileges", false, "Set no-new-privileges by default for new containers") - flags.StringVar(&conf.IpcMode, "default-ipc-mode", config.DefaultIpcMode, `Default mode for containers ipc ("shareable" | "private")`) + flags.StringVar(&conf.IpcMode, "default-ipc-mode", string(config.DefaultIpcMode), `Default mode for containers ipc ("shareable" | "private")`) flags.Var(&conf.NetworkConfig.DefaultAddressPools, "default-address-pool", "Default address pools for node specific local networks") // rootless needs to be explicitly specified for running "rootful" dockerd in rootless dockerd (#38702) // Note that defaultUserlandProxyPath and honorXDG are configured according to the value of rootless.RunningWithRootlessKit, not the value of --rootless. flags.BoolVar(&conf.Rootless, "rootless", rootless.RunningWithRootlessKit(), "Enable rootless mode; typically used with RootlessKit") - defaultCgroupNamespaceMode := "host" - if cgroups.Mode() == cgroups.Unified { - defaultCgroupNamespaceMode = "private" + defaultCgroupNamespaceMode := config.DefaultCgroupNamespaceMode + if cgroups.Mode() != cgroups.Unified { + defaultCgroupNamespaceMode = config.DefaultCgroupV1NamespaceMode } - flags.StringVar(&conf.CgroupNamespaceMode, "default-cgroupns-mode", defaultCgroupNamespaceMode, `Default mode for containers cgroup namespace ("host" | "private")`) + flags.StringVar(&conf.CgroupNamespaceMode, "default-cgroupns-mode", string(defaultCgroupNamespaceMode), `Default mode for containers cgroup namespace ("host" | "private")`) return nil } diff --git a/daemon/config/config_linux.go b/daemon/config/config_linux.go index fde8cc57d3..46acf0a849 100644 --- a/daemon/config/config_linux.go +++ b/daemon/config/config_linux.go @@ -12,7 +12,13 @@ import ( const ( // DefaultIpcMode is default for container's IpcMode, if not set otherwise - DefaultIpcMode = "private" + DefaultIpcMode = containertypes.IPCModePrivate + + // DefaultCgroupNamespaceMode is the default mode for containers cgroup namespace when using cgroups v2. + DefaultCgroupNamespaceMode = containertypes.CgroupnsModePrivate + + // DefaultCgroupV1NamespaceMode is the default mode for containers cgroup namespace when using cgroups v1. + DefaultCgroupV1NamespaceMode = containertypes.CgroupnsModeHost ) // BridgeConfig stores all the bridge driver specific diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index 2dcd80e260..526b6d6eca 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -347,9 +347,9 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf if hostConfig.IpcMode.IsEmpty() { m := config.DefaultIpcMode if daemon.configStore != nil { - m = daemon.configStore.IpcMode + m = containertypes.IpcMode(daemon.configStore.IpcMode) } - hostConfig.IpcMode = containertypes.IpcMode(m) + hostConfig.IpcMode = m } // Set default cgroup namespace mode, if unset for container @@ -357,16 +357,16 @@ func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConf // for cgroup v2: unshare cgroupns even for privileged containers // https://github.com/containers/libpod/pull/4374#issuecomment-549776387 if hostConfig.Privileged && cgroups.Mode() != cgroups.Unified { - hostConfig.CgroupnsMode = containertypes.CgroupnsMode("host") + hostConfig.CgroupnsMode = containertypes.CgroupnsModeHost } else { - m := "host" + m := containertypes.CgroupnsModeHost if cgroups.Mode() == cgroups.Unified { - m = "private" + m = containertypes.CgroupnsModePrivate } if daemon.configStore != nil { - m = daemon.configStore.CgroupNamespaceMode + m = containertypes.CgroupnsMode(daemon.configStore.CgroupNamespaceMode) } - hostConfig.CgroupnsMode = containertypes.CgroupnsMode(m) + hostConfig.CgroupnsMode = m } } diff --git a/daemon/logger/loggerutils/cache/local_cache.go b/daemon/logger/loggerutils/cache/local_cache.go index 1ca19eb5db..c5e8fc2cac 100644 --- a/daemon/logger/loggerutils/cache/local_cache.go +++ b/daemon/logger/loggerutils/cache/local_cache.go @@ -36,7 +36,7 @@ func WithLocalCache(l logger.Logger, info logger.Info) (logger.Logger, error) { return nil, errors.Wrap(err, "error initializing local log cache driver") } - if info.Config["mode"] == container.LogModeUnset || container.LogMode(info.Config["mode"]) == container.LogModeNonBlock { + if container.LogMode(info.Config["mode"]) == container.LogModeUnset || container.LogMode(info.Config["mode"]) == container.LogModeNonBlock { var size int64 = -1 if s, exists := info.Config["max-buffer-size"]; exists { size, err = units.RAMInBytes(s) diff --git a/daemon/oci_linux_test.go b/daemon/oci_linux_test.go index 927cd90dc2..8e0d7c77a7 100644 --- a/daemon/oci_linux_test.go +++ b/daemon/oci_linux_test.go @@ -66,7 +66,7 @@ func TestTmpfsDevShmNoDupMount(t *testing.T) { c := &container.Container{ ShmPath: "foobar", // non-empty, for c.IpcMounts() to work HostConfig: &containertypes.HostConfig{ - IpcMode: containertypes.IpcMode("shareable"), // default mode + IpcMode: containertypes.IPCModeShareable, // default mode // --tmpfs /dev/shm:rw,exec,size=NNN Tmpfs: map[string]string{ "/dev/shm": "rw,exec,size=1g", @@ -88,7 +88,7 @@ func TestIpcPrivateVsReadonly(t *testing.T) { skip.If(t, os.Getuid() != 0, "skipping test that requires root") c := &container.Container{ HostConfig: &containertypes.HostConfig{ - IpcMode: containertypes.IpcMode("private"), + IpcMode: containertypes.IPCModePrivate, ReadonlyRootfs: true, }, } diff --git a/integration/container/ipcmode_linux_test.go b/integration/container/ipcmode_linux_test.go index 030ec90179..86b60e5f5b 100644 --- a/integration/container/ipcmode_linux_test.go +++ b/integration/container/ipcmode_linux_test.go @@ -198,7 +198,7 @@ func TestAPIIpcModeHost(t *testing.T) { Cmd: []string{"top"}, } hostCfg := containertypes.HostConfig{ - IpcMode: containertypes.IpcMode("host"), + IpcMode: containertypes.IPCModeHost, } ctx := context.Background()