From 4661c239dc6394aba960ba73144f2a7e3859537f Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 16 Dec 2014 15:32:54 -0800 Subject: [PATCH 1/2] Add type for namespaces for better UI This adds `type Namespaces []Namespace` so that methods can be added to this slice so that it is easier for consumers to work with the values. Signed-off-by: Michael Crosby --- config.go | 35 ++++++++++++++++++++++++++++++++++- integration/exec_test.go | 20 +++----------------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/config.go b/config.go index 94c2bd981..33e55aa87 100644 --- a/config.go +++ b/config.go @@ -17,6 +17,39 @@ type Namespace struct { Path string `json:"path,omitempty"` } +type Namespaces []Namespace + +func (n Namespaces) Exists(name string) bool { + return n.index(name) != -1 +} + +func (n Namespaces) Remove(name string) bool { + i := n.index(name) + if i == -1 { + return false + } + n = append(n[:i], n[i+1:]...) + return true +} + +func (n Namespaces) Add(name, path string) { + i := n.index(name) + if i == -1 { + n = append(n, Namespace{Name: name, Path: path}) + return + } + n[i].Path = path +} + +func (n Namespaces) index(name string) int { + for i, ns := range n { + if ns.Name == name { + return i + } + } + return -1 +} + // Config defines configuration options for executing a process inside a contained environment. type Config struct { // Mount specific options. @@ -45,7 +78,7 @@ type Config struct { // Namespaces specifies the container's namespaces that it should setup when cloning the init process // If a namespace is not provided that namespace is shared from the container's parent process - Namespaces []Namespace `json:"namespaces,omitempty"` + Namespaces Namespaces `json:"namespaces,omitempty"` // Capabilities specify the capabilities to keep when executing the process inside the container // All capbilities not specified will be dropped from the processes capability mask diff --git a/integration/exec_test.go b/integration/exec_test.go index cf749efbf..bb2d6c11b 100644 --- a/integration/exec_test.go +++ b/integration/exec_test.go @@ -4,8 +4,6 @@ import ( "os" "strings" "testing" - - "github.com/docker/libcontainer" ) func TestExecPS(t *testing.T) { @@ -88,8 +86,7 @@ func TestIPCHost(t *testing.T) { } config := newTemplateConfig(rootfs) - i := getNamespaceIndex(config, "NEWIPC") - config.Namespaces = append(config.Namespaces[:i], config.Namespaces[i+1:]...) + config.Namespaces.Remove("NEWIPC") buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc") if err != nil { t.Fatal(err) @@ -121,8 +118,7 @@ func TestIPCJoinPath(t *testing.T) { } config := newTemplateConfig(rootfs) - i := getNamespaceIndex(config, "NEWIPC") - config.Namespaces[i].Path = "/proc/1/ns/ipc" + config.Namespaces.Add("NEWIPC", "/proc/1/ns/ipc") buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc") if err != nil { @@ -150,8 +146,7 @@ func TestIPCBadPath(t *testing.T) { defer remove(rootfs) config := newTemplateConfig(rootfs) - i := getNamespaceIndex(config, "NEWIPC") - config.Namespaces[i].Path = "/proc/1/ns/ipcc" + config.Namespaces.Add("NEWIPC", "/proc/1/ns/ipcc") _, _, err = runContainer(config, "", "true") if err == nil { @@ -179,12 +174,3 @@ func TestRlimit(t *testing.T) { t.Fatalf("expected rlimit to be 1024, got %s", limit) } } - -func getNamespaceIndex(config *libcontainer.Config, name string) int { - for i, v := range config.Namespaces { - if v.Name == name { - return i - } - } - return -1 -} From 2329014b6dbc473326291fa6e101e6d63c4dbd25 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 16 Dec 2014 16:34:46 -0800 Subject: [PATCH 2/2] Implement types for namespaces Signed-off-by: Michael Crosby --- config.go | 33 +++++++++++-------- config_test.go | 13 ++------ integration/exec_test.go | 8 +++-- integration/template_test.go | 12 +++---- namespaces/init.go | 2 +- namespaces/utils.go | 18 +++++----- sample_configs/apparmor.json | 10 +++--- sample_configs/attach_to_bridge.json | 10 +++--- sample_configs/minimal.json | 10 +++--- .../route_source_address_selection.json | 10 +++--- sample_configs/selinux.json | 10 +++--- 11 files changed, 68 insertions(+), 68 deletions(-) diff --git a/config.go b/config.go index 33e55aa87..bf5236555 100644 --- a/config.go +++ b/config.go @@ -10,21 +10,28 @@ type MountConfig mount.MountConfig type Network network.Network +type NamespaceType string + +const ( + NEWNET NamespaceType = "NEWNET" + NEWPID NamespaceType = "NEWPID" + NEWNS NamespaceType = "NEWNS" + NEWUTS NamespaceType = "NEWUTS" + NEWIPC NamespaceType = "NEWIPC" + NEWUSER NamespaceType = "NEWUSER" +) + // Namespace defines configuration for each namespace. It specifies an // alternate path that is able to be joined via setns. type Namespace struct { - Name string `json:"name"` - Path string `json:"path,omitempty"` + Type NamespaceType `json:"type"` + Path string `json:"path,omitempty"` } type Namespaces []Namespace -func (n Namespaces) Exists(name string) bool { - return n.index(name) != -1 -} - -func (n Namespaces) Remove(name string) bool { - i := n.index(name) +func (n Namespaces) Remove(t NamespaceType) bool { + i := n.index(t) if i == -1 { return false } @@ -32,18 +39,18 @@ func (n Namespaces) Remove(name string) bool { return true } -func (n Namespaces) Add(name, path string) { - i := n.index(name) +func (n Namespaces) Add(t NamespaceType, path string) { + i := n.index(t) if i == -1 { - n = append(n, Namespace{Name: name, Path: path}) + n = append(n, Namespace{Type: t, Path: path}) return } n[i].Path = path } -func (n Namespaces) index(name string) int { +func (n Namespaces) index(t NamespaceType) int { for i, ns := range n { - if ns.Name == name { + if ns.Type == t { return i } } diff --git a/config_test.go b/config_test.go index b4e16bf01..63b8aa8ad 100644 --- a/config_test.go +++ b/config_test.go @@ -64,12 +64,12 @@ func TestConfigJsonFormat(t *testing.T) { t.Fail() } - if getNamespaceIndex(container, "NEWNET") == -1 { + if container.Namespaces.index(NEWNET) == -1 { t.Log("namespaces should contain NEWNET") t.Fail() } - if getNamespaceIndex(container, "NEWUSER") != -1 { + if container.Namespaces.index(NEWUSER) != -1 { t.Log("namespaces should not contain NEWUSER") t.Fail() } @@ -158,12 +158,3 @@ func TestSelinuxLabels(t *testing.T) { t.Fatalf("expected mount label %q but received %q", label, container.MountConfig.MountLabel) } } - -func getNamespaceIndex(config *Config, name string) int { - for i, v := range config.Namespaces { - if v.Name == name { - return i - } - } - return -1 -} diff --git a/integration/exec_test.go b/integration/exec_test.go index bb2d6c11b..f0728c581 100644 --- a/integration/exec_test.go +++ b/integration/exec_test.go @@ -4,6 +4,8 @@ import ( "os" "strings" "testing" + + "github.com/docker/libcontainer" ) func TestExecPS(t *testing.T) { @@ -86,7 +88,7 @@ func TestIPCHost(t *testing.T) { } config := newTemplateConfig(rootfs) - config.Namespaces.Remove("NEWIPC") + config.Namespaces.Remove(libcontainer.NEWIPC) buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc") if err != nil { t.Fatal(err) @@ -118,7 +120,7 @@ func TestIPCJoinPath(t *testing.T) { } config := newTemplateConfig(rootfs) - config.Namespaces.Add("NEWIPC", "/proc/1/ns/ipc") + config.Namespaces.Add(libcontainer.NEWIPC, "/proc/1/ns/ipc") buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/ipc") if err != nil { @@ -146,7 +148,7 @@ func TestIPCBadPath(t *testing.T) { defer remove(rootfs) config := newTemplateConfig(rootfs) - config.Namespaces.Add("NEWIPC", "/proc/1/ns/ipcc") + config.Namespaces.Add(libcontainer.NEWIPC, "/proc/1/ns/ipcc") _, _, err = runContainer(config, "", "true") if err == nil { diff --git a/integration/template_test.go b/integration/template_test.go index f37070ffb..7e56628c2 100644 --- a/integration/template_test.go +++ b/integration/template_test.go @@ -32,12 +32,12 @@ func newTemplateConfig(rootfs string) *libcontainer.Config { "KILL", "AUDIT_WRITE", }, - Namespaces: []libcontainer.Namespace{ - {Name: "NEWNS"}, - {Name: "NEWUTS"}, - {Name: "NEWIPC"}, - {Name: "NEWPID"}, - {Name: "NEWNET"}, + Namespaces: libcontainer.Namespaces{ + {Type: libcontainer.NEWNS}, + {Type: libcontainer.NEWUTS}, + {Type: libcontainer.NEWIPC}, + {Type: libcontainer.NEWPID}, + {Type: libcontainer.NEWNET}, }, Cgroups: &cgroups.Cgroup{ Parent: "integration", diff --git a/namespaces/init.go b/namespaces/init.go index 10e450214..a4400bddb 100644 --- a/namespaces/init.go +++ b/namespaces/init.go @@ -318,7 +318,7 @@ func joinExistingNamespaces(namespaces []libcontainer.Namespace) error { if err != nil { return err } - err = system.Setns(f.Fd(), uintptr(namespaceInfo[ns.Name])) + err = system.Setns(f.Fd(), uintptr(namespaceInfo[ns.Type])) f.Close() if err != nil { return err diff --git a/namespaces/utils.go b/namespaces/utils.go index 556ea6699..de71a379f 100644 --- a/namespaces/utils.go +++ b/namespaces/utils.go @@ -17,13 +17,13 @@ func (i initError) Error() string { return i.Message } -var namespaceInfo = map[string]int{ - "NEWNET": syscall.CLONE_NEWNET, - "NEWNS": syscall.CLONE_NEWNS, - "NEWUSER": syscall.CLONE_NEWUSER, - "NEWIPC": syscall.CLONE_NEWIPC, - "NEWUTS": syscall.CLONE_NEWUTS, - "NEWPID": syscall.CLONE_NEWPID, +var namespaceInfo = map[libcontainer.NamespaceType]int{ + libcontainer.NEWNET: syscall.CLONE_NEWNET, + libcontainer.NEWNS: syscall.CLONE_NEWNS, + libcontainer.NEWUSER: syscall.CLONE_NEWUSER, + libcontainer.NEWIPC: syscall.CLONE_NEWIPC, + libcontainer.NEWUTS: syscall.CLONE_NEWUTS, + libcontainer.NEWPID: syscall.CLONE_NEWPID, } // New returns a newly initialized Pipe for communication between processes @@ -37,9 +37,9 @@ func newInitPipe() (parent *os.File, child *os.File, err error) { // GetNamespaceFlags parses the container's Namespaces options to set the correct // flags on clone, unshare, and setns -func GetNamespaceFlags(namespaces []libcontainer.Namespace) (flag int) { +func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { for _, v := range namespaces { - flag |= namespaceInfo[v.Name] + flag |= namespaceInfo[v.Type] } return flag } diff --git a/sample_configs/apparmor.json b/sample_configs/apparmor.json index 50421ec88..96f73cb79 100644 --- a/sample_configs/apparmor.json +++ b/sample_configs/apparmor.json @@ -177,11 +177,11 @@ ], "hostname": "koye", "namespaces": [ - {"name":"NEWIPC"}, - {"name": "NEWNET"}, - {"name": "NEWNS"}, - {"name": "NEWPID"}, - {"name": "NEWUTS"} + {"type":"NEWIPC"}, + {"type": "NEWNET"}, + {"type": "NEWNS"}, + {"type": "NEWPID"}, + {"type": "NEWUTS"} ], "networks": [ { diff --git a/sample_configs/attach_to_bridge.json b/sample_configs/attach_to_bridge.json index 9b190293a..e5c03a7ef 100644 --- a/sample_configs/attach_to_bridge.json +++ b/sample_configs/attach_to_bridge.json @@ -176,11 +176,11 @@ ], "hostname": "koye", "namespaces": [ - {"name": "NEWIPC"}, - {"name": "NEWNET"}, - {"name": "NEWNS"}, - {"name": "NEWPID"}, - {"name": "NEWUTS"} + {"type": "NEWIPC"}, + {"type": "NEWNET"}, + {"type": "NEWNS"}, + {"type": "NEWPID"}, + {"type": "NEWUTS"} ], "networks": [ { diff --git a/sample_configs/minimal.json b/sample_configs/minimal.json index 720be64f9..01de46746 100644 --- a/sample_configs/minimal.json +++ b/sample_configs/minimal.json @@ -182,11 +182,11 @@ ], "hostname": "koye", "namespaces": [ - {"name": "NEWIPC"}, - {"name": "NEWNET"}, - {"name": "NEWNS"}, - {"name": "NEWPID"}, - {"name": "NEWUTS"} + {"type": "NEWIPC"}, + {"type": "NEWNET"}, + {"type": "NEWNS"}, + {"type": "NEWPID"}, + {"type": "NEWUTS"} ], "networks": [ { diff --git a/sample_configs/route_source_address_selection.json b/sample_configs/route_source_address_selection.json index f403996dc..9c62045a4 100644 --- a/sample_configs/route_source_address_selection.json +++ b/sample_configs/route_source_address_selection.json @@ -176,11 +176,11 @@ ], "hostname": "koye", "namespaces": [ - {"name": "NEWIPC"}, - {"name": "NEWNET"}, - {"name": "NEWNS"}, - {"name": "NEWPID"}, - {"name": "NEWUTS"} + {"type": "NEWIPC"}, + {"type": "NEWNET"}, + {"type": "NEWNS"}, + {"type": "NEWPID"}, + {"type": "NEWUTS"} ], "networks": [ { diff --git a/sample_configs/selinux.json b/sample_configs/selinux.json index cfb83e09f..15556488a 100644 --- a/sample_configs/selinux.json +++ b/sample_configs/selinux.json @@ -178,11 +178,11 @@ ], "hostname": "koye", "namespaces": [ - {"name": "NEWIPC"}, - {"name": "NEWNET"}, - {"name": "NEWNS"}, - {"name": "NEWPID"}, - {"name": "NEWUTS"} + {"type": "NEWIPC"}, + {"type": "NEWNET"}, + {"type": "NEWNS"}, + {"type": "NEWPID"}, + {"type": "NEWUTS"} ], "networks": [ {