github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/client/task_runner_test.go (about) 1 package client 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "net/http" 8 "net/http/httptest" 9 "os" 10 "path/filepath" 11 "syscall" 12 "testing" 13 "time" 14 15 "github.com/hashicorp/nomad/client/allocdir" 16 "github.com/hashicorp/nomad/client/config" 17 "github.com/hashicorp/nomad/client/driver" 18 "github.com/hashicorp/nomad/client/vaultclient" 19 "github.com/hashicorp/nomad/nomad/mock" 20 "github.com/hashicorp/nomad/nomad/structs" 21 "github.com/hashicorp/nomad/testutil" 22 23 ctestutil "github.com/hashicorp/nomad/client/testutil" 24 ) 25 26 func testLogger() *log.Logger { 27 return prefixedTestLogger("") 28 } 29 30 func prefixedTestLogger(prefix string) *log.Logger { 31 return log.New(os.Stderr, prefix, log.LstdFlags) 32 } 33 34 type MockTaskStateUpdater struct { 35 state string 36 failed bool 37 events []*structs.TaskEvent 38 } 39 40 func (m *MockTaskStateUpdater) Update(name, state string, event *structs.TaskEvent) { 41 if state != "" { 42 m.state = state 43 } 44 if event != nil { 45 if event.FailsTask { 46 m.failed = true 47 } 48 m.events = append(m.events, event) 49 } 50 } 51 52 func testTaskRunner(restarts bool) (*MockTaskStateUpdater, *TaskRunner) { 53 return testTaskRunnerFromAlloc(restarts, mock.Alloc()) 54 } 55 56 // Creates a mock task runner using the first task in the first task group of 57 // the passed allocation. 58 func testTaskRunnerFromAlloc(restarts bool, alloc *structs.Allocation) (*MockTaskStateUpdater, *TaskRunner) { 59 logger := testLogger() 60 conf := config.DefaultConfig() 61 conf.StateDir = os.TempDir() 62 conf.AllocDir = os.TempDir() 63 upd := &MockTaskStateUpdater{} 64 task := alloc.Job.TaskGroups[0].Tasks[0] 65 // Initialize the port listing. This should be done by the offer process but 66 // we have a mock so that doesn't happen. 67 task.Resources.Networks[0].ReservedPorts = []structs.Port{{"", 80}} 68 69 allocDir := allocdir.NewAllocDir(filepath.Join(conf.AllocDir, alloc.ID)) 70 allocDir.Build([]*structs.Task{task}) 71 72 vclient := vaultclient.NewMockVaultClient() 73 ctx := driver.NewExecContext(allocDir, alloc.ID) 74 tr := NewTaskRunner(logger, conf, upd.Update, ctx, alloc, task, vclient) 75 if !restarts { 76 tr.restartTracker = noRestartsTracker() 77 } 78 return upd, tr 79 } 80 81 func TestTaskRunner_SimpleRun(t *testing.T) { 82 ctestutil.ExecCompatible(t) 83 upd, tr := testTaskRunner(false) 84 tr.MarkReceived() 85 go tr.Run() 86 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 87 defer tr.ctx.AllocDir.Destroy() 88 89 select { 90 case <-tr.WaitCh(): 91 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 92 t.Fatalf("timeout") 93 } 94 95 if len(upd.events) != 3 { 96 t.Fatalf("should have 3 updates: %#v", upd.events) 97 } 98 99 if upd.state != structs.TaskStateDead { 100 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 101 } 102 103 if upd.events[0].Type != structs.TaskReceived { 104 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 105 } 106 107 if upd.events[1].Type != structs.TaskStarted { 108 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 109 } 110 111 if upd.events[2].Type != structs.TaskTerminated { 112 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskTerminated) 113 } 114 } 115 116 func TestTaskRunner_Run_RecoverableStartError(t *testing.T) { 117 alloc := mock.Alloc() 118 task := alloc.Job.TaskGroups[0].Tasks[0] 119 task.Driver = "mock_driver" 120 task.Config = map[string]interface{}{ 121 "exit_code": 0, 122 "start_error": "driver failure", 123 "start_error_recoverable": true, 124 } 125 126 upd, tr := testTaskRunnerFromAlloc(true, alloc) 127 tr.MarkReceived() 128 go tr.Run() 129 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 130 defer tr.ctx.AllocDir.Destroy() 131 132 testutil.WaitForResult(func() (bool, error) { 133 if l := len(upd.events); l < 3 { 134 return false, fmt.Errorf("Expect at least three events; got %v", l) 135 } 136 137 if upd.events[0].Type != structs.TaskReceived { 138 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 139 } 140 141 if upd.events[1].Type != structs.TaskDriverFailure { 142 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskDriverFailure) 143 } 144 145 if upd.events[2].Type != structs.TaskRestarting { 146 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[2].Type, structs.TaskRestarting) 147 } 148 149 return true, nil 150 }, func(err error) { 151 t.Fatalf("err: %v", err) 152 }) 153 } 154 155 func TestTaskRunner_Destroy(t *testing.T) { 156 ctestutil.ExecCompatible(t) 157 upd, tr := testTaskRunner(true) 158 tr.MarkReceived() 159 defer tr.ctx.AllocDir.Destroy() 160 161 // Change command to ensure we run for a bit 162 tr.task.Config["command"] = "/bin/sleep" 163 tr.task.Config["args"] = []string{"1000"} 164 go tr.Run() 165 166 testutil.WaitForResult(func() (bool, error) { 167 if l := len(upd.events); l != 2 { 168 return false, fmt.Errorf("Expect two events; got %v", l) 169 } 170 171 if upd.events[0].Type != structs.TaskReceived { 172 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 173 } 174 175 if upd.events[1].Type != structs.TaskStarted { 176 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 177 } 178 179 return true, nil 180 }, func(err error) { 181 t.Fatalf("err: %v", err) 182 }) 183 184 // Make sure we are collecting afew stats 185 time.Sleep(2 * time.Second) 186 stats := tr.LatestResourceUsage() 187 if len(stats.Pids) == 0 || stats.ResourceUsage == nil || stats.ResourceUsage.MemoryStats.RSS == 0 { 188 t.Fatalf("expected task runner to have some stats") 189 } 190 191 // Begin the tear down 192 tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 193 194 select { 195 case <-tr.WaitCh(): 196 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 197 t.Fatalf("timeout") 198 } 199 200 if len(upd.events) != 4 { 201 t.Fatalf("should have 4 updates: %#v", upd.events) 202 } 203 204 if upd.state != structs.TaskStateDead { 205 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 206 } 207 208 if upd.events[2].Type != structs.TaskKilling { 209 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskKilling) 210 } 211 212 if upd.events[3].Type != structs.TaskKilled { 213 t.Fatalf("Third Event was %v; want %v", upd.events[3].Type, structs.TaskKilled) 214 } 215 } 216 217 func TestTaskRunner_Update(t *testing.T) { 218 ctestutil.ExecCompatible(t) 219 _, tr := testTaskRunner(false) 220 221 // Change command to ensure we run for a bit 222 tr.task.Config["command"] = "/bin/sleep" 223 tr.task.Config["args"] = []string{"100"} 224 go tr.Run() 225 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 226 defer tr.ctx.AllocDir.Destroy() 227 228 // Update the task definition 229 updateAlloc := tr.alloc.Copy() 230 231 // Update the restart policy 232 newTG := updateAlloc.Job.TaskGroups[0] 233 newMode := "foo" 234 newTG.RestartPolicy.Mode = newMode 235 236 newTask := updateAlloc.Job.TaskGroups[0].Tasks[0] 237 newTask.Driver = "foobar" 238 239 // Update the kill timeout 240 testutil.WaitForResult(func() (bool, error) { 241 if tr.handle == nil { 242 return false, fmt.Errorf("task not started") 243 } 244 return true, nil 245 }, func(err error) { 246 t.Fatalf("err: %v", err) 247 }) 248 249 oldHandle := tr.handle.ID() 250 newTask.KillTimeout = time.Hour 251 252 tr.Update(updateAlloc) 253 254 // Wait for update to take place 255 testutil.WaitForResult(func() (bool, error) { 256 if tr.task == newTask { 257 return false, fmt.Errorf("We copied the pointer! This would be very bad") 258 } 259 if tr.task.Driver != newTask.Driver { 260 return false, fmt.Errorf("Task not copied") 261 } 262 if tr.restartTracker.policy.Mode != newMode { 263 return false, fmt.Errorf("restart policy not updated") 264 } 265 if tr.handle.ID() == oldHandle { 266 return false, fmt.Errorf("handle not updated") 267 } 268 return true, nil 269 }, func(err error) { 270 t.Fatalf("err: %v", err) 271 }) 272 } 273 274 func TestTaskRunner_SaveRestoreState(t *testing.T) { 275 alloc := mock.Alloc() 276 task := alloc.Job.TaskGroups[0].Tasks[0] 277 task.Driver = "mock_driver" 278 task.Config = map[string]interface{}{ 279 "exit_code": "0", 280 "run_for": "5s", 281 } 282 283 // Give it a Vault token 284 task.Vault = &structs.Vault{Policies: []string{"default"}} 285 286 upd, tr := testTaskRunnerFromAlloc(false, alloc) 287 tr.MarkReceived() 288 go tr.Run() 289 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 290 291 // Wait for the task to be running and then snapshot the state 292 testutil.WaitForResult(func() (bool, error) { 293 if l := len(upd.events); l != 2 { 294 return false, fmt.Errorf("Expect two events; got %v", l) 295 } 296 297 if upd.events[0].Type != structs.TaskReceived { 298 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 299 } 300 301 if upd.events[1].Type != structs.TaskStarted { 302 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 303 } 304 305 return true, nil 306 }, func(err error) { 307 t.Fatalf("err: %v", err) 308 }) 309 310 if err := tr.SaveState(); err != nil { 311 t.Fatalf("err: %v", err) 312 } 313 314 // Read the token from the file system 315 secretDir, err := tr.ctx.AllocDir.GetSecretDir(task.Name) 316 if err != nil { 317 t.Fatalf("failed to determine task %s secret dir: %v", err) 318 } 319 320 tokenPath := filepath.Join(secretDir, vaultTokenFile) 321 data, err := ioutil.ReadFile(tokenPath) 322 if err != nil { 323 t.Fatalf("Failed to read file: %v", err) 324 } 325 token := string(data) 326 if len(token) == 0 { 327 t.Fatalf("Token not written to disk") 328 } 329 330 // Create a new task runner 331 tr2 := NewTaskRunner(tr.logger, tr.config, upd.Update, 332 tr.ctx, tr.alloc, &structs.Task{Name: tr.task.Name}, tr.vaultClient) 333 tr2.restartTracker = noRestartsTracker() 334 if err := tr2.RestoreState(); err != nil { 335 t.Fatalf("err: %v", err) 336 } 337 go tr2.Run() 338 defer tr2.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 339 340 // Destroy and wait 341 select { 342 case <-tr2.WaitCh(): 343 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 344 t.Fatalf("timeout") 345 } 346 347 // Check that we recovered the token 348 if act := tr2.vaultFuture.Get(); act != token { 349 t.Fatalf("Vault token not properly recovered") 350 } 351 } 352 353 func TestTaskRunner_Download_List(t *testing.T) { 354 ctestutil.ExecCompatible(t) 355 356 ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir(".")))) 357 defer ts.Close() 358 359 // Create an allocation that has a task with a list of artifacts. 360 alloc := mock.Alloc() 361 task := alloc.Job.TaskGroups[0].Tasks[0] 362 f1 := "task_runner_test.go" 363 f2 := "task_runner.go" 364 artifact1 := structs.TaskArtifact{ 365 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1), 366 } 367 artifact2 := structs.TaskArtifact{ 368 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f2), 369 } 370 task.Artifacts = []*structs.TaskArtifact{&artifact1, &artifact2} 371 372 upd, tr := testTaskRunnerFromAlloc(false, alloc) 373 tr.MarkReceived() 374 go tr.Run() 375 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 376 defer tr.ctx.AllocDir.Destroy() 377 378 select { 379 case <-tr.WaitCh(): 380 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 381 t.Fatalf("timeout") 382 } 383 384 if len(upd.events) != 4 { 385 t.Fatalf("should have 4 updates: %#v", upd.events) 386 } 387 388 if upd.state != structs.TaskStateDead { 389 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 390 } 391 392 if upd.events[0].Type != structs.TaskReceived { 393 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 394 } 395 396 if upd.events[1].Type != structs.TaskDownloadingArtifacts { 397 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskDownloadingArtifacts) 398 } 399 400 if upd.events[2].Type != structs.TaskStarted { 401 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskStarted) 402 } 403 404 if upd.events[3].Type != structs.TaskTerminated { 405 t.Fatalf("Fourth Event was %v; want %v", upd.events[3].Type, structs.TaskTerminated) 406 } 407 408 // Check that both files exist. 409 taskDir := tr.ctx.AllocDir.TaskDirs[task.Name] 410 if _, err := os.Stat(filepath.Join(taskDir, f1)); err != nil { 411 t.Fatalf("%v not downloaded", f1) 412 } 413 if _, err := os.Stat(filepath.Join(taskDir, f2)); err != nil { 414 t.Fatalf("%v not downloaded", f2) 415 } 416 } 417 418 func TestTaskRunner_Download_Retries(t *testing.T) { 419 ctestutil.ExecCompatible(t) 420 421 // Create an allocation that has a task with bad artifacts. 422 alloc := mock.Alloc() 423 task := alloc.Job.TaskGroups[0].Tasks[0] 424 artifact := structs.TaskArtifact{ 425 GetterSource: "http://127.1.1.111:12315/foo/bar/baz", 426 } 427 task.Artifacts = []*structs.TaskArtifact{&artifact} 428 429 // Make the restart policy try one update 430 alloc.Job.TaskGroups[0].RestartPolicy = &structs.RestartPolicy{ 431 Attempts: 1, 432 Interval: 10 * time.Minute, 433 Delay: 1 * time.Second, 434 Mode: structs.RestartPolicyModeFail, 435 } 436 437 upd, tr := testTaskRunnerFromAlloc(true, alloc) 438 tr.MarkReceived() 439 go tr.Run() 440 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 441 defer tr.ctx.AllocDir.Destroy() 442 443 select { 444 case <-tr.WaitCh(): 445 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 446 t.Fatalf("timeout") 447 } 448 449 if len(upd.events) != 7 { 450 t.Fatalf("should have 7 updates: %#v", upd.events) 451 } 452 453 if upd.state != structs.TaskStateDead { 454 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 455 } 456 457 if upd.events[0].Type != structs.TaskReceived { 458 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 459 } 460 461 if upd.events[1].Type != structs.TaskDownloadingArtifacts { 462 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskDownloadingArtifacts) 463 } 464 465 if upd.events[2].Type != structs.TaskArtifactDownloadFailed { 466 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskArtifactDownloadFailed) 467 } 468 469 if upd.events[3].Type != structs.TaskRestarting { 470 t.Fatalf("Fourth Event was %v; want %v", upd.events[3].Type, structs.TaskRestarting) 471 } 472 473 if upd.events[4].Type != structs.TaskDownloadingArtifacts { 474 t.Fatalf("Fifth Event was %v; want %v", upd.events[4].Type, structs.TaskDownloadingArtifacts) 475 } 476 477 if upd.events[5].Type != structs.TaskArtifactDownloadFailed { 478 t.Fatalf("Sixth Event was %v; want %v", upd.events[5].Type, structs.TaskArtifactDownloadFailed) 479 } 480 481 if upd.events[6].Type != structs.TaskNotRestarting { 482 t.Fatalf("Seventh Event was %v; want %v", upd.events[6].Type, structs.TaskNotRestarting) 483 } 484 } 485 486 func TestTaskRunner_Validate_UserEnforcement(t *testing.T) { 487 _, tr := testTaskRunner(false) 488 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 489 defer tr.ctx.AllocDir.Destroy() 490 491 if err := tr.setTaskEnv(); err != nil { 492 t.Fatalf("bad: %v", err) 493 } 494 495 // Try to run as root with exec. 496 tr.task.Driver = "exec" 497 tr.task.User = "root" 498 if err := tr.validateTask(); err == nil { 499 t.Fatalf("expected error running as root with exec") 500 } 501 502 // Try to run a non-blacklisted user with exec. 503 tr.task.Driver = "exec" 504 tr.task.User = "foobar" 505 if err := tr.validateTask(); err != nil { 506 t.Fatalf("unexpected error: %v", err) 507 } 508 509 // Try to run as root with docker. 510 tr.task.Driver = "docker" 511 tr.task.User = "root" 512 if err := tr.validateTask(); err != nil { 513 t.Fatalf("unexpected error: %v", err) 514 } 515 } 516 517 func TestTaskRunner_RestartTask(t *testing.T) { 518 alloc := mock.Alloc() 519 task := alloc.Job.TaskGroups[0].Tasks[0] 520 task.Driver = "mock_driver" 521 task.Config = map[string]interface{}{ 522 "exit_code": "0", 523 "run_for": "10s", 524 } 525 526 upd, tr := testTaskRunnerFromAlloc(true, alloc) 527 tr.MarkReceived() 528 go tr.Run() 529 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 530 defer tr.ctx.AllocDir.Destroy() 531 532 go func() { 533 time.Sleep(time.Duration(testutil.TestMultiplier()*300) * time.Millisecond) 534 tr.Restart("test", "restart") 535 time.Sleep(time.Duration(testutil.TestMultiplier()*300) * time.Millisecond) 536 tr.Kill("test", "restart", false) 537 }() 538 539 select { 540 case <-tr.WaitCh(): 541 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 542 t.Fatalf("timeout") 543 } 544 545 if len(upd.events) != 9 { 546 t.Fatalf("should have 9 updates: %#v", upd.events) 547 } 548 549 if upd.state != structs.TaskStateDead { 550 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 551 } 552 553 if upd.events[0].Type != structs.TaskReceived { 554 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 555 } 556 557 if upd.events[1].Type != structs.TaskStarted { 558 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 559 } 560 561 if upd.events[2].Type != structs.TaskRestartSignal { 562 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskRestartSignal) 563 } 564 565 if upd.events[3].Type != structs.TaskKilling { 566 t.Fatalf("Fourth Event was %v; want %v", upd.events[3].Type, structs.TaskKilling) 567 } 568 569 if upd.events[4].Type != structs.TaskKilled { 570 t.Fatalf("Fifth Event was %v; want %v", upd.events[4].Type, structs.TaskKilled) 571 } 572 573 t.Logf("%+v", upd.events[5]) 574 if upd.events[5].Type != structs.TaskRestarting { 575 t.Fatalf("Sixth Event was %v; want %v", upd.events[5].Type, structs.TaskRestarting) 576 } 577 578 if upd.events[6].Type != structs.TaskStarted { 579 t.Fatalf("Seventh Event was %v; want %v", upd.events[7].Type, structs.TaskStarted) 580 } 581 if upd.events[7].Type != structs.TaskKilling { 582 t.Fatalf("Eighth Event was %v; want %v", upd.events[7].Type, structs.TaskKilling) 583 } 584 585 if upd.events[8].Type != structs.TaskKilled { 586 t.Fatalf("Nineth Event was %v; want %v", upd.events[8].Type, structs.TaskKilled) 587 } 588 } 589 590 func TestTaskRunner_KillTask(t *testing.T) { 591 alloc := mock.Alloc() 592 task := alloc.Job.TaskGroups[0].Tasks[0] 593 task.Driver = "mock_driver" 594 task.Config = map[string]interface{}{ 595 "exit_code": "0", 596 "run_for": "10s", 597 } 598 599 upd, tr := testTaskRunnerFromAlloc(false, alloc) 600 tr.MarkReceived() 601 go tr.Run() 602 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 603 defer tr.ctx.AllocDir.Destroy() 604 605 go func() { 606 time.Sleep(100 * time.Millisecond) 607 tr.Kill("test", "kill", true) 608 }() 609 610 select { 611 case <-tr.WaitCh(): 612 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 613 t.Fatalf("timeout") 614 } 615 616 if len(upd.events) != 4 { 617 t.Fatalf("should have 4 updates: %#v", upd.events) 618 } 619 620 if upd.state != structs.TaskStateDead { 621 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 622 } 623 624 if !upd.failed { 625 t.Fatalf("TaskState should be failed: %+v", upd) 626 } 627 628 if upd.events[0].Type != structs.TaskReceived { 629 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 630 } 631 632 if upd.events[1].Type != structs.TaskStarted { 633 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 634 } 635 636 if upd.events[2].Type != structs.TaskKilling { 637 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskKilling) 638 } 639 640 if upd.events[3].Type != structs.TaskKilled { 641 t.Fatalf("Fourth Event was %v; want %v", upd.events[3].Type, structs.TaskKilled) 642 } 643 } 644 645 func TestTaskRunner_SignalFailure(t *testing.T) { 646 alloc := mock.Alloc() 647 task := alloc.Job.TaskGroups[0].Tasks[0] 648 task.Driver = "mock_driver" 649 task.Config = map[string]interface{}{ 650 "exit_code": "0", 651 "run_for": "10s", 652 "signal_error": "test forcing failure", 653 } 654 655 _, tr := testTaskRunnerFromAlloc(false, alloc) 656 tr.MarkReceived() 657 go tr.Run() 658 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 659 defer tr.ctx.AllocDir.Destroy() 660 661 time.Sleep(100 * time.Millisecond) 662 if err := tr.Signal("test", "test", syscall.SIGINT); err == nil { 663 t.Fatalf("Didn't receive error") 664 } 665 } 666 667 func TestTaskRunner_BlockForVault(t *testing.T) { 668 alloc := mock.Alloc() 669 task := alloc.Job.TaskGroups[0].Tasks[0] 670 task.Driver = "mock_driver" 671 task.Config = map[string]interface{}{ 672 "exit_code": "0", 673 "run_for": "1s", 674 } 675 task.Vault = &structs.Vault{Policies: []string{"default"}} 676 677 upd, tr := testTaskRunnerFromAlloc(false, alloc) 678 tr.MarkReceived() 679 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 680 defer tr.ctx.AllocDir.Destroy() 681 682 // Control when we get a Vault token 683 token := "1234" 684 waitCh := make(chan struct{}) 685 handler := func(*structs.Allocation, []string) (map[string]string, error) { 686 <-waitCh 687 return map[string]string{task.Name: token}, nil 688 } 689 tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler 690 691 go tr.Run() 692 693 select { 694 case <-tr.WaitCh(): 695 t.Fatalf("premature exit") 696 case <-time.After(1 * time.Second): 697 } 698 699 if len(upd.events) != 1 { 700 t.Fatalf("should have 1 updates: %#v", upd.events) 701 } 702 703 if upd.state != structs.TaskStatePending { 704 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStatePending) 705 } 706 707 if upd.events[0].Type != structs.TaskReceived { 708 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 709 } 710 711 // Unblock 712 close(waitCh) 713 714 select { 715 case <-tr.WaitCh(): 716 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 717 t.Fatalf("timeout") 718 } 719 720 if len(upd.events) != 3 { 721 t.Fatalf("should have 3 updates: %#v", upd.events) 722 } 723 724 if upd.state != structs.TaskStateDead { 725 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 726 } 727 728 if upd.events[0].Type != structs.TaskReceived { 729 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 730 } 731 732 if upd.events[1].Type != structs.TaskStarted { 733 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 734 } 735 736 if upd.events[2].Type != structs.TaskTerminated { 737 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskTerminated) 738 } 739 740 // Check that the token is on disk 741 secretDir, err := tr.ctx.AllocDir.GetSecretDir(task.Name) 742 if err != nil { 743 t.Fatalf("failed to determine task %s secret dir: %v", err) 744 } 745 746 // Read the token from the file system 747 tokenPath := filepath.Join(secretDir, vaultTokenFile) 748 data, err := ioutil.ReadFile(tokenPath) 749 if err != nil { 750 t.Fatalf("Failed to read file: %v", err) 751 } 752 753 if act := string(data); act != token { 754 t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token) 755 } 756 } 757 758 func TestTaskRunner_DeriveToken_Retry(t *testing.T) { 759 alloc := mock.Alloc() 760 task := alloc.Job.TaskGroups[0].Tasks[0] 761 task.Driver = "mock_driver" 762 task.Config = map[string]interface{}{ 763 "exit_code": "0", 764 "run_for": "1s", 765 } 766 task.Vault = &structs.Vault{Policies: []string{"default"}} 767 768 upd, tr := testTaskRunnerFromAlloc(false, alloc) 769 tr.MarkReceived() 770 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 771 defer tr.ctx.AllocDir.Destroy() 772 773 // Control when we get a Vault token 774 token := "1234" 775 count := 0 776 handler := func(*structs.Allocation, []string) (map[string]string, error) { 777 if count > 0 { 778 return map[string]string{task.Name: token}, nil 779 } 780 781 count++ 782 return nil, structs.NewRecoverableError(fmt.Errorf("Want a retry"), true) 783 } 784 tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler 785 go tr.Run() 786 787 select { 788 case <-tr.WaitCh(): 789 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 790 t.Fatalf("timeout") 791 } 792 793 if len(upd.events) != 3 { 794 t.Fatalf("should have 3 updates: %#v", upd.events) 795 } 796 797 if upd.state != structs.TaskStateDead { 798 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 799 } 800 801 if upd.events[0].Type != structs.TaskReceived { 802 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 803 } 804 805 if upd.events[1].Type != structs.TaskStarted { 806 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 807 } 808 809 if upd.events[2].Type != structs.TaskTerminated { 810 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskTerminated) 811 } 812 813 // Check that the token is on disk 814 secretDir, err := tr.ctx.AllocDir.GetSecretDir(task.Name) 815 if err != nil { 816 t.Fatalf("failed to determine task %s secret dir: %v", err) 817 } 818 819 // Read the token from the file system 820 tokenPath := filepath.Join(secretDir, vaultTokenFile) 821 data, err := ioutil.ReadFile(tokenPath) 822 if err != nil { 823 t.Fatalf("Failed to read file: %v", err) 824 } 825 826 if act := string(data); act != token { 827 t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token) 828 } 829 } 830 831 func TestTaskRunner_DeriveToken_Unrecoverable(t *testing.T) { 832 alloc := mock.Alloc() 833 task := alloc.Job.TaskGroups[0].Tasks[0] 834 task.Driver = "mock_driver" 835 task.Config = map[string]interface{}{ 836 "exit_code": "0", 837 "run_for": "10s", 838 } 839 task.Vault = &structs.Vault{ 840 Policies: []string{"default"}, 841 ChangeMode: structs.VaultChangeModeRestart, 842 } 843 844 upd, tr := testTaskRunnerFromAlloc(false, alloc) 845 tr.MarkReceived() 846 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 847 defer tr.ctx.AllocDir.Destroy() 848 849 // Error the token derivation 850 vc := tr.vaultClient.(*vaultclient.MockVaultClient) 851 vc.SetDeriveTokenError(alloc.ID, []string{task.Name}, fmt.Errorf("Non recoverable")) 852 go tr.Run() 853 854 // Wait for the task to start 855 testutil.WaitForResult(func() (bool, error) { 856 if l := len(upd.events); l != 2 { 857 return false, fmt.Errorf("Expect two events; got %v", l) 858 } 859 860 if upd.events[0].Type != structs.TaskReceived { 861 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 862 } 863 864 if upd.events[1].Type != structs.TaskKilling { 865 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskKilling) 866 } 867 868 return true, nil 869 }, func(err error) { 870 t.Fatalf("err: %v", err) 871 }) 872 } 873 874 func TestTaskRunner_Template_Block(t *testing.T) { 875 alloc := mock.Alloc() 876 task := alloc.Job.TaskGroups[0].Tasks[0] 877 task.Driver = "mock_driver" 878 task.Config = map[string]interface{}{ 879 "exit_code": "0", 880 "run_for": "1s", 881 } 882 task.Templates = []*structs.Template{ 883 { 884 EmbeddedTmpl: "{{key \"foo\"}}", 885 DestPath: "local/test", 886 ChangeMode: structs.TemplateChangeModeNoop, 887 }, 888 } 889 890 upd, tr := testTaskRunnerFromAlloc(false, alloc) 891 tr.MarkReceived() 892 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 893 defer tr.ctx.AllocDir.Destroy() 894 895 go tr.Run() 896 897 select { 898 case <-tr.WaitCh(): 899 t.Fatalf("premature exit") 900 case <-time.After(1 * time.Second): 901 } 902 903 if len(upd.events) != 1 { 904 t.Fatalf("should have 1 updates: %#v", upd.events) 905 } 906 907 if upd.state != structs.TaskStatePending { 908 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStatePending) 909 } 910 911 if upd.events[0].Type != structs.TaskReceived { 912 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 913 } 914 915 // Unblock 916 tr.UnblockStart("test") 917 918 select { 919 case <-tr.WaitCh(): 920 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 921 t.Fatalf("timeout") 922 } 923 924 if len(upd.events) != 3 { 925 t.Fatalf("should have 3 updates: %#v", upd.events) 926 } 927 928 if upd.state != structs.TaskStateDead { 929 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 930 } 931 932 if upd.events[0].Type != structs.TaskReceived { 933 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 934 } 935 936 if upd.events[1].Type != structs.TaskStarted { 937 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 938 } 939 940 if upd.events[2].Type != structs.TaskTerminated { 941 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskTerminated) 942 } 943 } 944 945 func TestTaskRunner_Template_Artifact(t *testing.T) { 946 dir, err := os.Getwd() 947 if err != nil { 948 t.Fatal("bad: %v", err) 949 } 950 951 ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(dir, "..")))) 952 defer ts.Close() 953 954 alloc := mock.Alloc() 955 task := alloc.Job.TaskGroups[0].Tasks[0] 956 task.Driver = "mock_driver" 957 task.Config = map[string]interface{}{ 958 "exit_code": "0", 959 "run_for": "1s", 960 } 961 // Create an allocation that has a task that renders a template from an 962 // artifact 963 f1 := "CHANGELOG.md" 964 artifact := structs.TaskArtifact{ 965 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1), 966 } 967 task.Artifacts = []*structs.TaskArtifact{&artifact} 968 task.Templates = []*structs.Template{ 969 { 970 SourcePath: "CHANGELOG.md", 971 DestPath: "local/test", 972 ChangeMode: structs.TemplateChangeModeNoop, 973 }, 974 } 975 976 upd, tr := testTaskRunnerFromAlloc(false, alloc) 977 tr.MarkReceived() 978 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 979 defer tr.ctx.AllocDir.Destroy() 980 981 go tr.Run() 982 983 select { 984 case <-tr.WaitCh(): 985 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 986 t.Fatalf("timeout") 987 } 988 989 if len(upd.events) != 4 { 990 t.Fatalf("should have 4 updates: %#v", upd.events) 991 } 992 993 if upd.state != structs.TaskStateDead { 994 t.Fatalf("TaskState %v; want %v", upd.state, structs.TaskStateDead) 995 } 996 997 if upd.events[0].Type != structs.TaskReceived { 998 t.Fatalf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 999 } 1000 1001 if upd.events[1].Type != structs.TaskDownloadingArtifacts { 1002 t.Fatalf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskDownloadingArtifacts) 1003 } 1004 1005 if upd.events[2].Type != structs.TaskStarted { 1006 t.Fatalf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskStarted) 1007 } 1008 1009 if upd.events[3].Type != structs.TaskTerminated { 1010 t.Fatalf("Fourth Event was %v; want %v", upd.events[3].Type, structs.TaskTerminated) 1011 } 1012 1013 // Check that both files exist. 1014 taskDir := tr.ctx.AllocDir.TaskDirs[task.Name] 1015 if _, err := os.Stat(filepath.Join(taskDir, f1)); err != nil { 1016 t.Fatalf("%v not downloaded", f1) 1017 } 1018 if _, err := os.Stat(filepath.Join(taskDir, allocdir.TaskLocal, "test")); err != nil { 1019 t.Fatalf("template not rendered") 1020 } 1021 } 1022 1023 func TestTaskRunner_Template_NewVaultToken(t *testing.T) { 1024 alloc := mock.Alloc() 1025 task := alloc.Job.TaskGroups[0].Tasks[0] 1026 task.Driver = "mock_driver" 1027 task.Config = map[string]interface{}{ 1028 "exit_code": "0", 1029 "run_for": "1s", 1030 } 1031 task.Templates = []*structs.Template{ 1032 { 1033 EmbeddedTmpl: "{{key \"foo\"}}", 1034 DestPath: "local/test", 1035 ChangeMode: structs.TemplateChangeModeNoop, 1036 }, 1037 } 1038 task.Vault = &structs.Vault{Policies: []string{"default"}} 1039 1040 _, tr := testTaskRunnerFromAlloc(false, alloc) 1041 tr.MarkReceived() 1042 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 1043 defer tr.ctx.AllocDir.Destroy() 1044 go tr.Run() 1045 1046 // Wait for a Vault token 1047 var token string 1048 testutil.WaitForResult(func() (bool, error) { 1049 if token = tr.vaultFuture.Get(); token == "" { 1050 return false, fmt.Errorf("No Vault token") 1051 } 1052 1053 return true, nil 1054 }, func(err error) { 1055 t.Fatalf("err: %v", err) 1056 }) 1057 1058 // Error the token renewal 1059 vc := tr.vaultClient.(*vaultclient.MockVaultClient) 1060 renewalCh, ok := vc.RenewTokens[token] 1061 if !ok { 1062 t.Fatalf("no renewal channel") 1063 } 1064 1065 originalManager := tr.templateManager 1066 1067 renewalCh <- fmt.Errorf("Test killing") 1068 close(renewalCh) 1069 1070 // Wait for a new Vault token 1071 var token2 string 1072 testutil.WaitForResult(func() (bool, error) { 1073 if token2 = tr.vaultFuture.Get(); token2 == "" || token2 == token { 1074 return false, fmt.Errorf("No new Vault token") 1075 } 1076 1077 if originalManager == tr.templateManager { 1078 return false, fmt.Errorf("Template manager not updated") 1079 } 1080 1081 return true, nil 1082 }, func(err error) { 1083 t.Fatalf("err: %v", err) 1084 }) 1085 } 1086 1087 func TestTaskRunner_VaultManager_Restart(t *testing.T) { 1088 alloc := mock.Alloc() 1089 task := alloc.Job.TaskGroups[0].Tasks[0] 1090 task.Driver = "mock_driver" 1091 task.Config = map[string]interface{}{ 1092 "exit_code": "0", 1093 "run_for": "10s", 1094 } 1095 task.Vault = &structs.Vault{ 1096 Policies: []string{"default"}, 1097 ChangeMode: structs.VaultChangeModeRestart, 1098 } 1099 1100 upd, tr := testTaskRunnerFromAlloc(false, alloc) 1101 tr.MarkReceived() 1102 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 1103 defer tr.ctx.AllocDir.Destroy() 1104 go tr.Run() 1105 1106 // Wait for the task to start 1107 testutil.WaitForResult(func() (bool, error) { 1108 if l := len(upd.events); l != 2 { 1109 return false, fmt.Errorf("Expect two events; got %v", l) 1110 } 1111 1112 if upd.events[0].Type != structs.TaskReceived { 1113 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 1114 } 1115 1116 if upd.events[1].Type != structs.TaskStarted { 1117 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 1118 } 1119 1120 return true, nil 1121 }, func(err error) { 1122 t.Fatalf("err: %v", err) 1123 }) 1124 1125 // Error the token renewal 1126 vc := tr.vaultClient.(*vaultclient.MockVaultClient) 1127 renewalCh, ok := vc.RenewTokens[tr.vaultFuture.Get()] 1128 if !ok { 1129 t.Fatalf("no renewal channel") 1130 } 1131 1132 renewalCh <- fmt.Errorf("Test killing") 1133 close(renewalCh) 1134 1135 // Ensure a restart 1136 testutil.WaitForResult(func() (bool, error) { 1137 if l := len(upd.events); l != 7 { 1138 return false, fmt.Errorf("Expect seven events; got %#v", upd.events) 1139 } 1140 1141 if upd.events[0].Type != structs.TaskReceived { 1142 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 1143 } 1144 1145 if upd.events[1].Type != structs.TaskStarted { 1146 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 1147 } 1148 1149 if upd.events[2].Type != structs.TaskRestartSignal { 1150 return false, fmt.Errorf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskRestartSignal) 1151 } 1152 1153 if upd.events[3].Type != structs.TaskKilling { 1154 return false, fmt.Errorf("Fourth Event was %v; want %v", upd.events[3].Type, structs.TaskKilling) 1155 } 1156 1157 if upd.events[4].Type != structs.TaskKilled { 1158 return false, fmt.Errorf("Fifth Event was %v; want %v", upd.events[4].Type, structs.TaskKilled) 1159 } 1160 1161 if upd.events[5].Type != structs.TaskRestarting { 1162 return false, fmt.Errorf("Sixth Event was %v; want %v", upd.events[5].Type, structs.TaskRestarting) 1163 } 1164 1165 if upd.events[6].Type != structs.TaskStarted { 1166 return false, fmt.Errorf("Seventh Event was %v; want %v", upd.events[6].Type, structs.TaskStarted) 1167 } 1168 1169 return true, nil 1170 }, func(err error) { 1171 t.Fatalf("err: %v", err) 1172 }) 1173 } 1174 1175 func TestTaskRunner_VaultManager_Signal(t *testing.T) { 1176 alloc := mock.Alloc() 1177 task := alloc.Job.TaskGroups[0].Tasks[0] 1178 task.Driver = "mock_driver" 1179 task.Config = map[string]interface{}{ 1180 "exit_code": "0", 1181 "run_for": "10s", 1182 } 1183 task.Vault = &structs.Vault{ 1184 Policies: []string{"default"}, 1185 ChangeMode: structs.VaultChangeModeSignal, 1186 ChangeSignal: "SIGUSR1", 1187 } 1188 1189 upd, tr := testTaskRunnerFromAlloc(false, alloc) 1190 tr.MarkReceived() 1191 defer tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 1192 defer tr.ctx.AllocDir.Destroy() 1193 go tr.Run() 1194 1195 // Wait for the task to start 1196 testutil.WaitForResult(func() (bool, error) { 1197 if l := len(upd.events); l != 2 { 1198 return false, fmt.Errorf("Expect two events; got %v", l) 1199 } 1200 1201 if upd.events[0].Type != structs.TaskReceived { 1202 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 1203 } 1204 1205 if upd.events[1].Type != structs.TaskStarted { 1206 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 1207 } 1208 1209 return true, nil 1210 }, func(err error) { 1211 t.Fatalf("err: %v", err) 1212 }) 1213 1214 // Error the token renewal 1215 vc := tr.vaultClient.(*vaultclient.MockVaultClient) 1216 renewalCh, ok := vc.RenewTokens[tr.vaultFuture.Get()] 1217 if !ok { 1218 t.Fatalf("no renewal channel") 1219 } 1220 1221 renewalCh <- fmt.Errorf("Test killing") 1222 close(renewalCh) 1223 1224 // Ensure a restart 1225 testutil.WaitForResult(func() (bool, error) { 1226 if l := len(upd.events); l != 3 { 1227 return false, fmt.Errorf("Expect three events; got %#v", upd.events) 1228 } 1229 1230 if upd.events[0].Type != structs.TaskReceived { 1231 return false, fmt.Errorf("First Event was %v; want %v", upd.events[0].Type, structs.TaskReceived) 1232 } 1233 1234 if upd.events[1].Type != structs.TaskStarted { 1235 return false, fmt.Errorf("Second Event was %v; want %v", upd.events[1].Type, structs.TaskStarted) 1236 } 1237 1238 if upd.events[2].Type != structs.TaskSignaling { 1239 return false, fmt.Errorf("Third Event was %v; want %v", upd.events[2].Type, structs.TaskSignaling) 1240 } 1241 1242 return true, nil 1243 }, func(err error) { 1244 t.Fatalf("err: %v", err) 1245 }) 1246 }