github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/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 "reflect" 12 "syscall" 13 "testing" 14 "time" 15 16 "github.com/golang/snappy" 17 "github.com/ncodes/nomad/client/allocdir" 18 "github.com/ncodes/nomad/client/config" 19 cstructs "github.com/ncodes/nomad/client/structs" 20 "github.com/ncodes/nomad/client/vaultclient" 21 "github.com/ncodes/nomad/nomad/mock" 22 "github.com/ncodes/nomad/nomad/structs" 23 "github.com/ncodes/nomad/testutil" 24 25 ctestutil "github.com/ncodes/nomad/client/testutil" 26 ) 27 28 func testLogger() *log.Logger { 29 return prefixedTestLogger("") 30 } 31 32 func prefixedTestLogger(prefix string) *log.Logger { 33 return log.New(os.Stderr, prefix, log.LstdFlags) 34 } 35 36 type MockTaskStateUpdater struct { 37 state string 38 failed bool 39 events []*structs.TaskEvent 40 } 41 42 func (m *MockTaskStateUpdater) Update(name, state string, event *structs.TaskEvent) { 43 if state != "" { 44 m.state = state 45 } 46 if event != nil { 47 if event.FailsTask { 48 m.failed = true 49 } 50 m.events = append(m.events, event) 51 } 52 } 53 54 type taskRunnerTestCtx struct { 55 upd *MockTaskStateUpdater 56 tr *TaskRunner 57 allocDir *allocdir.AllocDir 58 } 59 60 // Cleanup calls Destroy on the task runner and alloc dir 61 func (ctx *taskRunnerTestCtx) Cleanup() { 62 ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 63 ctx.allocDir.Destroy() 64 } 65 66 func testTaskRunner(t *testing.T, restarts bool) *taskRunnerTestCtx { 67 return testTaskRunnerFromAlloc(t, restarts, mock.Alloc()) 68 } 69 70 // Creates a mock task runner using the first task in the first task group of 71 // the passed allocation. 72 // 73 // Callers should defer Cleanup() to cleanup after completion 74 func testTaskRunnerFromAlloc(t *testing.T, restarts bool, alloc *structs.Allocation) *taskRunnerTestCtx { 75 logger := testLogger() 76 conf := config.DefaultConfig() 77 conf.StateDir = os.TempDir() 78 conf.AllocDir = os.TempDir() 79 upd := &MockTaskStateUpdater{} 80 task := alloc.Job.TaskGroups[0].Tasks[0] 81 // Initialize the port listing. This should be done by the offer process but 82 // we have a mock so that doesn't happen. 83 task.Resources.Networks[0].ReservedPorts = []structs.Port{{Label: "", Value: 80}} 84 85 allocDir := allocdir.NewAllocDir(testLogger(), filepath.Join(conf.AllocDir, alloc.ID)) 86 if err := allocDir.Build(); err != nil { 87 t.Fatalf("error building alloc dir: %v", err) 88 return nil 89 } 90 91 //HACK to get FSIsolation and chroot without using AllocRunner, 92 // TaskRunner, or Drivers 93 fsi := cstructs.FSIsolationImage 94 switch task.Driver { 95 case "raw_exec": 96 fsi = cstructs.FSIsolationNone 97 case "exec", "java": 98 fsi = cstructs.FSIsolationChroot 99 } 100 taskDir := allocDir.NewTaskDir(task.Name) 101 if err := taskDir.Build(false, config.DefaultChrootEnv, fsi); err != nil { 102 t.Fatalf("error building task dir %q: %v", task.Name, err) 103 return nil 104 } 105 106 vclient := vaultclient.NewMockVaultClient() 107 tr := NewTaskRunner(logger, conf, upd.Update, taskDir, alloc, task, vclient) 108 if !restarts { 109 tr.restartTracker = noRestartsTracker() 110 } 111 return &taskRunnerTestCtx{upd, tr, allocDir} 112 } 113 114 // testWaitForTaskToStart waits for the task to or fails the test 115 func testWaitForTaskToStart(t *testing.T, ctx *taskRunnerTestCtx) { 116 // Wait for the task to start 117 testutil.WaitForResult(func() (bool, error) { 118 l := len(ctx.upd.events) 119 if l < 2 { 120 return false, fmt.Errorf("Expect two events; got %v", l) 121 } 122 123 if ctx.upd.events[0].Type != structs.TaskReceived { 124 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 125 } 126 127 if l >= 3 { 128 if ctx.upd.events[1].Type != structs.TaskSetup { 129 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 130 } 131 if ctx.upd.events[2].Type != structs.TaskStarted { 132 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 133 } 134 } else { 135 if ctx.upd.events[1].Type != structs.TaskStarted { 136 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskStarted) 137 } 138 } 139 140 return true, nil 141 }, func(err error) { 142 t.Fatalf("err: %v", err) 143 }) 144 } 145 146 func TestTaskRunner_SimpleRun(t *testing.T) { 147 ctestutil.ExecCompatible(t) 148 ctx := testTaskRunner(t, false) 149 ctx.tr.MarkReceived() 150 go ctx.tr.Run() 151 defer ctx.Cleanup() 152 153 select { 154 case <-ctx.tr.WaitCh(): 155 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 156 t.Fatalf("timeout") 157 } 158 159 if len(ctx.upd.events) != 4 { 160 t.Fatalf("should have 3 ctx.updates: %#v", ctx.upd.events) 161 } 162 163 if ctx.upd.state != structs.TaskStateDead { 164 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 165 } 166 167 if ctx.upd.events[0].Type != structs.TaskReceived { 168 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 169 } 170 171 if ctx.upd.events[1].Type != structs.TaskSetup { 172 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 173 } 174 175 if ctx.upd.events[2].Type != structs.TaskStarted { 176 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 177 } 178 179 if ctx.upd.events[3].Type != structs.TaskTerminated { 180 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 181 } 182 } 183 184 func TestTaskRunner_Run_RecoverableStartError(t *testing.T) { 185 alloc := mock.Alloc() 186 task := alloc.Job.TaskGroups[0].Tasks[0] 187 task.Driver = "mock_driver" 188 task.Config = map[string]interface{}{ 189 "exit_code": 0, 190 "start_error": "driver failure", 191 "start_error_recoverable": true, 192 } 193 194 ctx := testTaskRunnerFromAlloc(t, true, alloc) 195 ctx.tr.MarkReceived() 196 go ctx.tr.Run() 197 defer ctx.Cleanup() 198 199 testutil.WaitForResult(func() (bool, error) { 200 if l := len(ctx.upd.events); l < 4 { 201 return false, fmt.Errorf("Expect at least four events; got %v", l) 202 } 203 204 if ctx.upd.events[0].Type != structs.TaskReceived { 205 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 206 } 207 208 if ctx.upd.events[1].Type != structs.TaskSetup { 209 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 210 } 211 212 if ctx.upd.events[2].Type != structs.TaskDriverFailure { 213 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDriverFailure) 214 } 215 216 if ctx.upd.events[3].Type != structs.TaskRestarting { 217 return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestarting) 218 } 219 220 return true, nil 221 }, func(err error) { 222 t.Fatalf("err: %v", err) 223 }) 224 } 225 226 func TestTaskRunner_Destroy(t *testing.T) { 227 ctestutil.ExecCompatible(t) 228 ctx := testTaskRunner(t, true) 229 ctx.tr.MarkReceived() 230 //FIXME This didn't used to send a kill status update!!!??? 231 defer ctx.Cleanup() 232 233 // Change command to ensure we run for a bit 234 ctx.tr.task.Config["command"] = "/bin/sleep" 235 ctx.tr.task.Config["args"] = []string{"1000"} 236 go ctx.tr.Run() 237 238 // Wait for the task to start 239 testWaitForTaskToStart(t, ctx) 240 241 // Make sure we are collecting a few stats 242 time.Sleep(2 * time.Second) 243 stats := ctx.tr.LatestResourceUsage() 244 if len(stats.Pids) == 0 || stats.ResourceUsage == nil || stats.ResourceUsage.MemoryStats.RSS == 0 { 245 t.Fatalf("expected task runner to have some stats") 246 } 247 248 // Begin the tear down 249 ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 250 251 select { 252 case <-ctx.tr.WaitCh(): 253 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 254 t.Fatalf("timeout") 255 } 256 257 if len(ctx.upd.events) != 5 { 258 t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events) 259 } 260 261 if ctx.upd.state != structs.TaskStateDead { 262 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 263 } 264 265 if ctx.upd.events[3].Type != structs.TaskKilling { 266 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskKilling) 267 } 268 269 if ctx.upd.events[4].Type != structs.TaskKilled { 270 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilled) 271 } 272 } 273 274 func TestTaskRunner_Update(t *testing.T) { 275 ctestutil.ExecCompatible(t) 276 ctx := testTaskRunner(t, false) 277 278 // Change command to ensure we run for a bit 279 ctx.tr.task.Config["command"] = "/bin/sleep" 280 ctx.tr.task.Config["args"] = []string{"100"} 281 go ctx.tr.Run() 282 defer ctx.Cleanup() 283 284 // Update the task definition 285 updateAlloc := ctx.tr.alloc.Copy() 286 287 // Update the restart policy 288 newTG := updateAlloc.Job.TaskGroups[0] 289 newMode := "foo" 290 newTG.RestartPolicy.Mode = newMode 291 292 newTask := updateAlloc.Job.TaskGroups[0].Tasks[0] 293 newTask.Driver = "foobar" 294 295 // Update the kill timeout 296 testutil.WaitForResult(func() (bool, error) { 297 if ctx.tr.handle == nil { 298 return false, fmt.Errorf("task not started") 299 } 300 return true, nil 301 }, func(err error) { 302 t.Fatalf("err: %v", err) 303 }) 304 305 oldHandle := ctx.tr.handle.ID() 306 newTask.KillTimeout = time.Hour 307 308 ctx.tr.Update(updateAlloc) 309 310 // Wait for ctx.update to take place 311 testutil.WaitForResult(func() (bool, error) { 312 if ctx.tr.task == newTask { 313 return false, fmt.Errorf("We copied the pointer! This would be very bad") 314 } 315 if ctx.tr.task.Driver != newTask.Driver { 316 return false, fmt.Errorf("Task not copied") 317 } 318 if ctx.tr.restartTracker.policy.Mode != newMode { 319 return false, fmt.Errorf("restart policy not ctx.updated") 320 } 321 if ctx.tr.handle.ID() == oldHandle { 322 return false, fmt.Errorf("handle not ctx.updated") 323 } 324 return true, nil 325 }, func(err error) { 326 t.Fatalf("err: %v", err) 327 }) 328 } 329 330 func TestTaskRunner_SaveRestoreState(t *testing.T) { 331 alloc := mock.Alloc() 332 task := alloc.Job.TaskGroups[0].Tasks[0] 333 task.Driver = "mock_driver" 334 task.Config = map[string]interface{}{ 335 "exit_code": "0", 336 "run_for": "5s", 337 } 338 339 // Give it a Vault token 340 task.Vault = &structs.Vault{Policies: []string{"default"}} 341 342 ctx := testTaskRunnerFromAlloc(t, false, alloc) 343 ctx.tr.MarkReceived() 344 go ctx.tr.Run() 345 //FIXME This test didn't used to defer destroy the allocidr ???!!! 346 defer ctx.Cleanup() 347 348 // Wait for the task to be running and then snapshot the state 349 testWaitForTaskToStart(t, ctx) 350 351 if err := ctx.tr.SaveState(); err != nil { 352 t.Fatalf("err: %v", err) 353 } 354 355 // Read the token from the file system 356 tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile) 357 data, err := ioutil.ReadFile(tokenPath) 358 if err != nil { 359 t.Fatalf("Failed to read file: %v", err) 360 } 361 token := string(data) 362 if len(token) == 0 { 363 t.Fatalf("Token not written to disk") 364 } 365 366 // Create a new task runner 367 task2 := &structs.Task{Name: ctx.tr.task.Name, Driver: ctx.tr.task.Driver} 368 tr2 := NewTaskRunner(ctx.tr.logger, ctx.tr.config, ctx.upd.Update, 369 ctx.tr.taskDir, ctx.tr.alloc, task2, ctx.tr.vaultClient) 370 tr2.restartTracker = noRestartsTracker() 371 if err := tr2.RestoreState(); err != nil { 372 t.Fatalf("err: %v", err) 373 } 374 go tr2.Run() 375 defer tr2.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 376 377 // Destroy and wait 378 select { 379 case <-tr2.WaitCh(): 380 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 381 t.Fatalf("timeout") 382 } 383 384 // Check that we recovered the token 385 if act := tr2.vaultFuture.Get(); act != token { 386 t.Fatalf("Vault token not properly recovered") 387 } 388 } 389 390 func TestTaskRunner_Download_List(t *testing.T) { 391 ctestutil.ExecCompatible(t) 392 393 ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir(".")))) 394 defer ts.Close() 395 396 // Create an allocation that has a task with a list of artifacts. 397 alloc := mock.Alloc() 398 task := alloc.Job.TaskGroups[0].Tasks[0] 399 f1 := "task_runner_test.go" 400 f2 := "task_runner.go" 401 artifact1 := structs.TaskArtifact{ 402 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1), 403 } 404 artifact2 := structs.TaskArtifact{ 405 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f2), 406 } 407 task.Artifacts = []*structs.TaskArtifact{&artifact1, &artifact2} 408 409 ctx := testTaskRunnerFromAlloc(t, false, alloc) 410 ctx.tr.MarkReceived() 411 go ctx.tr.Run() 412 defer ctx.Cleanup() 413 414 select { 415 case <-ctx.tr.WaitCh(): 416 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 417 t.Fatalf("timeout") 418 } 419 420 if len(ctx.upd.events) != 5 { 421 t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events) 422 } 423 424 if ctx.upd.state != structs.TaskStateDead { 425 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 426 } 427 428 if ctx.upd.events[0].Type != structs.TaskReceived { 429 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 430 } 431 432 if ctx.upd.events[1].Type != structs.TaskSetup { 433 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 434 } 435 436 if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts { 437 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts) 438 } 439 440 if ctx.upd.events[3].Type != structs.TaskStarted { 441 t.Fatalf("Forth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskStarted) 442 } 443 444 if ctx.upd.events[4].Type != structs.TaskTerminated { 445 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskTerminated) 446 } 447 448 // Check that both files exist. 449 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f1)); err != nil { 450 t.Fatalf("%v not downloaded", f1) 451 } 452 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f2)); err != nil { 453 t.Fatalf("%v not downloaded", f2) 454 } 455 } 456 457 func TestTaskRunner_Download_Retries(t *testing.T) { 458 ctestutil.ExecCompatible(t) 459 460 // Create an allocation that has a task with bad artifacts. 461 alloc := mock.Alloc() 462 task := alloc.Job.TaskGroups[0].Tasks[0] 463 artifact := structs.TaskArtifact{ 464 GetterSource: "http://127.1.1.111:12315/foo/bar/baz", 465 } 466 task.Artifacts = []*structs.TaskArtifact{&artifact} 467 468 // Make the restart policy try one ctx.upd.te 469 alloc.Job.TaskGroups[0].RestartPolicy = &structs.RestartPolicy{ 470 Attempts: 1, 471 Interval: 10 * time.Minute, 472 Delay: 1 * time.Second, 473 Mode: structs.RestartPolicyModeFail, 474 } 475 476 ctx := testTaskRunnerFromAlloc(t, true, alloc) 477 ctx.tr.MarkReceived() 478 go ctx.tr.Run() 479 defer ctx.Cleanup() 480 481 select { 482 case <-ctx.tr.WaitCh(): 483 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 484 t.Fatalf("timeout") 485 } 486 487 if len(ctx.upd.events) != 8 { 488 t.Fatalf("should have 8 ctx.updates: %#v", ctx.upd.events) 489 } 490 491 if ctx.upd.state != structs.TaskStateDead { 492 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 493 } 494 495 if ctx.upd.events[0].Type != structs.TaskReceived { 496 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 497 } 498 499 if ctx.upd.events[1].Type != structs.TaskSetup { 500 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 501 } 502 503 if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts { 504 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts) 505 } 506 507 if ctx.upd.events[3].Type != structs.TaskArtifactDownloadFailed { 508 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskArtifactDownloadFailed) 509 } 510 511 if ctx.upd.events[4].Type != structs.TaskRestarting { 512 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskRestarting) 513 } 514 515 if ctx.upd.events[5].Type != structs.TaskDownloadingArtifacts { 516 t.Fatalf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskDownloadingArtifacts) 517 } 518 519 if ctx.upd.events[6].Type != structs.TaskArtifactDownloadFailed { 520 t.Fatalf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskArtifactDownloadFailed) 521 } 522 523 if ctx.upd.events[7].Type != structs.TaskNotRestarting { 524 t.Fatalf("Eighth Event was %v; want %v", ctx.upd.events[7].Type, structs.TaskNotRestarting) 525 } 526 } 527 528 func TestTaskRunner_Validate_UserEnforcement(t *testing.T) { 529 ctestutil.ExecCompatible(t) 530 ctx := testTaskRunner(t, false) 531 defer ctx.Cleanup() 532 533 if err := ctx.tr.setTaskEnv(); err != nil { 534 t.Fatalf("bad: %v", err) 535 } 536 537 // Try to run as root with exec. 538 ctx.tr.task.Driver = "exec" 539 ctx.tr.task.User = "root" 540 if err := ctx.tr.validateTask(); err == nil { 541 t.Fatalf("expected error running as root with exec") 542 } 543 544 // Try to run a non-blacklisted user with exec. 545 ctx.tr.task.Driver = "exec" 546 ctx.tr.task.User = "foobar" 547 if err := ctx.tr.validateTask(); err != nil { 548 t.Fatalf("unexpected error: %v", err) 549 } 550 551 // Try to run as root with docker. 552 ctx.tr.task.Driver = "docker" 553 ctx.tr.task.User = "root" 554 if err := ctx.tr.validateTask(); err != nil { 555 t.Fatalf("unexpected error: %v", err) 556 } 557 } 558 559 func TestTaskRunner_RestartTask(t *testing.T) { 560 alloc := mock.Alloc() 561 task := alloc.Job.TaskGroups[0].Tasks[0] 562 task.Driver = "mock_driver" 563 task.Config = map[string]interface{}{ 564 "exit_code": "0", 565 "run_for": "100s", 566 } 567 568 ctx := testTaskRunnerFromAlloc(t, true, alloc) 569 ctx.tr.MarkReceived() 570 go ctx.tr.Run() 571 defer ctx.Cleanup() 572 573 // Wait for it to start 574 go func() { 575 testWaitForTaskToStart(t, ctx) 576 ctx.tr.Restart("test", "restart") 577 578 // Wait for it to restart then kill 579 go func() { 580 // Wait for the task to start again 581 testutil.WaitForResult(func() (bool, error) { 582 if len(ctx.upd.events) != 8 { 583 t.Fatalf("task %q in alloc %q should have 8 ctx.updates: %#v", task.Name, alloc.ID, ctx.upd.events) 584 } 585 586 return true, nil 587 }, func(err error) { 588 t.Fatalf("err: %v", err) 589 }) 590 ctx.tr.Kill("test", "restart", false) 591 }() 592 }() 593 594 select { 595 case <-ctx.tr.WaitCh(): 596 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 597 t.Fatalf("timeout") 598 } 599 600 if len(ctx.upd.events) != 10 { 601 t.Fatalf("should have 9 ctx.updates: %#v", ctx.upd.events) 602 } 603 604 if ctx.upd.state != structs.TaskStateDead { 605 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 606 } 607 608 if ctx.upd.events[0].Type != structs.TaskReceived { 609 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 610 } 611 612 if ctx.upd.events[1].Type != structs.TaskSetup { 613 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 614 } 615 616 if ctx.upd.events[2].Type != structs.TaskStarted { 617 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 618 } 619 620 if ctx.upd.events[3].Type != structs.TaskRestartSignal { 621 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestartSignal) 622 } 623 624 if ctx.upd.events[4].Type != structs.TaskKilling { 625 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilling) 626 } 627 628 if ctx.upd.events[5].Type != structs.TaskKilled { 629 t.Fatalf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskKilled) 630 } 631 632 if ctx.upd.events[6].Type != structs.TaskRestarting { 633 t.Fatalf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskRestarting) 634 } 635 636 if ctx.upd.events[7].Type != structs.TaskStarted { 637 t.Fatalf("Eighth Event was %v; want %v", ctx.upd.events[8].Type, structs.TaskStarted) 638 } 639 if ctx.upd.events[8].Type != structs.TaskKilling { 640 t.Fatalf("Nineth Event was %v; want %v", ctx.upd.events[8].Type, structs.TaskKilling) 641 } 642 643 if ctx.upd.events[9].Type != structs.TaskKilled { 644 t.Fatalf("Tenth Event was %v; want %v", ctx.upd.events[9].Type, structs.TaskKilled) 645 } 646 } 647 648 // This test is just to make sure we are resilient to failures when a restart or 649 // signal is triggered and the task is not running. 650 func TestTaskRunner_RestartSignalTask_NotRunning(t *testing.T) { 651 alloc := mock.Alloc() 652 task := alloc.Job.TaskGroups[0].Tasks[0] 653 task.Driver = "mock_driver" 654 task.Config = map[string]interface{}{ 655 "exit_code": "0", 656 "run_for": "100s", 657 } 658 659 // Use vault to block the start 660 task.Vault = &structs.Vault{Policies: []string{"default"}} 661 662 ctx := testTaskRunnerFromAlloc(t, true, alloc) 663 ctx.tr.MarkReceived() 664 defer ctx.Cleanup() 665 666 // Control when we get a Vault token 667 token := "1234" 668 waitCh := make(chan struct{}) 669 defer close(waitCh) 670 handler := func(*structs.Allocation, []string) (map[string]string, error) { 671 <-waitCh 672 return map[string]string{task.Name: token}, nil 673 } 674 ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler 675 go ctx.tr.Run() 676 677 select { 678 case <-ctx.tr.WaitCh(): 679 t.Fatalf("premature exit") 680 case <-time.After(1 * time.Second): 681 } 682 683 // Send a signal and restart 684 if err := ctx.tr.Signal("test", "don't panic", syscall.SIGCHLD); err != nil { 685 t.Fatalf("Signalling errored: %v", err) 686 } 687 688 // Send a restart 689 ctx.tr.Restart("test", "don't panic") 690 691 if len(ctx.upd.events) != 2 { 692 t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events) 693 } 694 695 if ctx.upd.state != structs.TaskStatePending { 696 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending) 697 } 698 699 if ctx.upd.events[0].Type != structs.TaskReceived { 700 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 701 } 702 703 if ctx.upd.events[1].Type != structs.TaskSetup { 704 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 705 } 706 } 707 708 func TestTaskRunner_KillTask(t *testing.T) { 709 alloc := mock.Alloc() 710 task := alloc.Job.TaskGroups[0].Tasks[0] 711 task.Driver = "mock_driver" 712 task.Config = map[string]interface{}{ 713 "exit_code": "0", 714 "run_for": "10s", 715 } 716 717 ctx := testTaskRunnerFromAlloc(t, false, alloc) 718 ctx.tr.MarkReceived() 719 go ctx.tr.Run() 720 defer ctx.Cleanup() 721 722 go func() { 723 testWaitForTaskToStart(t, ctx) 724 ctx.tr.Kill("test", "kill", true) 725 }() 726 727 select { 728 case <-ctx.tr.WaitCh(): 729 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 730 t.Fatalf("timeout") 731 } 732 733 if len(ctx.upd.events) != 5 { 734 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 735 } 736 737 if ctx.upd.state != structs.TaskStateDead { 738 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 739 } 740 741 if !ctx.upd.failed { 742 t.Fatalf("TaskState should be failed: %+v", ctx.upd) 743 } 744 745 if ctx.upd.events[0].Type != structs.TaskReceived { 746 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 747 } 748 749 if ctx.upd.events[1].Type != structs.TaskSetup { 750 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 751 } 752 753 if ctx.upd.events[2].Type != structs.TaskStarted { 754 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 755 } 756 757 if ctx.upd.events[3].Type != structs.TaskKilling { 758 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskKilling) 759 } 760 761 if ctx.upd.events[4].Type != structs.TaskKilled { 762 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilled) 763 } 764 } 765 766 func TestTaskRunner_SignalFailure(t *testing.T) { 767 alloc := mock.Alloc() 768 task := alloc.Job.TaskGroups[0].Tasks[0] 769 task.Driver = "mock_driver" 770 task.Config = map[string]interface{}{ 771 "exit_code": "0", 772 "run_for": "10s", 773 "signal_error": "test forcing failure", 774 } 775 776 ctx := testTaskRunnerFromAlloc(t, false, alloc) 777 ctx.tr.MarkReceived() 778 go ctx.tr.Run() 779 defer ctx.Cleanup() 780 781 // Wait for the task to start 782 testWaitForTaskToStart(t, ctx) 783 784 if err := ctx.tr.Signal("test", "test", syscall.SIGINT); err == nil { 785 t.Fatalf("Didn't receive error") 786 } 787 } 788 789 func TestTaskRunner_BlockForVault(t *testing.T) { 790 alloc := mock.Alloc() 791 task := alloc.Job.TaskGroups[0].Tasks[0] 792 task.Driver = "mock_driver" 793 task.Config = map[string]interface{}{ 794 "exit_code": "0", 795 "run_for": "1s", 796 } 797 task.Vault = &structs.Vault{Policies: []string{"default"}} 798 799 ctx := testTaskRunnerFromAlloc(t, false, alloc) 800 ctx.tr.MarkReceived() 801 defer ctx.Cleanup() 802 803 // Control when we get a Vault token 804 token := "1234" 805 waitCh := make(chan struct{}) 806 handler := func(*structs.Allocation, []string) (map[string]string, error) { 807 <-waitCh 808 return map[string]string{task.Name: token}, nil 809 } 810 ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler 811 812 go ctx.tr.Run() 813 814 select { 815 case <-ctx.tr.WaitCh(): 816 t.Fatalf("premature exit") 817 case <-time.After(1 * time.Second): 818 } 819 820 if len(ctx.upd.events) != 2 { 821 t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events) 822 } 823 824 if ctx.upd.state != structs.TaskStatePending { 825 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending) 826 } 827 828 if ctx.upd.events[0].Type != structs.TaskReceived { 829 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 830 } 831 832 if ctx.upd.events[1].Type != structs.TaskSetup { 833 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 834 } 835 836 // Unblock 837 close(waitCh) 838 839 select { 840 case <-ctx.tr.WaitCh(): 841 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 842 t.Fatalf("timeout") 843 } 844 845 if len(ctx.upd.events) != 4 { 846 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 847 } 848 849 if ctx.upd.state != structs.TaskStateDead { 850 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 851 } 852 853 if ctx.upd.events[0].Type != structs.TaskReceived { 854 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 855 } 856 857 if ctx.upd.events[1].Type != structs.TaskSetup { 858 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 859 } 860 861 if ctx.upd.events[2].Type != structs.TaskStarted { 862 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 863 } 864 865 if ctx.upd.events[3].Type != structs.TaskTerminated { 866 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 867 } 868 869 // Check that the token is on disk 870 tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile) 871 data, err := ioutil.ReadFile(tokenPath) 872 if err != nil { 873 t.Fatalf("Failed to read file: %v", err) 874 } 875 876 if act := string(data); act != token { 877 t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token) 878 } 879 880 // Check the token was revoked 881 m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 882 testutil.WaitForResult(func() (bool, error) { 883 if len(m.StoppedTokens) != 1 { 884 return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens) 885 } 886 887 if a := m.StoppedTokens[0]; a != token { 888 return false, fmt.Errorf("got stopped token %q; want %q", a, token) 889 } 890 return true, nil 891 }, func(err error) { 892 t.Fatalf("err: %v", err) 893 }) 894 } 895 896 func TestTaskRunner_DeriveToken_Retry(t *testing.T) { 897 alloc := mock.Alloc() 898 task := alloc.Job.TaskGroups[0].Tasks[0] 899 task.Driver = "mock_driver" 900 task.Config = map[string]interface{}{ 901 "exit_code": "0", 902 "run_for": "1s", 903 } 904 task.Vault = &structs.Vault{Policies: []string{"default"}} 905 906 ctx := testTaskRunnerFromAlloc(t, false, alloc) 907 ctx.tr.MarkReceived() 908 defer ctx.Cleanup() 909 910 // Control when we get a Vault token 911 token := "1234" 912 count := 0 913 handler := func(*structs.Allocation, []string) (map[string]string, error) { 914 if count > 0 { 915 return map[string]string{task.Name: token}, nil 916 } 917 918 count++ 919 return nil, structs.NewRecoverableError(fmt.Errorf("Want a retry"), true) 920 } 921 ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler 922 go ctx.tr.Run() 923 924 select { 925 case <-ctx.tr.WaitCh(): 926 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 927 t.Fatalf("timeout") 928 } 929 930 if len(ctx.upd.events) != 4 { 931 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 932 } 933 934 if ctx.upd.state != structs.TaskStateDead { 935 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 936 } 937 938 if ctx.upd.events[0].Type != structs.TaskReceived { 939 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 940 } 941 942 if ctx.upd.events[1].Type != structs.TaskSetup { 943 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 944 } 945 946 if ctx.upd.events[2].Type != structs.TaskStarted { 947 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 948 } 949 950 if ctx.upd.events[3].Type != structs.TaskTerminated { 951 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 952 } 953 954 // Check that the token is on disk 955 tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile) 956 data, err := ioutil.ReadFile(tokenPath) 957 if err != nil { 958 t.Fatalf("Failed to read file: %v", err) 959 } 960 961 if act := string(data); act != token { 962 t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token) 963 } 964 965 // Check the token was revoked 966 m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 967 testutil.WaitForResult(func() (bool, error) { 968 if len(m.StoppedTokens) != 1 { 969 return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens) 970 } 971 972 if a := m.StoppedTokens[0]; a != token { 973 return false, fmt.Errorf("got stopped token %q; want %q", a, token) 974 } 975 return true, nil 976 }, func(err error) { 977 t.Fatalf("err: %v", err) 978 }) 979 } 980 981 func TestTaskRunner_DeriveToken_Unrecoverable(t *testing.T) { 982 alloc := mock.Alloc() 983 task := alloc.Job.TaskGroups[0].Tasks[0] 984 task.Driver = "mock_driver" 985 task.Config = map[string]interface{}{ 986 "exit_code": "0", 987 "run_for": "10s", 988 } 989 task.Vault = &structs.Vault{ 990 Policies: []string{"default"}, 991 ChangeMode: structs.VaultChangeModeRestart, 992 } 993 994 ctx := testTaskRunnerFromAlloc(t, false, alloc) 995 ctx.tr.MarkReceived() 996 defer ctx.Cleanup() 997 998 // Error the token derivation 999 vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 1000 vc.SetDeriveTokenError(alloc.ID, []string{task.Name}, fmt.Errorf("Non recoverable")) 1001 go ctx.tr.Run() 1002 1003 // Wait for the task to start 1004 testutil.WaitForResult(func() (bool, error) { 1005 if l := len(ctx.upd.events); l != 3 { 1006 return false, fmt.Errorf("Expect 3 events; got %v", l) 1007 } 1008 1009 if ctx.upd.events[0].Type != structs.TaskReceived { 1010 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1011 } 1012 1013 if ctx.upd.events[1].Type != structs.TaskSetup { 1014 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1015 } 1016 1017 if ctx.upd.events[2].Type != structs.TaskKilling { 1018 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskKilling) 1019 } 1020 1021 return true, nil 1022 }, func(err error) { 1023 t.Fatalf("err: %v", err) 1024 }) 1025 } 1026 1027 func TestTaskRunner_Template_Block(t *testing.T) { 1028 testRetryRate = 2 * time.Second 1029 defer func() { 1030 testRetryRate = 0 1031 }() 1032 alloc := mock.Alloc() 1033 task := alloc.Job.TaskGroups[0].Tasks[0] 1034 task.Driver = "mock_driver" 1035 task.Config = map[string]interface{}{ 1036 "exit_code": "0", 1037 "run_for": "1s", 1038 } 1039 task.Templates = []*structs.Template{ 1040 { 1041 EmbeddedTmpl: "{{key \"foo\"}}", 1042 DestPath: "local/test", 1043 ChangeMode: structs.TemplateChangeModeNoop, 1044 }, 1045 } 1046 1047 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1048 ctx.tr.MarkReceived() 1049 go ctx.tr.Run() 1050 defer ctx.Cleanup() 1051 1052 select { 1053 case <-ctx.tr.WaitCh(): 1054 t.Fatalf("premature exit") 1055 case <-time.After(1 * time.Second): 1056 } 1057 1058 if len(ctx.upd.events) != 2 { 1059 t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events) 1060 } 1061 1062 if ctx.upd.state != structs.TaskStatePending { 1063 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending) 1064 } 1065 1066 if ctx.upd.events[0].Type != structs.TaskReceived { 1067 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1068 } 1069 1070 if ctx.upd.events[1].Type != structs.TaskSetup { 1071 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1072 } 1073 1074 // Unblock 1075 ctx.tr.UnblockStart("test") 1076 1077 select { 1078 case <-ctx.tr.WaitCh(): 1079 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1080 t.Fatalf("timeout") 1081 } 1082 1083 if len(ctx.upd.events) != 4 { 1084 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 1085 } 1086 1087 if ctx.upd.state != structs.TaskStateDead { 1088 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1089 } 1090 1091 if ctx.upd.events[0].Type != structs.TaskReceived { 1092 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1093 } 1094 1095 if ctx.upd.events[1].Type != structs.TaskSetup { 1096 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1097 } 1098 1099 if ctx.upd.events[2].Type != structs.TaskStarted { 1100 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1101 } 1102 1103 if ctx.upd.events[3].Type != structs.TaskTerminated { 1104 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 1105 } 1106 } 1107 1108 func TestTaskRunner_Template_Artifact(t *testing.T) { 1109 dir, err := os.Getwd() 1110 if err != nil { 1111 t.Fatalf("bad: %v", err) 1112 } 1113 1114 ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(dir, "..")))) 1115 defer ts.Close() 1116 1117 alloc := mock.Alloc() 1118 task := alloc.Job.TaskGroups[0].Tasks[0] 1119 task.Driver = "mock_driver" 1120 task.Config = map[string]interface{}{ 1121 "exit_code": "0", 1122 "run_for": "1s", 1123 } 1124 // Create an allocation that has a task that renders a template from an 1125 // artifact 1126 f1 := "CHANGELOG.md" 1127 artifact := structs.TaskArtifact{ 1128 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1), 1129 } 1130 task.Artifacts = []*structs.TaskArtifact{&artifact} 1131 task.Templates = []*structs.Template{ 1132 { 1133 SourcePath: "CHANGELOG.md", 1134 DestPath: "local/test", 1135 ChangeMode: structs.TemplateChangeModeNoop, 1136 }, 1137 } 1138 1139 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1140 ctx.tr.MarkReceived() 1141 defer ctx.Cleanup() 1142 go ctx.tr.Run() 1143 1144 select { 1145 case <-ctx.tr.WaitCh(): 1146 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1147 t.Fatalf("timeout") 1148 } 1149 1150 if len(ctx.upd.events) != 5 { 1151 t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events) 1152 } 1153 1154 if ctx.upd.state != structs.TaskStateDead { 1155 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1156 } 1157 1158 if ctx.upd.events[0].Type != structs.TaskReceived { 1159 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1160 } 1161 1162 if ctx.upd.events[1].Type != structs.TaskSetup { 1163 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1164 } 1165 1166 if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts { 1167 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts) 1168 } 1169 1170 if ctx.upd.events[3].Type != structs.TaskStarted { 1171 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskStarted) 1172 } 1173 1174 if ctx.upd.events[4].Type != structs.TaskTerminated { 1175 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskTerminated) 1176 } 1177 1178 // Check that both files exist. 1179 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f1)); err != nil { 1180 t.Fatalf("%v not downloaded", f1) 1181 } 1182 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.LocalDir, "test")); err != nil { 1183 t.Fatalf("template not rendered") 1184 } 1185 } 1186 1187 func TestTaskRunner_Template_NewVaultToken(t *testing.T) { 1188 alloc := mock.Alloc() 1189 task := alloc.Job.TaskGroups[0].Tasks[0] 1190 task.Driver = "mock_driver" 1191 task.Config = map[string]interface{}{ 1192 "exit_code": "0", 1193 "run_for": "1s", 1194 } 1195 task.Templates = []*structs.Template{ 1196 { 1197 EmbeddedTmpl: "{{key \"foo\"}}", 1198 DestPath: "local/test", 1199 ChangeMode: structs.TemplateChangeModeNoop, 1200 }, 1201 } 1202 task.Vault = &structs.Vault{Policies: []string{"default"}} 1203 1204 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1205 ctx.tr.MarkReceived() 1206 defer ctx.Cleanup() 1207 go ctx.tr.Run() 1208 1209 // Wait for a Vault token 1210 var token string 1211 testutil.WaitForResult(func() (bool, error) { 1212 if token = ctx.tr.vaultFuture.Get(); token == "" { 1213 return false, fmt.Errorf("No Vault token") 1214 } 1215 1216 return true, nil 1217 }, func(err error) { 1218 t.Fatalf("err: %v", err) 1219 }) 1220 1221 // Error the token renewal 1222 vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 1223 renewalCh, ok := vc.RenewTokens[token] 1224 if !ok { 1225 t.Fatalf("no renewal channel") 1226 } 1227 1228 originalManager := ctx.tr.templateManager 1229 1230 renewalCh <- fmt.Errorf("Test killing") 1231 close(renewalCh) 1232 1233 // Wait for a new Vault token 1234 var token2 string 1235 testutil.WaitForResult(func() (bool, error) { 1236 if token2 = ctx.tr.vaultFuture.Get(); token2 == "" || token2 == token { 1237 return false, fmt.Errorf("No new Vault token") 1238 } 1239 1240 if originalManager == ctx.tr.templateManager { 1241 return false, fmt.Errorf("Template manager not ctx.updated") 1242 } 1243 1244 return true, nil 1245 }, func(err error) { 1246 t.Fatalf("err: %v", err) 1247 }) 1248 1249 // Check the token was revoked 1250 m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 1251 testutil.WaitForResult(func() (bool, error) { 1252 if len(m.StoppedTokens) != 1 { 1253 return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens) 1254 } 1255 1256 if a := m.StoppedTokens[0]; a != token { 1257 return false, fmt.Errorf("got stopped token %q; want %q", a, token) 1258 } 1259 return true, nil 1260 }, func(err error) { 1261 t.Fatalf("err: %v", err) 1262 }) 1263 } 1264 1265 func TestTaskRunner_VaultManager_Restart(t *testing.T) { 1266 alloc := mock.Alloc() 1267 task := alloc.Job.TaskGroups[0].Tasks[0] 1268 task.Driver = "mock_driver" 1269 task.Config = map[string]interface{}{ 1270 "exit_code": "0", 1271 "run_for": "10s", 1272 } 1273 task.Vault = &structs.Vault{ 1274 Policies: []string{"default"}, 1275 ChangeMode: structs.VaultChangeModeRestart, 1276 } 1277 1278 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1279 ctx.tr.MarkReceived() 1280 defer ctx.Cleanup() 1281 go ctx.tr.Run() 1282 1283 // Wait for the task to start 1284 testWaitForTaskToStart(t, ctx) 1285 1286 // Error the token renewal 1287 vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 1288 renewalCh, ok := vc.RenewTokens[ctx.tr.vaultFuture.Get()] 1289 if !ok { 1290 t.Fatalf("no renewal channel") 1291 } 1292 1293 renewalCh <- fmt.Errorf("Test killing") 1294 close(renewalCh) 1295 1296 // Ensure a restart 1297 testutil.WaitForResult(func() (bool, error) { 1298 if l := len(ctx.upd.events); l != 8 { 1299 return false, fmt.Errorf("Expect eight events; got %#v", ctx.upd.events) 1300 } 1301 1302 if ctx.upd.events[0].Type != structs.TaskReceived { 1303 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1304 } 1305 1306 if ctx.upd.events[1].Type != structs.TaskSetup { 1307 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskStarted) 1308 } 1309 1310 if ctx.upd.events[2].Type != structs.TaskStarted { 1311 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1312 } 1313 1314 if ctx.upd.events[3].Type != structs.TaskRestartSignal { 1315 return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestartSignal) 1316 } 1317 1318 if ctx.upd.events[4].Type != structs.TaskKilling { 1319 return false, fmt.Errorf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilling) 1320 } 1321 1322 if ctx.upd.events[5].Type != structs.TaskKilled { 1323 return false, fmt.Errorf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskKilled) 1324 } 1325 1326 if ctx.upd.events[6].Type != structs.TaskRestarting { 1327 return false, fmt.Errorf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskRestarting) 1328 } 1329 1330 if ctx.upd.events[7].Type != structs.TaskStarted { 1331 return false, fmt.Errorf("Eight Event was %v; want %v", ctx.upd.events[7].Type, structs.TaskStarted) 1332 } 1333 1334 return true, nil 1335 }, func(err error) { 1336 t.Fatalf("err: %v", err) 1337 }) 1338 } 1339 1340 func TestTaskRunner_VaultManager_Signal(t *testing.T) { 1341 alloc := mock.Alloc() 1342 task := alloc.Job.TaskGroups[0].Tasks[0] 1343 task.Driver = "mock_driver" 1344 task.Config = map[string]interface{}{ 1345 "exit_code": "0", 1346 "run_for": "10s", 1347 } 1348 task.Vault = &structs.Vault{ 1349 Policies: []string{"default"}, 1350 ChangeMode: structs.VaultChangeModeSignal, 1351 ChangeSignal: "SIGUSR1", 1352 } 1353 1354 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1355 ctx.tr.MarkReceived() 1356 go ctx.tr.Run() 1357 defer ctx.Cleanup() 1358 1359 // Wait for the task to start 1360 testWaitForTaskToStart(t, ctx) 1361 1362 // Error the token renewal 1363 vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 1364 renewalCh, ok := vc.RenewTokens[ctx.tr.vaultFuture.Get()] 1365 if !ok { 1366 t.Fatalf("no renewal channel") 1367 } 1368 1369 renewalCh <- fmt.Errorf("Test killing") 1370 close(renewalCh) 1371 1372 // Ensure a restart 1373 testutil.WaitForResult(func() (bool, error) { 1374 if l := len(ctx.upd.events); l != 4 { 1375 return false, fmt.Errorf("Expect four events; got %#v", ctx.upd.events) 1376 } 1377 1378 if ctx.upd.events[0].Type != structs.TaskReceived { 1379 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1380 } 1381 1382 if ctx.upd.events[1].Type != structs.TaskSetup { 1383 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1384 } 1385 1386 if ctx.upd.events[2].Type != structs.TaskStarted { 1387 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1388 } 1389 1390 if ctx.upd.events[3].Type != structs.TaskSignaling { 1391 return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskSignaling) 1392 } 1393 1394 return true, nil 1395 }, func(err error) { 1396 t.Fatalf("err: %v", err) 1397 }) 1398 } 1399 1400 // Test that the payload is written to disk 1401 func TestTaskRunner_SimpleRun_Dispatch(t *testing.T) { 1402 alloc := mock.Alloc() 1403 task := alloc.Job.TaskGroups[0].Tasks[0] 1404 task.Driver = "mock_driver" 1405 task.Config = map[string]interface{}{ 1406 "exit_code": "0", 1407 "run_for": "1s", 1408 } 1409 fileName := "test" 1410 task.DispatchPayload = &structs.DispatchPayloadConfig{ 1411 File: fileName, 1412 } 1413 alloc.Job.ParameterizedJob = &structs.ParameterizedJobConfig{} 1414 1415 // Add an encrypted payload 1416 expected := []byte("hello world") 1417 compressed := snappy.Encode(nil, expected) 1418 alloc.Job.Payload = compressed 1419 1420 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1421 ctx.tr.MarkReceived() 1422 defer ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 1423 defer ctx.allocDir.Destroy() 1424 go ctx.tr.Run() 1425 1426 select { 1427 case <-ctx.tr.WaitCh(): 1428 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1429 t.Fatalf("timeout") 1430 } 1431 1432 if len(ctx.upd.events) != 4 { 1433 t.Fatalf("should have 4 updates: %#v", ctx.upd.events) 1434 } 1435 1436 if ctx.upd.state != structs.TaskStateDead { 1437 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1438 } 1439 1440 if ctx.upd.events[0].Type != structs.TaskReceived { 1441 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1442 } 1443 1444 if ctx.upd.events[1].Type != structs.TaskSetup { 1445 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1446 } 1447 1448 if ctx.upd.events[2].Type != structs.TaskStarted { 1449 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1450 } 1451 1452 if ctx.upd.events[3].Type != structs.TaskTerminated { 1453 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 1454 } 1455 1456 // Check that the file was written to disk properly 1457 payloadPath := filepath.Join(ctx.tr.taskDir.LocalDir, fileName) 1458 data, err := ioutil.ReadFile(payloadPath) 1459 if err != nil { 1460 t.Fatalf("Failed to read file: %v", err) 1461 } 1462 if !reflect.DeepEqual(data, expected) { 1463 t.Fatalf("Bad; got %v; want %v", string(data), string(expected)) 1464 } 1465 } 1466 1467 // TestTaskRunner_CleanupEmpty ensures TaskRunner works when createdResources 1468 // is empty. 1469 func TestTaskRunner_CleanupEmpty(t *testing.T) { 1470 alloc := mock.Alloc() 1471 task := alloc.Job.TaskGroups[0].Tasks[0] 1472 task.Driver = "mock_driver" 1473 1474 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1475 ctx.tr.MarkReceived() 1476 1477 defer ctx.Cleanup() 1478 ctx.tr.Run() 1479 1480 // Since we only failed once, createdResources should be empty 1481 if len(ctx.tr.createdResources.Resources) != 0 { 1482 t.Fatalf("createdResources should still be empty: %v", ctx.tr.createdResources) 1483 } 1484 } 1485 1486 func TestTaskRunner_CleanupOK(t *testing.T) { 1487 alloc := mock.Alloc() 1488 task := alloc.Job.TaskGroups[0].Tasks[0] 1489 task.Driver = "mock_driver" 1490 key := "ERR" 1491 1492 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1493 ctx.tr.config.Options = map[string]string{ 1494 "cleanup_fail_on": key, 1495 "cleanup_fail_num": "1", 1496 } 1497 ctx.tr.MarkReceived() 1498 1499 ctx.tr.createdResources.Resources[key] = []string{"x", "y"} 1500 ctx.tr.createdResources.Resources["foo"] = []string{"z"} 1501 1502 defer ctx.Cleanup() 1503 ctx.tr.Run() 1504 1505 // Since we only failed once, createdResources should be empty 1506 if len(ctx.tr.createdResources.Resources) > 0 { 1507 t.Fatalf("expected all created resources to be removed: %#v", ctx.tr.createdResources.Resources) 1508 } 1509 } 1510 1511 func TestTaskRunner_CleanupFail(t *testing.T) { 1512 alloc := mock.Alloc() 1513 task := alloc.Job.TaskGroups[0].Tasks[0] 1514 task.Driver = "mock_driver" 1515 key := "ERR" 1516 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1517 ctx.tr.config.Options = map[string]string{ 1518 "cleanup_fail_on": key, 1519 "cleanup_fail_num": "5", 1520 } 1521 ctx.tr.MarkReceived() 1522 1523 ctx.tr.createdResources.Resources[key] = []string{"x"} 1524 ctx.tr.createdResources.Resources["foo"] = []string{"y", "z"} 1525 1526 defer ctx.Cleanup() 1527 ctx.tr.Run() 1528 1529 // Since we failed > 3 times, the failed key should remain 1530 expected := map[string][]string{key: {"x"}} 1531 if !reflect.DeepEqual(expected, ctx.tr.createdResources.Resources) { 1532 t.Fatalf("expected %#v but found: %#v", expected, ctx.tr.createdResources.Resources) 1533 } 1534 }