1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
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 printDiag(t *tap.T, diagActual, diagExpected, diagNsType string, errNs error) {
specErr := specerror.NewError(specerror.NSNewNSWithoutPath,
errNs, rspec.Version)
diagnostic := map[string]string{
"actual": diagActual,
"expected": diagExpected,
"namespace type": diagNsType,
"level": specErr.(*specerror.Error).Err.Level.String(),
"reference": specErr.(*specerror.Error).Err.Reference,
}
t.YAML(diagnostic)
}
func testNamespaceNoPath(t *tap.T) error {
var errNs error
diagActual := ""
diagExpected := ""
diagNsType := ""
// To be able to print out diagnostics for all kinds of error cases
// at the end of the tests, we make use of defer function. To do that,
// each error handling routine should set diagActual, diagExpected,
// diagNsType, and errNs, before returning an error.
defer func() {
if errNs != nil {
printDiag(t, diagActual, diagExpected, diagNsType, errNs)
}
}()
hostNsPath := fmt.Sprintf("/proc/%d/ns", os.Getpid())
hostNsInodes := map[string]string{}
for _, nsName := range util.ProcNamespaces {
nsPathAbs := filepath.Join(hostNsPath, nsName)
nsInode, err := os.Readlink(nsPathAbs)
if err != nil {
errNs = fmt.Errorf("cannot resolve symlink %q: %v", nsPathAbs, err)
diagActual = fmt.Sprintf("err == %v", errNs)
diagExpected = "err == nil"
diagNsType = nsName
return errNs
}
hostNsInodes[nsName] = nsInode
}
g, err := util.GetDefaultGenerator()
if err != nil {
errNs = fmt.Errorf("cannot get the default generator: %v", err)
diagActual = fmt.Sprintf("err == %v", errNs)
diagExpected = "err == nil"
// NOTE: we don't have a namespace type
return errNs
}
// 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", "")
// For user namespaces, we need to set uid/gid maps to create a container
g.AddLinuxUIDMapping(uint32(1000), uint32(0), uint32(1000))
g.AddLinuxGIDMapping(uint32(1000), uint32(0), uint32(1000))
err = util.RuntimeOutsideValidate(g, t, func(config *rspec.Spec, t *tap.T, state *rspec.State) error {
containerNsPath := fmt.Sprintf("/proc/%d/ns", state.Pid)
for _, nsName := range util.ProcNamespaces {
nsPathAbs := filepath.Join(containerNsPath, nsName)
nsInode, err := os.Readlink(nsPathAbs)
if err != nil {
errNs = fmt.Errorf("cannot resolve symlink %q: %v", nsPathAbs, err)
diagActual = fmt.Sprintf("err == %v", errNs)
diagExpected = "err == nil"
diagNsType = nsName
return errNs
}
t.Ok(hostNsInodes[nsName] != nsInode, fmt.Sprintf("create namespace %s without path", nsName))
if hostNsInodes[nsName] == nsInode {
// NOTE: for such inode match cases, we should print out diagnostics
// for each case, not only at the end of tests. So we should simply
// call once printDiag(), then continue testing next namespaces.
// Thus we don't need to set diagActual, diagExpected, diagNsType, etc.
printDiag(t, nsInode, fmt.Sprintf("!= %s", hostNsInodes[nsName]), nsName,
fmt.Errorf("both namespaces for %s have the same inode %s", nsName, nsInode))
continue
}
}
return nil
})
if err != nil {
errNs = fmt.Errorf("cannot run validation tests: %v", err)
}
return errNs
}
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 {
t.Fail(err.Error())
}
t.AutoPlan()
}
|