github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/pkg/idtools/idtools_unix_test.go (about) 1 // +build !windows 2 3 package idtools 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "syscall" 11 "testing" 12 ) 13 14 type node struct { 15 uid int 16 gid int 17 } 18 19 func TestMkdirAllAs(t *testing.T) { 20 dirName, err := ioutil.TempDir("", "mkdirall") 21 if err != nil { 22 t.Fatalf("Couldn't create temp dir: %v", err) 23 } 24 defer os.RemoveAll(dirName) 25 26 testTree := map[string]node{ 27 "usr": {0, 0}, 28 "usr/bin": {0, 0}, 29 "lib": {33, 33}, 30 "lib/x86_64": {45, 45}, 31 "lib/x86_64/share": {1, 1}, 32 } 33 34 if err := buildTree(dirName, testTree); err != nil { 35 t.Fatal(err) 36 } 37 38 // test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid 39 if err := MkdirAllAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil { 40 t.Fatal(err) 41 } 42 testTree["usr/share"] = node{99, 99} 43 verifyTree, err := readTree(dirName, "") 44 if err != nil { 45 t.Fatal(err) 46 } 47 if err := compareTrees(testTree, verifyTree); err != nil { 48 t.Fatal(err) 49 } 50 51 // test 2-deep new directories--both should be owned by the uid/gid pair 52 if err := MkdirAllAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil { 53 t.Fatal(err) 54 } 55 testTree["lib/some"] = node{101, 101} 56 testTree["lib/some/other"] = node{101, 101} 57 verifyTree, err = readTree(dirName, "") 58 if err != nil { 59 t.Fatal(err) 60 } 61 if err := compareTrees(testTree, verifyTree); err != nil { 62 t.Fatal(err) 63 } 64 65 // test a directory that already exists; should be chowned, but nothing else 66 if err := MkdirAllAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil { 67 t.Fatal(err) 68 } 69 testTree["usr"] = node{102, 102} 70 verifyTree, err = readTree(dirName, "") 71 if err != nil { 72 t.Fatal(err) 73 } 74 if err := compareTrees(testTree, verifyTree); err != nil { 75 t.Fatal(err) 76 } 77 } 78 79 func TestMkdirAllNewAs(t *testing.T) { 80 81 dirName, err := ioutil.TempDir("", "mkdirnew") 82 if err != nil { 83 t.Fatalf("Couldn't create temp dir: %v", err) 84 } 85 defer os.RemoveAll(dirName) 86 87 testTree := map[string]node{ 88 "usr": {0, 0}, 89 "usr/bin": {0, 0}, 90 "lib": {33, 33}, 91 "lib/x86_64": {45, 45}, 92 "lib/x86_64/share": {1, 1}, 93 } 94 95 if err := buildTree(dirName, testTree); err != nil { 96 t.Fatal(err) 97 } 98 99 // test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid 100 if err := MkdirAllNewAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil { 101 t.Fatal(err) 102 } 103 testTree["usr/share"] = node{99, 99} 104 verifyTree, err := readTree(dirName, "") 105 if err != nil { 106 t.Fatal(err) 107 } 108 if err := compareTrees(testTree, verifyTree); err != nil { 109 t.Fatal(err) 110 } 111 112 // test 2-deep new directories--both should be owned by the uid/gid pair 113 if err := MkdirAllNewAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil { 114 t.Fatal(err) 115 } 116 testTree["lib/some"] = node{101, 101} 117 testTree["lib/some/other"] = node{101, 101} 118 verifyTree, err = readTree(dirName, "") 119 if err != nil { 120 t.Fatal(err) 121 } 122 if err := compareTrees(testTree, verifyTree); err != nil { 123 t.Fatal(err) 124 } 125 126 // test a directory that already exists; should NOT be chowned 127 if err := MkdirAllNewAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil { 128 t.Fatal(err) 129 } 130 verifyTree, err = readTree(dirName, "") 131 if err != nil { 132 t.Fatal(err) 133 } 134 if err := compareTrees(testTree, verifyTree); err != nil { 135 t.Fatal(err) 136 } 137 } 138 139 func TestMkdirAs(t *testing.T) { 140 141 dirName, err := ioutil.TempDir("", "mkdir") 142 if err != nil { 143 t.Fatalf("Couldn't create temp dir: %v", err) 144 } 145 defer os.RemoveAll(dirName) 146 147 testTree := map[string]node{ 148 "usr": {0, 0}, 149 } 150 if err := buildTree(dirName, testTree); err != nil { 151 t.Fatal(err) 152 } 153 154 // test a directory that already exists; should just chown to the requested uid/gid 155 if err := MkdirAs(filepath.Join(dirName, "usr"), 0755, 99, 99); err != nil { 156 t.Fatal(err) 157 } 158 testTree["usr"] = node{99, 99} 159 verifyTree, err := readTree(dirName, "") 160 if err != nil { 161 t.Fatal(err) 162 } 163 if err := compareTrees(testTree, verifyTree); err != nil { 164 t.Fatal(err) 165 } 166 167 // create a subdir under a dir which doesn't exist--should fail 168 if err := MkdirAs(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, 102, 102); err == nil { 169 t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed") 170 } 171 172 // create a subdir under an existing dir; should only change the ownership of the new subdir 173 if err := MkdirAs(filepath.Join(dirName, "usr", "bin"), 0755, 102, 102); err != nil { 174 t.Fatal(err) 175 } 176 testTree["usr/bin"] = node{102, 102} 177 verifyTree, err = readTree(dirName, "") 178 if err != nil { 179 t.Fatal(err) 180 } 181 if err := compareTrees(testTree, verifyTree); err != nil { 182 t.Fatal(err) 183 } 184 } 185 186 func buildTree(base string, tree map[string]node) error { 187 for path, node := range tree { 188 fullPath := filepath.Join(base, path) 189 if err := os.MkdirAll(fullPath, 0755); err != nil { 190 return fmt.Errorf("Couldn't create path: %s; error: %v", fullPath, err) 191 } 192 if err := os.Chown(fullPath, node.uid, node.gid); err != nil { 193 return fmt.Errorf("Couldn't chown path: %s; error: %v", fullPath, err) 194 } 195 } 196 return nil 197 } 198 199 func readTree(base, root string) (map[string]node, error) { 200 tree := make(map[string]node) 201 202 dirInfos, err := ioutil.ReadDir(base) 203 if err != nil { 204 return nil, fmt.Errorf("Couldn't read directory entries for %q: %v", base, err) 205 } 206 207 for _, info := range dirInfos { 208 s := &syscall.Stat_t{} 209 if err := syscall.Stat(filepath.Join(base, info.Name()), s); err != nil { 210 return nil, fmt.Errorf("Can't stat file %q: %v", filepath.Join(base, info.Name()), err) 211 } 212 tree[filepath.Join(root, info.Name())] = node{int(s.Uid), int(s.Gid)} 213 if info.IsDir() { 214 // read the subdirectory 215 subtree, err := readTree(filepath.Join(base, info.Name()), filepath.Join(root, info.Name())) 216 if err != nil { 217 return nil, err 218 } 219 for path, nodeinfo := range subtree { 220 tree[path] = nodeinfo 221 } 222 } 223 } 224 return tree, nil 225 } 226 227 func compareTrees(left, right map[string]node) error { 228 if len(left) != len(right) { 229 return fmt.Errorf("Trees aren't the same size") 230 } 231 for path, nodeLeft := range left { 232 if nodeRight, ok := right[path]; ok { 233 if nodeRight.uid != nodeLeft.uid || nodeRight.gid != nodeLeft.gid { 234 // mismatch 235 return fmt.Errorf("mismatched ownership for %q: expected: %d:%d, got: %d:%d", path, 236 nodeLeft.uid, nodeLeft.gid, nodeRight.uid, nodeRight.gid) 237 } 238 continue 239 } 240 return fmt.Errorf("right tree didn't contain path %q", path) 241 } 242 return nil 243 } 244 245 func TestParseSubidFileWithNewlinesAndComments(t *testing.T) { 246 tmpDir, err := ioutil.TempDir("", "parsesubid") 247 if err != nil { 248 t.Fatal(err) 249 } 250 fnamePath := filepath.Join(tmpDir, "testsubuid") 251 fcontent := `tss:100000:65536 252 # empty default subuid/subgid file 253 254 dockremap:231072:65536` 255 if err := ioutil.WriteFile(fnamePath, []byte(fcontent), 0644); err != nil { 256 t.Fatal(err) 257 } 258 ranges, err := parseSubidFile(fnamePath, "dockremap") 259 if err != nil { 260 t.Fatal(err) 261 } 262 if len(ranges) != 1 { 263 t.Fatalf("wanted 1 element in ranges, got %d instead", len(ranges)) 264 } 265 if ranges[0].Start != 231072 { 266 t.Fatalf("wanted 231072, got %d instead", ranges[0].Start) 267 } 268 if ranges[0].Length != 65536 { 269 t.Fatalf("wanted 65536, got %d instead", ranges[0].Length) 270 } 271 }