From 71f195b3d423e1abf8b82d4357cfa1122511090d Mon Sep 17 00:00:00 2001 From: Michael McCracken Date: Wed, 1 May 2019 18:27:57 -0700 Subject: [PATCH 1/6] create: handle namespaces in spec Signed-off-by: Michael McCracken --- cmd/create.go | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/cmd/create.go b/cmd/create.go index 2d53b6c3..c3edad95 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -9,6 +9,7 @@ import ( "os/exec" "path" "path/filepath" + "regexp" "strings" "time" @@ -42,6 +43,17 @@ var createCmd = cli.Command{ }, } +// maps from CRIO namespace names to LXC names +var NamespaceMap = map[string]string{ + "cgroup": "cgroup", + "ipc": "ipc", + "mount": "mnt", + "network": "net", + "pid": "pid", + "user": "user", + "uts": "uts", +} + func ensureShell(rootfs string) { shPath := filepath.Join(rootfs, "bin/sh") if exists, _ := pathExists(shPath); exists { @@ -202,6 +214,46 @@ func configureContainer(ctx *cli.Context, c *lxc.Container, spec *specs.Spec) er return errors.Wrap(err, "failed to set hook version") } + procPidPathRE := regexp.MustCompile(`/proc/(\d+)/ns`) + + var nsToClone []string + var configVal string + seenNamespaceTypes := map[specs.LinuxNamespaceType]bool{} + for _, ns := range spec.Linux.Namespaces { + if _, ok := seenNamespaceTypes[ns.Type]; ok == true { + return fmt.Errorf("duplicate namespace type %s", ns.Type) + } + seenNamespaceTypes[ns.Type] = true + if ns.Path == "" { + nsToClone = append(nsToClone, NamespaceMap[string(ns.Type)]) + } else { + configKey := fmt.Sprintf("lxc.namespace.share.%s", NamespaceMap[string(ns.Type)]) + + matches := procPidPathRE.FindStringSubmatch(ns.Path) + switch len(matches) { + case 0: + configVal = ns.Path + case 1: + return fmt.Errorf("error parsing namespace path. expected /proc/(\\d+)/ns/*, got '%s'", ns.Path) + case 2: + configVal = matches[1] + default: + return fmt.Errorf("error parsing namespace path. expected /proc/(\\d+)/ns/*, got '%s'", ns.Path) + } + + if err := c.SetConfigItem(configKey, configVal); err != nil { + return errors.Wrapf(err, "failed to set namespace config: '%s'='%s'", configKey, configVal) + } + } + } + + if len(nsToClone) > 0 { + configVal = strings.Join(nsToClone, " ") + if err := c.SetConfigItem("lxc.namespace.clone", configVal); err != nil { + return errors.Wrapf(err, "failed to set lxc.namespace.clone=%s", configVal) + } + } + // capabilities? // if !spec.Process.Terminal { From 8fbba421bedf68439fdc0b72d38d2a6cd4335411 Mon Sep 17 00:00:00 2001 From: Michael McCracken Date: Thu, 2 May 2019 12:10:24 -0700 Subject: [PATCH 2/6] helpers: fix var reference in crictl func want to substitute, not run CRICTLDEBUG Signed-off-by: Michael McCracken --- test/helpers.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helpers.bash b/test/helpers.bash index 9b906db5..1741ea13 100644 --- a/test/helpers.bash +++ b/test/helpers.bash @@ -54,7 +54,7 @@ function crictl { # watch out for: https://github.com/kubernetes-sigs/cri-tools/issues/460 # If you need more debug output, set CRICTLDEBUG to -D CRICTLDEBUG="" - $(which crictl) $(CRICTLDEBUG) --runtime-endpoint "$TEMP_DIR/crio.sock" $@ + $(which crictl) ${CRICTLDEBUG} --runtime-endpoint "$TEMP_DIR/crio.sock" $@ echo "$output" } From d7ed2812ea42801e86d999a6e9e13cfcece4a86c Mon Sep 17 00:00:00 2001 From: Michael McCracken Date: Thu, 2 May 2019 16:38:08 -0700 Subject: [PATCH 3/6] test: clean up created containers Signed-off-by: Michael McCracken --- test/basic.bats | 2 ++ test/manual.bats | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/basic.bats b/test/basic.bats index b9a8c6d4..70e93176 100644 --- a/test/basic.bats +++ b/test/basic.bats @@ -15,4 +15,6 @@ function teardown() { podid=$(crictl pods | grep nginx-sandbox | awk '{ print $1 }') crictl create $podid test/basic-container-config.json test/basic-pod-config.json crictl ps -a | grep busybox + crictl stopp $podid + crictl rmp $podid } diff --git a/test/manual.bats b/test/manual.bats index 7dc4ecfb..ec8246c6 100644 --- a/test/manual.bats +++ b/test/manual.bats @@ -14,4 +14,6 @@ function teardown() { @test "manual invocation" { crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" create --bundle "$TEMP_DIR/dest" alpine crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" start alpine + crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" kill alpine + crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" delete alpine } From c7d98002c17563dc55f8483a02b633b07f13dcee Mon Sep 17 00:00:00 2001 From: Michael McCracken Date: Thu, 2 May 2019 16:38:27 -0700 Subject: [PATCH 4/6] test: manual: replace shell with sleep so container stays running so we can test killing and deleting Signed-off-by: Michael McCracken --- test/manual.bats | 1 + 1 file changed, 1 insertion(+) diff --git a/test/manual.bats b/test/manual.bats index ec8246c6..1ec28edb 100644 --- a/test/manual.bats +++ b/test/manual.bats @@ -5,6 +5,7 @@ function setup() { skopeo --insecure-policy copy docker://alpine:latest oci:$ROOT_DIR/test/oci-cache:alpine umoci unpack --image "$ROOT_DIR/test/oci-cache:alpine" "$TEMP_DIR/dest" sed -i -e "s?rootfs?$TEMP_DIR/dest/rootfs?" "$TEMP_DIR/dest/config.json" + sed -i -e "s?\"/bin/sh\"?\"/bin/sleep\",\n\"60\"?" "$TEMP_DIR/dest/config.json" } function teardown() { From ae8352f59b8980ad4e799c1e1f393db5835e8c23 Mon Sep 17 00:00:00 2001 From: Michael McCracken Date: Thu, 2 May 2019 18:52:03 -0700 Subject: [PATCH 5/6] test: check that container correctly shares a namespace Signed-off-by: Michael McCracken --- test/manual.bats | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/manual.bats b/test/manual.bats index 1ec28edb..265e1fb0 100644 --- a/test/manual.bats +++ b/test/manual.bats @@ -5,7 +5,9 @@ function setup() { skopeo --insecure-policy copy docker://alpine:latest oci:$ROOT_DIR/test/oci-cache:alpine umoci unpack --image "$ROOT_DIR/test/oci-cache:alpine" "$TEMP_DIR/dest" sed -i -e "s?rootfs?$TEMP_DIR/dest/rootfs?" "$TEMP_DIR/dest/config.json" - sed -i -e "s?\"/bin/sh\"?\"/bin/sleep\",\n\"60\"?" "$TEMP_DIR/dest/config.json" + sed -i -e "s?\"/bin/sh\"?\"/bin/sleep\",\n\"10\"?" "$TEMP_DIR/dest/config.json" + sed -i -e "s?\"type\": \"ipc\"?\"type\": \"ipc\",\n\"path\": \"/proc/1/ns/ipc\"?" "$TEMP_DIR/dest/config.json" + } function teardown() { @@ -13,8 +15,12 @@ function teardown() { } @test "manual invocation" { - crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" create --bundle "$TEMP_DIR/dest" alpine + crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" create --bundle "$TEMP_DIR/dest" --pid-file "$TEMP_DIR/pid" alpine crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" start alpine + pid1ipcnsinode=$(stat -L -c%i /proc/1/ns/ipc) + mypid=$(<"$TEMP_DIR/pid") + mypidipcnsinode=$(stat -L -c%i "/proc/$mypid/ns/ipc") + [ $pid1ipcnsinode = $mypidipcnsinode ] crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" kill alpine crio-lxc --debug --log-level trace --log-file "$TEMP_DIR/log" delete alpine } From 2626572f5059030845ad8b8e1d818ffb9d6fcf7d Mon Sep 17 00:00:00 2001 From: Michael McCracken Date: Fri, 3 May 2019 15:07:49 -0700 Subject: [PATCH 6/6] create: hoist namespace config into configureNamespaces avoids having one huge function Signed-off-by: Michael McCracken --- cmd/create.go | 83 ++++++++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/cmd/create.go b/cmd/create.go index c3edad95..7c418f2b 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -92,6 +92,49 @@ exec $@ return ioutil.WriteFile(file, []byte(fifoWaiter), 0755) } +func configureNamespaces(c *lxc.Container, spec *specs.Spec) error { + procPidPathRE := regexp.MustCompile(`/proc/(\d+)/ns`) + + var nsToClone []string + var configVal string + seenNamespaceTypes := map[specs.LinuxNamespaceType]bool{} + for _, ns := range spec.Linux.Namespaces { + if _, ok := seenNamespaceTypes[ns.Type]; ok == true { + return fmt.Errorf("duplicate namespace type %s", ns.Type) + } + seenNamespaceTypes[ns.Type] = true + if ns.Path == "" { + nsToClone = append(nsToClone, NamespaceMap[string(ns.Type)]) + } else { + configKey := fmt.Sprintf("lxc.namespace.share.%s", NamespaceMap[string(ns.Type)]) + + matches := procPidPathRE.FindStringSubmatch(ns.Path) + switch len(matches) { + case 0: + configVal = ns.Path + case 1: + return fmt.Errorf("error parsing namespace path. expected /proc/(\\d+)/ns/*, got '%s'", ns.Path) + case 2: + configVal = matches[1] + default: + return fmt.Errorf("error parsing namespace path. expected /proc/(\\d+)/ns/*, got '%s'", ns.Path) + } + + if err := c.SetConfigItem(configKey, configVal); err != nil { + return errors.Wrapf(err, "failed to set namespace config: '%s'='%s'", configKey, configVal) + } + } + } + + if len(nsToClone) > 0 { + configVal = strings.Join(nsToClone, " ") + if err := c.SetConfigItem("lxc.namespace.clone", configVal); err != nil { + return errors.Wrapf(err, "failed to set lxc.namespace.clone=%s", configVal) + } + } + return nil +} + func doCreate(ctx *cli.Context) error { pidfile := ctx.String("pid-file") containerID := ctx.Args().Get(0) @@ -214,44 +257,8 @@ func configureContainer(ctx *cli.Context, c *lxc.Container, spec *specs.Spec) er return errors.Wrap(err, "failed to set hook version") } - procPidPathRE := regexp.MustCompile(`/proc/(\d+)/ns`) - - var nsToClone []string - var configVal string - seenNamespaceTypes := map[specs.LinuxNamespaceType]bool{} - for _, ns := range spec.Linux.Namespaces { - if _, ok := seenNamespaceTypes[ns.Type]; ok == true { - return fmt.Errorf("duplicate namespace type %s", ns.Type) - } - seenNamespaceTypes[ns.Type] = true - if ns.Path == "" { - nsToClone = append(nsToClone, NamespaceMap[string(ns.Type)]) - } else { - configKey := fmt.Sprintf("lxc.namespace.share.%s", NamespaceMap[string(ns.Type)]) - - matches := procPidPathRE.FindStringSubmatch(ns.Path) - switch len(matches) { - case 0: - configVal = ns.Path - case 1: - return fmt.Errorf("error parsing namespace path. expected /proc/(\\d+)/ns/*, got '%s'", ns.Path) - case 2: - configVal = matches[1] - default: - return fmt.Errorf("error parsing namespace path. expected /proc/(\\d+)/ns/*, got '%s'", ns.Path) - } - - if err := c.SetConfigItem(configKey, configVal); err != nil { - return errors.Wrapf(err, "failed to set namespace config: '%s'='%s'", configKey, configVal) - } - } - } - - if len(nsToClone) > 0 { - configVal = strings.Join(nsToClone, " ") - if err := c.SetConfigItem("lxc.namespace.clone", configVal); err != nil { - return errors.Wrapf(err, "failed to set lxc.namespace.clone=%s", configVal) - } + if err := configureNamespaces(c, spec); err != nil { + return errors.Wrap(err, "failed to configure namespaces") } // capabilities?