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