github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/client/allocdir/alloc_dir_test.go (about) 1 package allocdir 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "io" 7 "io/ioutil" 8 "log" 9 "os" 10 "path/filepath" 11 "reflect" 12 "runtime" 13 "strings" 14 "testing" 15 16 tomb "gopkg.in/tomb.v1" 17 18 "github.com/hashicorp/nomad/client/testutil" 19 "github.com/hashicorp/nomad/nomad/structs" 20 ) 21 22 var ( 23 osMountSharedDirSupport = map[string]bool{ 24 "darwin": true, 25 "linux": true, 26 } 27 28 t1 = &structs.Task{ 29 Name: "web", 30 Driver: "exec", 31 Config: map[string]interface{}{ 32 "command": "/bin/date", 33 "args": "+%s", 34 }, 35 Resources: &structs.Resources{ 36 DiskMB: 1, 37 }, 38 } 39 40 t2 = &structs.Task{ 41 Name: "web2", 42 Driver: "exec", 43 Config: map[string]interface{}{ 44 "command": "/bin/date", 45 "args": "+%s", 46 }, 47 Resources: &structs.Resources{ 48 DiskMB: 1, 49 }, 50 } 51 ) 52 53 // Test that given a set of tasks, each task gets a directory and that directory 54 // has the shared alloc dir inside of it. 55 func TestAllocDir_BuildAlloc(t *testing.T) { 56 tmp, err := ioutil.TempDir("", "AllocDir") 57 if err != nil { 58 t.Fatalf("Couldn't create temp dir: %v", err) 59 } 60 defer os.RemoveAll(tmp) 61 62 d := NewAllocDir(tmp) 63 defer d.Destroy() 64 tasks := []*structs.Task{t1, t2} 65 if err := d.Build(tasks); err != nil { 66 t.Fatalf("Build(%v) failed: %v", tasks, err) 67 } 68 69 // Check that the AllocDir and each of the task directories exist. 70 if _, err := os.Stat(d.AllocDir); os.IsNotExist(err) { 71 t.Fatalf("Build(%v) didn't create AllocDir %v", tasks, d.AllocDir) 72 } 73 74 for _, task := range tasks { 75 tDir, ok := d.TaskDirs[task.Name] 76 if !ok { 77 t.Fatalf("Task directory not found for %v", task.Name) 78 } 79 80 if _, err := os.Stat(tDir); os.IsNotExist(err) { 81 t.Fatalf("Build(%v) didn't create TaskDir %v", tasks, tDir) 82 } 83 84 if _, err := os.Stat(filepath.Join(tDir, TaskSecrets)); os.IsNotExist(err) { 85 t.Fatalf("Build(%v) didn't create secret dir %v", tasks) 86 } 87 } 88 } 89 90 func TestAllocDir_LogDir(t *testing.T) { 91 tmp, err := ioutil.TempDir("", "AllocDir") 92 if err != nil { 93 t.Fatalf("Couldn't create temp dir: %v", err) 94 } 95 defer os.RemoveAll(tmp) 96 97 d := NewAllocDir(tmp) 98 defer d.Destroy() 99 100 expected := filepath.Join(d.AllocDir, SharedAllocName, LogDirName) 101 if d.LogDir() != expected { 102 t.Fatalf("expected: %v, got: %v", expected, d.LogDir()) 103 } 104 } 105 106 func TestAllocDir_EmbedNonExistent(t *testing.T) { 107 tmp, err := ioutil.TempDir("", "AllocDir") 108 if err != nil { 109 t.Fatalf("Couldn't create temp dir: %v", err) 110 } 111 defer os.RemoveAll(tmp) 112 113 d := NewAllocDir(tmp) 114 defer d.Destroy() 115 tasks := []*structs.Task{t1, t2} 116 if err := d.Build(tasks); err != nil { 117 t.Fatalf("Build(%v) failed: %v", tasks, err) 118 } 119 120 fakeDir := "/foobarbaz" 121 task := tasks[0].Name 122 mapping := map[string]string{fakeDir: fakeDir} 123 if err := d.Embed(task, mapping); err != nil { 124 t.Fatalf("Embed(%v, %v) should should skip %v since it does not exist", task, mapping, fakeDir) 125 } 126 } 127 128 func TestAllocDir_EmbedDirs(t *testing.T) { 129 tmp, err := ioutil.TempDir("", "AllocDir") 130 if err != nil { 131 t.Fatalf("Couldn't create temp dir: %v", err) 132 } 133 defer os.RemoveAll(tmp) 134 135 d := NewAllocDir(tmp) 136 defer d.Destroy() 137 tasks := []*structs.Task{t1, t2} 138 if err := d.Build(tasks); err != nil { 139 t.Fatalf("Build(%v) failed: %v", tasks, err) 140 } 141 142 // Create a fake host directory, with a file, and a subfolder that contains 143 // a file. 144 host, err := ioutil.TempDir("", "AllocDirHost") 145 if err != nil { 146 t.Fatalf("Couldn't create temp dir: %v", err) 147 } 148 defer os.RemoveAll(host) 149 150 subDirName := "subdir" 151 subDir := filepath.Join(host, subDirName) 152 if err := os.MkdirAll(subDir, 0777); err != nil { 153 t.Fatalf("Failed to make subdir %v: %v", subDir, err) 154 } 155 156 file := "foo" 157 subFile := "bar" 158 if err := ioutil.WriteFile(filepath.Join(host, file), []byte{'a'}, 0777); err != nil { 159 t.Fatalf("Coudn't create file in host dir %v: %v", host, err) 160 } 161 162 if err := ioutil.WriteFile(filepath.Join(subDir, subFile), []byte{'a'}, 0777); err != nil { 163 t.Fatalf("Coudn't create file in host subdir %v: %v", subDir, err) 164 } 165 166 // Create mapping from host dir to task dir. 167 task := tasks[0].Name 168 taskDest := "bin/test/" 169 mapping := map[string]string{host: taskDest} 170 if err := d.Embed(task, mapping); err != nil { 171 t.Fatalf("Embed(%v, %v) failed: %v", task, mapping, err) 172 } 173 174 // Check that the embedding was done properly. 175 taskDir, ok := d.TaskDirs[task] 176 if !ok { 177 t.Fatalf("Task directory not found for %v", task) 178 } 179 180 exp := []string{filepath.Join(taskDir, taskDest, file), filepath.Join(taskDir, taskDest, subDirName, subFile)} 181 for _, e := range exp { 182 if _, err := os.Stat(e); os.IsNotExist(err) { 183 t.Fatalf("File %v not embeded: %v", e, err) 184 } 185 } 186 } 187 188 func TestAllocDir_MountSharedAlloc(t *testing.T) { 189 testutil.MountCompatible(t) 190 tmp, err := ioutil.TempDir("", "AllocDir") 191 if err != nil { 192 t.Fatalf("Couldn't create temp dir: %v", err) 193 } 194 defer os.RemoveAll(tmp) 195 196 d := NewAllocDir(tmp) 197 defer d.Destroy() 198 tasks := []*structs.Task{t1, t2} 199 if err := d.Build(tasks); err != nil { 200 t.Fatalf("Build(%v) failed: %v", tasks, err) 201 } 202 203 // Write a file to the shared dir. 204 exp := []byte{'f', 'o', 'o'} 205 file := "bar" 206 if err := ioutil.WriteFile(filepath.Join(d.SharedDir, file), exp, 0777); err != nil { 207 t.Fatalf("Couldn't write file to shared directory: %v", err) 208 } 209 210 for _, task := range tasks { 211 // Mount and then check that the file exists in the task directory. 212 if err := d.MountSharedDir(task.Name); err != nil { 213 if v, ok := osMountSharedDirSupport[runtime.GOOS]; v && ok { 214 t.Fatalf("MountSharedDir(%v) failed: %v", task.Name, err) 215 } else { 216 t.Skipf("MountShareDir(%v) failed, no OS support") 217 } 218 } 219 220 taskDir, ok := d.TaskDirs[task.Name] 221 if !ok { 222 t.Fatalf("Task directory not found for %v", task.Name) 223 } 224 225 taskFile := filepath.Join(taskDir, SharedAllocName, file) 226 act, err := ioutil.ReadFile(taskFile) 227 if err != nil { 228 t.Fatalf("Failed to read shared alloc file from task dir: %v", err) 229 } 230 231 if !reflect.DeepEqual(act, exp) { 232 t.Fatalf("Incorrect data read from task dir: want %v; got %v", exp, act) 233 } 234 } 235 } 236 237 func TestAllocDir_Snapshot(t *testing.T) { 238 tmp, err := ioutil.TempDir("", "AllocDir") 239 if err != nil { 240 t.Fatalf("Couldn't create temp dir: %v", err) 241 } 242 defer os.RemoveAll(tmp) 243 244 d := NewAllocDir(tmp) 245 defer d.Destroy() 246 247 tasks := []*structs.Task{t1, t2} 248 if err := d.Build(tasks); err != nil { 249 t.Fatalf("Build(%v) failed: %v", tasks, err) 250 } 251 252 dataDir := filepath.Join(d.SharedDir, "data") 253 taskDir := d.TaskDirs[t1.Name] 254 taskLocal := filepath.Join(taskDir, "local") 255 256 // Write a file to the shared dir. 257 exp := []byte{'f', 'o', 'o'} 258 file := "bar" 259 if err := ioutil.WriteFile(filepath.Join(dataDir, file), exp, 0777); err != nil { 260 t.Fatalf("Couldn't write file to shared directory: %v", err) 261 } 262 263 // Write a file to the task local 264 exp = []byte{'b', 'a', 'r'} 265 file1 := "lol" 266 if err := ioutil.WriteFile(filepath.Join(taskLocal, file1), exp, 0777); err != nil { 267 t.Fatalf("couldn't write to task local directory: %v", err) 268 } 269 270 var b bytes.Buffer 271 if err := d.Snapshot(&b); err != nil { 272 t.Fatalf("err: %v", err) 273 } 274 275 tr := tar.NewReader(&b) 276 var files []string 277 for { 278 hdr, err := tr.Next() 279 if err != nil && err != io.EOF { 280 t.Fatalf("err: %v", err) 281 } 282 if err == io.EOF { 283 break 284 } 285 if hdr.Typeflag == tar.TypeReg { 286 files = append(files, hdr.FileInfo().Name()) 287 } 288 } 289 290 if len(files) != 2 { 291 t.Fatalf("bad files: %#v", files) 292 } 293 } 294 295 func TestAllocDir_Move(t *testing.T) { 296 tmp1, err := ioutil.TempDir("", "AllocDir") 297 if err != nil { 298 t.Fatalf("Couldn't create temp dir: %v", err) 299 } 300 defer os.RemoveAll(tmp1) 301 302 tmp2, err := ioutil.TempDir("", "AllocDir") 303 if err != nil { 304 t.Fatalf("Couldn't create temp dir: %v", err) 305 } 306 defer os.RemoveAll(tmp2) 307 308 // Create two alloc dirs 309 d1 := NewAllocDir(tmp1) 310 defer d1.Destroy() 311 312 d2 := NewAllocDir(tmp2) 313 defer d2.Destroy() 314 315 tasks := []*structs.Task{t1, t2} 316 if err := d1.Build(tasks); err != nil { 317 t.Fatalf("Build(%v) failed: %v", tasks, err) 318 } 319 320 if err := d2.Build(tasks); err != nil { 321 t.Fatalf("Build(%v) failed: %v", tasks, err) 322 } 323 324 dataDir := filepath.Join(d1.SharedDir, "data") 325 taskDir := d1.TaskDirs[t1.Name] 326 taskLocal := filepath.Join(taskDir, "local") 327 328 // Write a file to the shared dir. 329 exp := []byte{'f', 'o', 'o'} 330 file := "bar" 331 if err := ioutil.WriteFile(filepath.Join(dataDir, file), exp, 0777); err != nil { 332 t.Fatalf("Couldn't write file to shared directory: %v", err) 333 } 334 335 // Write a file to the task local 336 exp = []byte{'b', 'a', 'r'} 337 file1 := "lol" 338 if err := ioutil.WriteFile(filepath.Join(taskLocal, file1), exp, 0777); err != nil { 339 t.Fatalf("couldn't write to task local directory: %v", err) 340 } 341 342 // Move the d1 allocdir to d2 343 if err := d2.Move(d1, []*structs.Task{t1, t2}); err != nil { 344 t.Fatalf("err: %v", err) 345 } 346 347 // Ensure the files in d1 are present in d2 348 fi, err := os.Stat(filepath.Join(d2.SharedDir, "data", "bar")) 349 if err != nil || fi == nil { 350 t.Fatalf("data dir was not moved") 351 } 352 353 fi, err = os.Stat(filepath.Join(d2.TaskDirs[t1.Name], "local", "lol")) 354 if err != nil || fi == nil { 355 t.Fatalf("task local dir was not moved") 356 } 357 } 358 359 func TestAllocDir_EscapeChecking(t *testing.T) { 360 tmp, err := ioutil.TempDir("", "AllocDir") 361 if err != nil { 362 t.Fatalf("Couldn't create temp dir: %v", err) 363 } 364 defer os.RemoveAll(tmp) 365 366 d := NewAllocDir(tmp) 367 defer d.Destroy() 368 tasks := []*structs.Task{t1, t2} 369 if err := d.Build(tasks); err != nil { 370 t.Fatalf("Build(%v) failed: %v", tasks, err) 371 } 372 373 // Check that issuing calls that escape the alloc dir returns errors 374 // List 375 if _, err := d.List(".."); err == nil || !strings.Contains(err.Error(), "escapes") { 376 t.Fatalf("List of escaping path didn't error: %v", err) 377 } 378 379 // Stat 380 if _, err := d.Stat("../foo"); err == nil || !strings.Contains(err.Error(), "escapes") { 381 t.Fatalf("Stat of escaping path didn't error: %v", err) 382 } 383 384 // ReadAt 385 if _, err := d.ReadAt("../foo", 0); err == nil || !strings.Contains(err.Error(), "escapes") { 386 t.Fatalf("ReadAt of escaping path didn't error: %v", err) 387 } 388 389 // BlockUntilExists 390 tomb := tomb.Tomb{} 391 if _, err := d.BlockUntilExists("../foo", &tomb); err == nil || !strings.Contains(err.Error(), "escapes") { 392 t.Fatalf("BlockUntilExists of escaping path didn't error: %v", err) 393 } 394 395 // ChangeEvents 396 if _, err := d.ChangeEvents("../foo", 0, &tomb); err == nil || !strings.Contains(err.Error(), "escapes") { 397 t.Fatalf("ChangeEvents of escaping path didn't error: %v", err) 398 } 399 } 400 401 func TestAllocDir_ReadAt_SecretDir(t *testing.T) { 402 tmp, err := ioutil.TempDir("", "AllocDir") 403 if err != nil { 404 t.Fatalf("Couldn't create temp dir: %v", err) 405 } 406 defer os.RemoveAll(tmp) 407 408 d := NewAllocDir(tmp) 409 defer d.Destroy() 410 tasks := []*structs.Task{t1, t2} 411 if err := d.Build(tasks); err != nil { 412 t.Fatalf("Build(%v) failed: %v", tasks, err) 413 } 414 415 // ReadAt of secret dir should fail 416 secret := filepath.Join(t1.Name, TaskSecrets, "test_file") 417 if _, err := d.ReadAt(secret, 0); err == nil || !strings.Contains(err.Error(), "secret file prohibited") { 418 t.Fatalf("ReadAt of secret file didn't error: %v", err) 419 } 420 } 421 422 func TestAllocDir_SplitPath(t *testing.T) { 423 dir, err := ioutil.TempDir("/tmp", "tmpdirtest") 424 if err != nil { 425 log.Fatal(err) 426 } 427 defer os.RemoveAll(dir) 428 429 dest := filepath.Join(dir, "/foo/bar/baz") 430 if err := os.MkdirAll(dest, os.ModePerm); err != nil { 431 t.Fatalf("err: %v", err) 432 } 433 434 d := NewAllocDir(dir) 435 defer d.Destroy() 436 437 info, err := d.splitPath(dest) 438 if err != nil { 439 t.Fatalf("err: %v", err) 440 } 441 if len(info) != 6 { 442 t.Fatalf("expected: %v, actual: %v", 6, len(info)) 443 } 444 } 445 446 func TestAllocDir_CreateDir(t *testing.T) { 447 dir, err := ioutil.TempDir("/tmp", "tmpdirtest") 448 if err != nil { 449 t.Fatalf("err: %v", err) 450 } 451 defer os.RemoveAll(dir) 452 453 // create a subdir and a file 454 subdir := filepath.Join(dir, "subdir") 455 if err := os.MkdirAll(subdir, 0760); err != nil { 456 t.Fatalf("err: %v", err) 457 } 458 subdirMode, err := os.Stat(subdir) 459 if err != nil { 460 t.Fatalf("err: %v", err) 461 } 462 463 // Create the above hierarchy under another destination 464 dir1, err := ioutil.TempDir("/tmp", "tempdirdest") 465 if err != nil { 466 t.Fatalf("err: %v", err) 467 } 468 469 d := NewAllocDir(dir) 470 defer d.Destroy() 471 472 if err := d.createDir(dir1, subdir); err != nil { 473 t.Fatalf("err: %v", err) 474 } 475 476 // Ensure that the subdir had the right perm 477 fi, err := os.Stat(filepath.Join(dir1, dir, "subdir")) 478 if err != nil { 479 t.Fatalf("err: %v", err) 480 } 481 if fi.Mode() != subdirMode.Mode() { 482 t.Fatalf("wrong file mode: %v, expected: %v", fi.Mode(), subdirMode.Mode()) 483 } 484 }