From b7e458aaf9bf262f94c827c64a8b80fe035e2488 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 6 May 2016 22:55:41 -0700 Subject: [PATCH 1/3] generate: Add replaceOrAppendNamespace to avoid clobbering template If the template already has namespaces in it, we don't want to blow them away in setupNamespaces. For example: $ echo '{"linux": {"namespaces": [{"type": "pid"}]}}' >config-template.json $ ocitools generate --template config-template.json --network=abc $ jq .linux.namespaces config.json [ { "type": "pid" }, { "type": "network", "path": "abc" } ] $ ocitools generate --template config-template.json $ jq .linux.namespaces config.json [ { "type": "pid" } ] Signed-off-by: W. Trevor King --- generate.go | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/generate.go b/generate.go index 3b6c740ad..d16f65a70 100644 --- a/generate.go +++ b/generate.go @@ -661,16 +661,28 @@ func mapStrToNamespace(ns string, path string) rspec.Namespace { func setupNamespaces(spec *rspec.Spec, context *cli.Context) { namespaces := []string{"network", "pid", "mount", "ipc", "uts"} - var linuxNs []rspec.Namespace for _, nsName := range namespaces { + if !context.IsSet(nsName) { + continue + } nsPath := context.String(nsName) if nsPath == "host" { continue } ns := mapStrToNamespace(nsName, nsPath) - linuxNs = append(linuxNs, ns) + replaceOrAppendNamespace(&spec.Linux.Namespaces, ns) + } +} + +func replaceOrAppendNamespace(namespaces *[]rspec.Namespace, namespace rspec.Namespace) { + for i, ns := range *namespaces { + if ns.Type == namespace.Type { + (*namespaces)[i] = namespace + return + } } - spec.Linux.Namespaces = linuxNs + new := append(*namespaces, namespace) + *namespaces = new } func sPtr(s string) *string { return &s } From 6c52ea0c72a63d2efe116f5786eda913884066aa Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 6 May 2016 22:29:01 -0700 Subject: [PATCH 2/3] generate: Don't add namespaces by default And actively remove them if the PATH is the keyword "host". This helps with --template, because it's harder to get clean template round-trips if you have to opt-out of the namespace additions. The default template includes the non-user namespaces, so this commit doesn't effect the bare 'ocitools generate' output. Also document the PATH argument in ocitools-generate(1). I couldn't find a way to support '--network', etc. in codegangsta/cli, so the: --network=[PATH] and such are intentional. I would have preferred --network[=PATH], but using --network= instead of --network for "create a new network namespace" isn't that bad. Signed-off-by: W. Trevor King --- generate.go | 11 +++++++++++ man/ocitools-generate.1.md | 30 ++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/generate.go b/generate.go index d16f65a70..9e8fcc5c0 100644 --- a/generate.go +++ b/generate.go @@ -667,6 +667,8 @@ func setupNamespaces(spec *rspec.Spec, context *cli.Context) { } nsPath := context.String(nsName) if nsPath == "host" { + ns := mapStrToNamespace(nsName, "") + removeNamespace(&spec.Linux.Namespaces, ns.Type) continue } ns := mapStrToNamespace(nsName, nsPath) @@ -685,6 +687,15 @@ func replaceOrAppendNamespace(namespaces *[]rspec.Namespace, namespace rspec.Nam *namespaces = new } +func removeNamespace(namespaces *[]rspec.Namespace, namespaceType rspec.NamespaceType) { + for i, ns := range *namespaces { + if ns.Type == namespaceType { + *namespaces = append((*namespaces)[:i], (*namespaces)[i+1:]...) + return + } + } +} + func sPtr(s string) *string { return &s } func getDefaultTemplate() *rspec.Spec { diff --git a/man/ocitools-generate.1.md b/man/ocitools-generate.1.md index 335774285..42763fdd4 100644 --- a/man/ocitools-generate.1.md +++ b/man/ocitools-generate.1.md @@ -70,11 +70,15 @@ inside of the container. Sets the container host name that is available inside the container. -**--ipc** - Use ipc namespace +**--ipc**=[*PATH*] + Use an IPC namespace. If *PATH* is set, join that namespace. If it + is unset, create a new namespace. The special *PATH* `host` removes + any existing IPC namespace from the configuration. -**--mount** - Use a mount namespace +**--mount**=[*PATH*] + Use a network namespace. If *PATH* is set, join that namespace. If + it is unset, create a new namespace. The special *PATH* `host` + removes any existing mount namespace from the configuration. **--mount-cgroups**=[rw|ro|no] Mount cgroups. The default is `no`. @@ -91,8 +95,10 @@ inside of the container. "system_u:object_r:usr_t:s0" might be a good label for a readonly container, "system_u:system_r:svirt_sandbox_file_t:s0:c1,c2" for a read/write container. -**--network** - Use network namespace +**--network**=[*PATH*] + Use a network namespace. If *PATH* is set, join that namespace. If + it is unset, create a new namespace. The special *PATH* `host` + removes any existing network namespace from the configuration. **--no-new-privileges** Set no new privileges bit for the container process. Setting this flag @@ -103,8 +109,10 @@ inside of the container. **--os**=OS Operating system used within the container -**--pid** - Use a pid namespace +**--pid**=[*PATH*] + Use a PID namespace. If *PATH* is set, join that namespace. If it + is unset, create a new namespace. The special *PATH* `host` removes + any existing UTS namespace from the configuration. **--poststart**=CMD Path to command to run in poststart hooks. This command will be run before @@ -185,8 +193,10 @@ inside of the container. **--uidmappings** Add UIDMappings e.g HostUID:ContainerID:Size for use with User Namespace -**--uts** - Use the uts namespace +**--uts**=[*PATH*] + Use a UTS namespace. If *PATH* is set, join that namespace. If it + is unset, create a new namespace. The special *PATH* `host` removes + any existing UTS namespace from the configuration. # EXAMPLES From 77ed36a79d97960519d22a8b0405adb8469fdce7 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 6 May 2016 23:26:48 -0700 Subject: [PATCH 3/3] generate: Add --user and consolidate user-namespace handling Put this in setupNamespaces with the other namespaces. This commit allows users to: * Join an existing user namespace with --user=path/to/ns. * Create a new user namespace without mapping IDs (although this is likely not very useful). * Clear a templated user namespace with --user=host (although without being able to clear the ID mappings, this may not be very useful). I haven't checked for likely-invalid configuration like: --uidmappings=1000:0:1 --user=path/to/ns We can add that in a follow-up commit if we want. Signed-off-by: W. Trevor King --- generate.go | 14 ++++++++------ man/ocitools-generate.1.md | 9 +++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/generate.go b/generate.go index 9e8fcc5c0..363718763 100644 --- a/generate.go +++ b/generate.go @@ -31,6 +31,7 @@ var generateFlags = []cli.Flag{ cli.StringFlag{Name: "mount", Usage: "mount namespace"}, cli.StringFlag{Name: "pid", Usage: "pid namespace"}, cli.StringFlag{Name: "ipc", Usage: "ipc namespace"}, + cli.StringFlag{Name: "user", Usage: "user namespace"}, cli.StringFlag{Name: "uts", Usage: "uts namespace"}, cli.StringFlag{Name: "selinux-label", Usage: "process selinux label"}, cli.StringFlag{Name: "mount-label", Usage: "selinux mount context label"}, @@ -463,10 +464,6 @@ func addIDMappings(spec *rspec.Spec, context *cli.Context) error { } } - if len(context.StringSlice("uidmappings")) > 0 || len(context.StringSlice("gidmappings")) > 0 { - spec.Linux.Namespaces = append(spec.Linux.Namespaces, rspec.Namespace{Type: "user"}) - } - return nil } @@ -660,9 +657,14 @@ func mapStrToNamespace(ns string, path string) rspec.Namespace { } func setupNamespaces(spec *rspec.Spec, context *cli.Context) { - namespaces := []string{"network", "pid", "mount", "ipc", "uts"} + var needsNewUser = false + if len(context.StringSlice("uidmappings")) > 0 || len(context.StringSlice("gidmappings")) > 0 { + needsNewUser = true + } + + namespaces := []string{"network", "pid", "mount", "ipc", "uts", "user"} for _, nsName := range namespaces { - if !context.IsSet(nsName) { + if !context.IsSet(nsName) && !(needsNewUser && nsName == "user") { continue } nsPath := context.String(nsName) diff --git a/man/ocitools-generate.1.md b/man/ocitools-generate.1.md index 42763fdd4..cd2bbf169 100644 --- a/man/ocitools-generate.1.md +++ b/man/ocitools-generate.1.md @@ -57,7 +57,7 @@ inside of the container. Gid for the process inside of container **--gidmappings**=GIDMAPPINGS - Add GIDMappings e.g HostID:ContainerID:Size for use with User Namespace + Add GIDMappings e.g HostID:ContainerID:Size. Implies **-user=**. **--groups**=GROUP Supplementary groups for the processes inside of container @@ -191,7 +191,12 @@ inside of the container. Sets the UID used within the container. **--uidmappings** - Add UIDMappings e.g HostUID:ContainerID:Size for use with User Namespace + Add UIDMappings e.g HostUID:ContainerID:Size. Implies **--user=**. + +**--user**=[*PATH*] + Use a user namespace. If *PATH* is set, join that namespace. If it + is unset, create a new namespace. The special *PATH* `host` removes + any existing user namespace from the configuration. **--uts**=[*PATH*] Use a UTS namespace. If *PATH* is set, join that namespace. If it