This repository has been archived by the owner on Apr 21, 2021. It is now read-only.
forked from opencontainers/runtime-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
validation: add a new test for NSPathMatchTypeError
`checkNSPathMatchType` checks if the container returns an error when deliberately setting a wrong namespace type. Doing that, it is possible to verify `NSPathMatchTypeError`, i.e. `The runtime MUST generate an error if path is not associated with a namespace of type "type"`. See also opencontainers#572 Signed-off-by: Dongsu Park <[email protected]>
- Loading branch information
Dongsu Park
committed
May 15, 2018
1 parent
923cf4e
commit d4961ab
Showing
1 changed file
with
122 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os/exec" | ||
"runtime" | ||
"syscall" | ||
|
||
"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 getRuntimeToolsNamespace(ns string) string { | ||
// Deal with exceptional cases of "net" and "mnt", because those strings | ||
// cannot be recognized by mapStrToNamespace(), which actually expects | ||
// "network" and "mount" respectively. | ||
switch ns { | ||
case "net": | ||
return "network" | ||
case "mnt": | ||
return "mount" | ||
} | ||
|
||
// In other cases, return just the original string | ||
return ns | ||
} | ||
|
||
func checkNSPathMatchType(t *tap.T, ns, wrongNs string) error { | ||
// Deliberately set ns path with a wrong namespace, to check if the runtime | ||
// returns error when running with the wrong namespace path. | ||
unshareNsPath := fmt.Sprintf("/proc/self/ns/%s", wrongNs) | ||
|
||
g, err := util.GetDefaultGenerator() | ||
if err != nil { | ||
return fmt.Errorf("cannot get default config from generator: %v", err) | ||
} | ||
|
||
rtns := getRuntimeToolsNamespace(ns) | ||
g.AddOrReplaceLinuxNamespace(rtns, unshareNsPath) | ||
|
||
err = util.RuntimeOutsideValidate(g, func(config *rspec.Spec, state *rspec.State) error { | ||
return nil | ||
}) | ||
|
||
t.Ok(err != nil, fmt.Sprintf("got error when setting a wrong namespace path %q with type %s", unshareNsPath, rtns)) | ||
if err == nil { | ||
rfcError, errRfc := specerror.NewRFCError(specerror.NSPathMatchTypeError, | ||
fmt.Errorf("got no error when setting a wrong namespace path %q with type %s", unshareNsPath, rtns), | ||
rspec.Version) | ||
if errRfc != nil { | ||
return fmt.Errorf("cannot get new rfcError: %v", errRfc) | ||
} | ||
diagnostic := map[string]string{ | ||
"expected": fmt.Sprintf("err == %v", err), | ||
"actual": "err == nil", | ||
"namespace type": rtns, | ||
"level": rfcError.Level.String(), | ||
"reference": rfcError.Reference, | ||
} | ||
t.YAML(diagnostic) | ||
|
||
return fmt.Errorf("cannot validate path with wrong type") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testNSPathMatchType(t *tap.T, ns, unshareOpt, wrongNs string) error { | ||
// Calling 'unshare' (part of util-linux) is easier than doing it from | ||
// Golang: mnt namespaces cannot be unshared from multithreaded | ||
// programs. | ||
cmd := exec.Command("unshare", unshareOpt, "--fork", "sleep", "10000") | ||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | ||
err := cmd.Start() | ||
if err != nil { | ||
return fmt.Errorf("cannot run unshare: %s", err) | ||
} | ||
defer func() { | ||
if cmd.Process != nil { | ||
cmd.Process.Kill() | ||
} | ||
cmd.Wait() | ||
syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) | ||
}() | ||
if cmd.Process == nil { | ||
return fmt.Errorf("process failed to start") | ||
} | ||
|
||
return checkNSPathMatchType(t, ns, wrongNs) | ||
} | ||
|
||
func main() { | ||
t := tap.New() | ||
t.Header(0) | ||
|
||
cases := []struct { | ||
name string | ||
unshareOpt string | ||
wrongname string | ||
}{ | ||
{"cgroup", "--cgroup", "ipc"}, | ||
{"ipc", "--ipc", "mnt"}, | ||
{"mnt", "--mount", "net"}, | ||
{"net", "--net", "pid"}, | ||
{"pid", "--pid", "user"}, | ||
{"user", "--user", "uts"}, | ||
{"uts", "--uts", "cgroup"}, | ||
} | ||
|
||
for _, c := range cases { | ||
if "linux" != runtime.GOOS { | ||
t.Skip(1, fmt.Sprintf("linux-specific namespace test: %s", c)) | ||
} | ||
|
||
err := testNSPathMatchType(t, c.name, c.unshareOpt, c.wrongname) | ||
t.Ok(err == nil, fmt.Sprintf("namespace path matches with type %s", c.name)) | ||
} | ||
|
||
t.AutoPlan() | ||
} |