summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel J Walsh <dwalsh@redhat.com>2018-09-01 12:51:00 -0400
committerAtomic Bot <atomic-devel@projectatomic.io>2018-09-07 18:18:54 +0000
commit87f90ce14abf36fbf85f6128b3024ea89a44d670 (patch)
tree7090c0a491c2f4199f8172e1d30b525fa938ed86
parentccc4a339cd124abc668b7542a9eb838cd7d1b214 (diff)
downloadpodman-87f90ce14abf36fbf85f6128b3024ea89a44d670.tar.gz
podman-87f90ce14abf36fbf85f6128b3024ea89a44d670.tar.bz2
podman-87f90ce14abf36fbf85f6128b3024ea89a44d670.zip
Fix pod sharing for utsmode
We should be sharing cgroups namespace by default in pods uts namespace sharing was broken in pods. Create a new libpod/pkg/namespaces for handling of namespace fields in containers Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #1418 Approved by: mheon
-rw-r--r--cmd/podman/create.go12
-rw-r--r--cmd/podman/parse.go138
-rw-r--r--cmd/podman/pod_create.go2
-rw-r--r--cmd/podman/shared/pod.go2
-rw-r--r--pkg/namespaces/namespaces.go219
-rw-r--r--pkg/spec/createconfig.go56
-rw-r--r--pkg/varlinkapi/containers_create.go12
-rw-r--r--test/e2e/rootless_test.go3
8 files changed, 269 insertions, 175 deletions
diff --git a/cmd/podman/create.go b/cmd/podman/create.go
index 20d976c0b..7a3b26c85 100644
--- a/cmd/podman/create.go
+++ b/cmd/podman/create.go
@@ -16,11 +16,11 @@ import (
ann "github.com/containers/libpod/pkg/annotations"
"github.com/containers/libpod/pkg/apparmor"
"github.com/containers/libpod/pkg/inspect"
+ "github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
libpodVersion "github.com/containers/libpod/version"
- "github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/signal"
"github.com/docker/go-connections/nat"
"github.com/docker/go-units"
@@ -456,7 +456,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if !c.IsSet("pid") && pod != nil && pod.SharesPID() {
pidModeStr = cc.POD
}
- pidMode := container.PidMode(pidModeStr)
+ pidMode := namespaces.PidMode(pidModeStr)
if !cc.Valid(string(pidMode), pidMode) {
return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
}
@@ -465,7 +465,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if !c.IsSet("userns") && pod != nil && pod.SharesUser() {
usernsModeStr = cc.POD
}
- usernsMode := container.UsernsMode(usernsModeStr)
+ usernsMode := namespaces.UsernsMode(usernsModeStr)
if !cc.Valid(string(usernsMode), usernsMode) {
return nil, errors.Errorf("--userns %q is not valid", c.String("userns"))
}
@@ -474,7 +474,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if !c.IsSet("uts") && pod != nil && pod.SharesUTS() {
utsModeStr = cc.POD
}
- utsMode := container.UTSMode(utsModeStr)
+ utsMode := namespaces.UTSMode(utsModeStr)
if !cc.Valid(string(utsMode), utsMode) {
return nil, errors.Errorf("--uts %q is not valid", c.String("uts"))
}
@@ -483,7 +483,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
if !c.IsSet("ipc") && pod != nil && pod.SharesIPC() {
ipcModeStr = cc.POD
}
- ipcMode := container.IpcMode(ipcModeStr)
+ ipcMode := namespaces.IpcMode(ipcModeStr)
if !cc.Valid(string(ipcMode), ipcMode) {
return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
}
@@ -492,7 +492,7 @@ func parseCreateOpts(ctx context.Context, c *cli.Context, runtime *libpod.Runtim
netModeStr = cc.POD
}
// Make sure if network is set to container namespace, port binding is not also being asked for
- netMode := container.NetworkMode(netModeStr)
+ netMode := namespaces.NetworkMode(netModeStr)
if netMode.IsContainer() || cc.IsPod(netModeStr) {
if len(c.StringSlice("publish")) > 0 || c.Bool("publish-all") {
return nil, errors.Errorf("cannot set port bindings on an existing container network namespace")
diff --git a/cmd/podman/parse.go b/cmd/podman/parse.go
index 158a006fb..ade592ddf 100644
--- a/cmd/podman/parse.go
+++ b/cmd/podman/parse.go
@@ -239,50 +239,6 @@ func parseEnvFile(env map[string]string, filename string) error {
return scanner.Err()
}
-// NsIpc represents the container ipc stack.
-// for ipc flag
-type NsIpc string
-
-// IsPrivate indicates whether the container uses its private ipc stack.
-func (n NsIpc) IsPrivate() bool {
- return !(n.IsHost() || n.IsContainer())
-}
-
-// IsHost indicates whether the container uses the host's ipc stack.
-func (n NsIpc) IsHost() bool {
- return n == "host"
-}
-
-// IsContainer indicates whether the container uses a container's ipc stack.
-func (n NsIpc) IsContainer() bool {
- parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
-}
-
-// Valid indicates whether the ipc stack is valid.
-func (n NsIpc) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- case "container":
- if len(parts) != 2 || parts[1] == "" {
- return false
- }
- default:
- return false
- }
- return true
-}
-
-// Container returns the name of the container ipc stack is going to be used.
-func (n NsIpc) Container() string {
- parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
- return parts[1]
- }
- return ""
-}
-
// validateLabel validates that the specified string is a valid label, and returns it.
// Labels are in the form on key=value.
// for label flag
@@ -313,50 +269,6 @@ func parseLoggingOpts(logDriver string, logDriverOpt []string) (map[string]strin
return logOptsMap, nil
}
-// NsPid represents the pid namespace of the container.
-//for pid flag
-type NsPid string
-
-// IsPrivate indicates whether the container uses its own new pid namespace.
-func (n NsPid) IsPrivate() bool {
- return !(n.IsHost() || n.IsContainer())
-}
-
-// IsHost indicates whether the container uses the host's pid namespace.
-func (n NsPid) IsHost() bool {
- return n == "host"
-}
-
-// IsContainer indicates whether the container uses a container's pid namespace.
-func (n NsPid) IsContainer() bool {
- parts := strings.SplitN(string(n), ":", 2)
- return len(parts) > 1 && parts[0] == "container"
-}
-
-// Valid indicates whether the pid namespace is valid.
-func (n NsPid) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- case "container":
- if len(parts) != 2 || parts[1] == "" {
- return false
- }
- default:
- return false
- }
- return true
-}
-
-// Container returns the name of the container whose pid namespace is going to be used.
-func (n NsPid) Container() string {
- parts := strings.SplitN(string(n), ":", 2)
- if len(parts) > 1 {
- return parts[1]
- }
- return ""
-}
-
// parsePortSpecs receives port specs in the format of ip:public:private/proto and parses
// these in to the internal types
// for publish, publish-all, and expose flags
@@ -567,56 +479,6 @@ func convertKVStringsToMap(values []string) map[string]string {
return result
}
-// NsUser represents userns mode in the container.
-// for userns flag
-type NsUser string
-
-// IsHost indicates whether the container uses the host's userns.
-func (n NsUser) IsHost() bool {
- return n == "host"
-}
-
-// IsPrivate indicates whether the container uses the a private userns.
-func (n NsUser) IsPrivate() bool {
- return !(n.IsHost())
-}
-
-// Valid indicates whether the userns is valid.
-func (n NsUser) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- default:
- return false
- }
- return true
-}
-
-// NsUts represents the UTS namespace of the container.
-// for uts flag
-type NsUts string
-
-// IsPrivate indicates whether the container uses its private UTS namespace.
-func (n NsUts) IsPrivate() bool {
- return !(n.IsHost())
-}
-
-// IsHost indicates whether the container uses the host's UTS namespace.
-func (n NsUts) IsHost() bool {
- return n == "host"
-}
-
-// Valid indicates whether the UTS namespace is valid.
-func (n NsUts) Valid() bool {
- parts := strings.Split(string(n), ":")
- switch mode := parts[0]; mode {
- case "", "host":
- default:
- return false
- }
- return true
-}
-
// Takes a stringslice and converts to a uint32slice
func stringSlicetoUint32Slice(inputSlice []string) ([]uint32, error) {
var outputSlice []uint32
diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go
index 488fef869..61086f890 100644
--- a/cmd/podman/pod_create.go
+++ b/cmd/podman/pod_create.go
@@ -15,7 +15,7 @@ import (
var (
// Kernel namespaces shared by default within a pod
- DefaultKernelNamespaces = "ipc,net,uts"
+ DefaultKernelNamespaces = "cgroup,ipc,net,uts"
)
var podCreateDescription = "Creates a new empty pod. The pod ID is then" +
diff --git a/cmd/podman/shared/pod.go b/cmd/podman/shared/pod.go
index 1a14b3777..badc7a837 100644
--- a/cmd/podman/shared/pod.go
+++ b/cmd/podman/shared/pod.go
@@ -70,6 +70,8 @@ func GetNamespaceOptions(ns []string) ([]libpod.PodCreateOption, error) {
var erroredOptions []libpod.PodCreateOption
for _, toShare := range ns {
switch toShare {
+ case "cgroup":
+ options = append(options, libpod.WithPodCgroups())
case "net":
options = append(options, libpod.WithPodNet())
case "mnt":
diff --git a/pkg/namespaces/namespaces.go b/pkg/namespaces/namespaces.go
new file mode 100644
index 000000000..1bdb2b00d
--- /dev/null
+++ b/pkg/namespaces/namespaces.go
@@ -0,0 +1,219 @@
+package namespaces
+
+import (
+ "strings"
+)
+
+// UsernsMode represents userns mode in the container.
+type UsernsMode string
+
+// IsHost indicates whether the container uses the host's userns.
+func (n UsernsMode) IsHost() bool {
+ return n == "host"
+}
+
+// IsPrivate indicates whether the container uses the a private userns.
+func (n UsernsMode) IsPrivate() bool {
+ return !(n.IsHost())
+}
+
+// Valid indicates whether the userns is valid.
+func (n UsernsMode) Valid() bool {
+ parts := strings.Split(string(n), ":")
+ switch mode := parts[0]; mode {
+ case "", "host":
+ default:
+ return false
+ }
+ return true
+}
+
+// UTSMode represents the UTS namespace of the container.
+type UTSMode string
+
+// IsPrivate indicates whether the container uses its private UTS namespace.
+func (n UTSMode) IsPrivate() bool {
+ return !(n.IsHost())
+}
+
+// IsHost indicates whether the container uses the host's UTS namespace.
+func (n UTSMode) IsHost() bool {
+ return n == "host"
+}
+
+// IsContainer indicates whether the container uses a container's UTS namespace.
+func (n UTSMode) IsContainer() bool {
+ parts := strings.SplitN(string(n), ":", 2)
+ return len(parts) > 1 && parts[0] == "container"
+}
+
+// Container returns the name of the container whose uts namespace is going to be used.
+func (n UTSMode) Container() string {
+ parts := strings.SplitN(string(n), ":", 2)
+ if len(parts) > 1 {
+ return parts[1]
+ }
+ return ""
+}
+
+// Valid indicates whether the UTS namespace is valid.
+func (n UTSMode) Valid() bool {
+ parts := strings.Split(string(n), ":")
+ switch mode := parts[0]; mode {
+ case "", "host":
+ case "container":
+ if len(parts) != 2 || parts[1] == "" {
+ return false
+ }
+ default:
+ return false
+ }
+ return true
+}
+
+// IpcMode represents the container ipc stack.
+type IpcMode string
+
+// IsPrivate indicates whether the container uses its own private ipc namespace which can not be shared.
+func (n IpcMode) IsPrivate() bool {
+ return n == "private"
+}
+
+// IsHost indicates whether the container shares the host's ipc namespace.
+func (n IpcMode) IsHost() bool {
+ return n == "host"
+}
+
+// IsShareable indicates whether the container's ipc namespace can be shared with another container.
+func (n IpcMode) IsShareable() bool {
+ return n == "shareable"
+}
+
+// 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"
+}
+
+// IsNone indicates whether container IpcMode is set to "none".
+func (n IpcMode) IsNone() bool {
+ return n == "none"
+}
+
+// IsEmpty indicates whether container IpcMode is empty
+func (n IpcMode) IsEmpty() bool {
+ return n == ""
+}
+
+// Valid indicates whether the ipc mode is valid.
+func (n IpcMode) Valid() bool {
+ return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer()
+}
+
+// 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]
+ }
+ return ""
+}
+
+// PidMode represents the pid namespace of the container.
+type PidMode string
+
+// IsPrivate indicates whether the container uses its own new pid namespace.
+func (n PidMode) IsPrivate() bool {
+ return !(n.IsHost() || n.IsContainer())
+}
+
+// IsHost indicates whether the container uses the host's pid namespace.
+func (n PidMode) IsHost() bool {
+ return n == "host"
+}
+
+// IsContainer indicates whether the container uses a container's pid namespace.
+func (n PidMode) IsContainer() bool {
+ parts := strings.SplitN(string(n), ":", 2)
+ return len(parts) > 1 && parts[0] == "container"
+}
+
+// Valid indicates whether the pid namespace is valid.
+func (n PidMode) Valid() bool {
+ parts := strings.Split(string(n), ":")
+ switch mode := parts[0]; mode {
+ case "", "host":
+ case "container":
+ if len(parts) != 2 || parts[1] == "" {
+ return false
+ }
+ default:
+ return false
+ }
+ return true
+}
+
+// Container returns the name of the container whose pid namespace is going to be used.
+func (n PidMode) Container() string {
+ parts := strings.SplitN(string(n), ":", 2)
+ if len(parts) > 1 {
+ return parts[1]
+ }
+ return ""
+}
+
+// NetworkMode represents the container network stack.
+type NetworkMode string
+
+// IsNone indicates whether container isn't using a network stack.
+func (n NetworkMode) IsNone() bool {
+ return n == "none"
+}
+
+// IsHost indicates whether the container uses the host's network stack.
+func (n NetworkMode) IsHost() bool {
+ return n == "host"
+}
+
+// IsDefault indicates whether container uses the default network stack.
+func (n NetworkMode) IsDefault() bool {
+ return n == "default"
+}
+
+// IsPrivate indicates whether container uses its private network stack.
+func (n NetworkMode) IsPrivate() bool {
+ return !(n.IsHost() || n.IsContainer())
+}
+
+// IsContainer indicates whether container uses a container network stack.
+func (n NetworkMode) IsContainer() bool {
+ parts := strings.SplitN(string(n), ":", 2)
+ return len(parts) > 1 && parts[0] == "container"
+}
+
+// ConnectedContainer is the id of the container which network this container is connected to.
+func (n NetworkMode) ConnectedContainer() string {
+ parts := strings.SplitN(string(n), ":", 2)
+ if len(parts) > 1 {
+ return parts[1]
+ }
+ return ""
+}
+
+//UserDefined indicates user-created network
+func (n NetworkMode) UserDefined() string {
+ if n.IsUserDefined() {
+ return string(n)
+ }
+ return ""
+}
+
+// IsBridge indicates whether container uses the bridge network stack
+func (n NetworkMode) IsBridge() bool {
+ return n == "bridge"
+}
+
+// IsUserDefined indicates user-created network
+func (n NetworkMode) IsUserDefined() bool {
+ return !n.IsDefault() && !n.IsBridge() && !n.IsHost() && !n.IsNone() && !n.IsContainer()
+}
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 0ab0bb9ff..0b7ee993d 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -8,10 +8,10 @@ import (
"syscall"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
"github.com/cri-o/ocicni/pkg/ocicni"
- "github.com/docker/docker/api/types/container"
"github.com/docker/go-connections/nat"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
@@ -90,22 +90,22 @@ type CreateConfig struct {
ImageID string
BuiltinImgVolumes map[string]struct{} // volumes defined in the image config
IDMappings *storage.IDMappingOptions
- ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore
- Interactive bool //interactive
- IpcMode container.IpcMode //ipc
- IP6Address string //ipv6
- IPAddress string //ip
- Labels map[string]string //label
- LinkLocalIP []string // link-local-ip
- LogDriver string // log-driver
- LogDriverOpt []string // log-opt
- MacAddress string //mac-address
- Name string //name
- NetMode container.NetworkMode //net
- Network string //network
- NetworkAlias []string //network-alias
- PidMode container.PidMode //pid
- Pod string //pod
+ ImageVolumeType string // how to handle the image volume, either bind, tmpfs, or ignore
+ Interactive bool //interactive
+ IpcMode namespaces.IpcMode //ipc
+ IP6Address string //ipv6
+ IPAddress string //ip
+ Labels map[string]string //label
+ LinkLocalIP []string // link-local-ip
+ LogDriver string // log-driver
+ LogDriverOpt []string // log-opt
+ MacAddress string //mac-address
+ Name string //name
+ NetMode namespaces.NetworkMode //net
+ Network string //network
+ NetworkAlias []string //network-alias
+ PidMode namespaces.PidMode //pid
+ Pod string //pod
PortBindings nat.PortMap
Privileged bool //privileged
Publish []string //publish
@@ -119,12 +119,12 @@ type CreateConfig struct {
StopTimeout uint // stop-timeout
Sysctl map[string]string //sysctl
Systemd bool
- Tmpfs []string // tmpfs
- Tty bool //tty
- UsernsMode container.UsernsMode //userns
- User string //user
- UtsMode container.UTSMode //uts
- Volumes []string //volume
+ Tmpfs []string // tmpfs
+ Tty bool //tty
+ UsernsMode namespaces.UsernsMode //userns
+ User string //user
+ UtsMode namespaces.UTSMode //uts
+ Volumes []string //volume
VolumesFrom []string
WorkDir string //workdir
MountLabel string //SecurityOpts
@@ -222,7 +222,7 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
}
// GetVolumesFrom reads the create-config artifact of the container to get volumes from
-// and adds it to c.Volumes of the curent container.
+// and adds it to c.Volumes of the current container.
func (c *CreateConfig) GetVolumesFrom() error {
var options string
for _, vol := range c.VolumesFrom {
@@ -423,6 +423,14 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime) ([]lib
if IsPod(string(c.UtsMode)) {
options = append(options, libpod.WithUTSNSFromPod(pod))
}
+ if c.UtsMode.IsContainer() {
+ connectedCtr, err := c.Runtime.LookupContainer(c.UtsMode.Container())
+ if err != nil {
+ return nil, errors.Wrapf(err, "container %q not found", c.UtsMode.Container())
+ }
+
+ options = append(options, libpod.WithUTSNSFrom(connectedCtr))
+ }
// TODO: MNT, USER, CGROUP
options = append(options, libpod.WithStopSignal(c.StopSignal))
diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go
index e57f51cc1..843d7a5ba 100644
--- a/pkg/varlinkapi/containers_create.go
+++ b/pkg/varlinkapi/containers_create.go
@@ -12,9 +12,9 @@ import (
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/inspect"
+ "github.com/containers/libpod/pkg/namespaces"
cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
- "github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/signal"
"github.com/sirupsen/logrus"
)
@@ -164,10 +164,10 @@ func varlinkCreateToCreateConfig(ctx context.Context, create iopodman.Create, ru
LogDriverOpt: create.Log_driver_opt,
Name: create.Name,
Network: networkMode,
- IpcMode: container.IpcMode(create.Ipc_mode),
- NetMode: container.NetworkMode(networkMode),
- UtsMode: container.UTSMode(create.Uts_mode),
- PidMode: container.PidMode(create.Pid_mode),
+ IpcMode: namespaces.IpcMode(create.Ipc_mode),
+ NetMode: namespaces.NetworkMode(networkMode),
+ UtsMode: namespaces.UTSMode(create.Uts_mode),
+ PidMode: namespaces.PidMode(create.Pid_mode),
Pod: create.Pod,
Privileged: create.Privileged,
Publish: create.Publish,
@@ -209,7 +209,7 @@ func varlinkCreateToCreateConfig(ctx context.Context, create iopodman.Create, ru
Tmpfs: create.Tmpfs,
Tty: create.Tty,
User: user,
- UsernsMode: container.UsernsMode(create.Userns_mode),
+ UsernsMode: namespaces.UsernsMode(create.Userns_mode),
Volumes: create.Volumes,
WorkDir: workDir,
}
diff --git a/test/e2e/rootless_test.go b/test/e2e/rootless_test.go
index 84d5cd6f1..72ca37d6e 100644
--- a/test/e2e/rootless_test.go
+++ b/test/e2e/rootless_test.go
@@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
"syscall"
. "github.com/onsi/ginkgo"
@@ -153,6 +154,8 @@ var _ = Describe("Podman rootless", func() {
runRootlessHelper := func(args []string) {
f := func(rootlessTest PodmanTest, xdgRuntimeDir string, home string, mountPath string) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
env := os.Environ()
env = append(env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", xdgRuntimeDir))
env = append(env, fmt.Sprintf("HOME=%s", home))