From 40f829c1abb2cce0ab6853d970217f737abaad07 Mon Sep 17 00:00:00 2001 From: Dongsu Park Date: Thu, 12 Apr 2018 17:11:01 +0200 Subject: [PATCH] validation: add a new test for NSNewNSWithoutPath This test is to check for NSNewNSWithoutPath, i.e. "If path is not specified, the runtime MUST create a new container namespace of the given type" See also https://github.com/opencontainers/runtime-tools/issues/572 Signed-off-by: Dongsu Park --- validation/linux_ns_nopath.go | 85 ++++++++++++++++++++++++++++++ validation/util/linux_namespace.go | 14 +++++ 2 files changed, 99 insertions(+) create mode 100644 validation/linux_ns_nopath.go create mode 100644 validation/util/linux_namespace.go diff --git a/validation/linux_ns_nopath.go b/validation/linux_ns_nopath.go new file mode 100644 index 000000000..8c2c80ab6 --- /dev/null +++ b/validation/linux_ns_nopath.go @@ -0,0 +1,85 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + + "github.com/mndrix/tap-go" + rspec "github.com/opencontainers/runtime-spec/specs-go" + "github.com/opencontainers/runtime-tools/specerror" + "github.com/opencontainers/runtime-tools/validation/util" +) + +func testNamespaceNoPath(t *tap.T) error { + hostNsPath := fmt.Sprintf("/proc/%d/ns", os.Getpid()) + hostNsInodes := map[string]string{} + for _, nsName := range util.ProcNamespaces { + nsInode, err := os.Readlink(filepath.Join(hostNsPath, nsName)) + if err != nil { + return err + } + hostNsInodes[nsName] = nsInode + } + + g := util.GetDefaultGenerator() + + // As the namespaces, cgroups and user, are not set by GetDefaultGenerator(), + // others are set by default. We just set them explicitly to avoid confusion. + g.AddOrReplaceLinuxNamespace("cgroup", "") + g.AddOrReplaceLinuxNamespace("ipc", "") + g.AddOrReplaceLinuxNamespace("mount", "") + g.AddOrReplaceLinuxNamespace("network", "") + g.AddOrReplaceLinuxNamespace("pid", "") + g.AddOrReplaceLinuxNamespace("user", "") + g.AddOrReplaceLinuxNamespace("uts", "") + + err := util.RuntimeOutsideValidate(g, func(config *rspec.Spec, state *rspec.State) error { + containerNsPath := fmt.Sprintf("/proc/%d/ns", state.Pid) + + for _, nsName := range util.ProcNamespaces { + nsInode, err := os.Readlink(filepath.Join(containerNsPath, nsName)) + if err != nil { + return err + } + + t.Ok(hostNsInodes[nsName] != nsInode, fmt.Sprintf("create namespace %s without path", nsName)) + if hostNsInodes[nsName] == nsInode { + specErr := specerror.NewError(specerror.NSNewNSWithoutPath, + fmt.Errorf("both namespaces for %s have the same inode %s", nsName, nsInode), + rspec.Version) + diagnostic := map[string]interface{}{ + "expected": fmt.Sprintf("!= %s", hostNsInodes[nsName]), + "actual": nsInode, + "namespace type": nsName, + "level": specErr.(*specerror.Error).Err.Level, + "reference": specErr.(*specerror.Error).Err.Reference, + } + t.YAML(diagnostic) + + continue + } + } + + return nil + }) + + return err +} + +func main() { + t := tap.New() + t.Header(0) + + if "linux" != runtime.GOOS { + t.Skip(1, fmt.Sprintf("linux-specific namespace test")) + } + + err := testNamespaceNoPath(t) + if err != nil { + util.Fatal(err) + } + + t.AutoPlan() +} diff --git a/validation/util/linux_namespace.go b/validation/util/linux_namespace.go new file mode 100644 index 000000000..3d434b425 --- /dev/null +++ b/validation/util/linux_namespace.go @@ -0,0 +1,14 @@ +package util + +// ProcNamespaces defines a list of namespaces to be found under /proc/*/ns/. +// NOTE: it is not the same as generate.Namespaces, because of naming +// mismatches like "mnt" vs "mount" or "net" vs "network". +var ProcNamespaces = []string{ + "cgroup", + "ipc", + "mnt", + "net", + "pid", + "user", + "uts", +}