github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/client/allocrunner/taskrunner/task_runner_test.go (about) 1 package taskrunner 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "net/http" 7 "net/http/httptest" 8 "os" 9 "path/filepath" 10 "reflect" 11 "strings" 12 "syscall" 13 "testing" 14 "time" 15 16 "github.com/boltdb/bolt" 17 "github.com/golang/snappy" 18 "github.com/hashicorp/nomad/client/allocdir" 19 "github.com/hashicorp/nomad/client/allocrunner/taskrunner/restarts" 20 "github.com/hashicorp/nomad/client/config" 21 consulApi "github.com/hashicorp/nomad/client/consul" 22 "github.com/hashicorp/nomad/client/driver/env" 23 cstructs "github.com/hashicorp/nomad/client/structs" 24 "github.com/hashicorp/nomad/client/vaultclient" 25 "github.com/hashicorp/nomad/command/agent/consul" 26 "github.com/hashicorp/nomad/helper/testlog" 27 "github.com/hashicorp/nomad/nomad/mock" 28 "github.com/hashicorp/nomad/nomad/structs" 29 "github.com/hashicorp/nomad/testutil" 30 "github.com/kr/pretty" 31 ) 32 33 // Returns a tracker that never restarts. 34 func noRestartsTracker() *restarts.RestartTracker { 35 policy := &structs.RestartPolicy{Attempts: 0, Mode: structs.RestartPolicyModeFail} 36 return restarts.NewRestartTracker(policy, structs.JobTypeBatch) 37 } 38 39 type MockTaskStateUpdater struct { 40 state string 41 failed bool 42 events []*structs.TaskEvent 43 } 44 45 func (m *MockTaskStateUpdater) Update(name, state string, event *structs.TaskEvent, _ bool) { 46 if state != "" { 47 m.state = state 48 } 49 if event != nil { 50 if event.FailsTask { 51 m.failed = true 52 } 53 m.events = append(m.events, event) 54 } 55 } 56 57 // String for debugging purposes. 58 func (m *MockTaskStateUpdater) String() string { 59 s := fmt.Sprintf("Updates:\n state=%q\n failed=%t\n events=\n", m.state, m.failed) 60 for _, e := range m.events { 61 s += fmt.Sprintf(" %#v\n", e) 62 } 63 return s 64 } 65 66 type taskRunnerTestCtx struct { 67 upd *MockTaskStateUpdater 68 tr *TaskRunner 69 allocDir *allocdir.AllocDir 70 vault *vaultclient.MockVaultClient 71 consul *consul.MockAgent 72 consulClient *consul.ServiceClient 73 } 74 75 // Cleanup calls Destroy on the task runner and alloc dir 76 func (ctx *taskRunnerTestCtx) Cleanup() { 77 ctx.consulClient.Shutdown() 78 ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 79 ctx.allocDir.Destroy() 80 } 81 82 func testTaskRunner(t *testing.T, restarts bool) *taskRunnerTestCtx { 83 // Use mock driver 84 alloc := mock.Alloc() 85 task := alloc.Job.TaskGroups[0].Tasks[0] 86 task.Driver = "mock_driver" 87 task.Config["run_for"] = "500ms" 88 return testTaskRunnerFromAlloc(t, restarts, alloc) 89 } 90 91 // Creates a mock task runner using the first task in the first task group of 92 // the passed allocation. 93 // 94 // Callers should defer Cleanup() to cleanup after completion 95 func testTaskRunnerFromAlloc(t *testing.T, restarts bool, alloc *structs.Allocation) *taskRunnerTestCtx { 96 logger := testlog.Logger(t) 97 conf := config.DefaultConfig() 98 conf.Node = mock.Node() 99 conf.StateDir = os.TempDir() 100 conf.AllocDir = os.TempDir() 101 102 tmp, err := ioutil.TempFile("", "state-db") 103 if err != nil { 104 t.Fatalf("error creating state db file: %v", err) 105 } 106 db, err := bolt.Open(tmp.Name(), 0600, nil) 107 if err != nil { 108 t.Fatalf("error creating state db: %v", err) 109 } 110 111 upd := &MockTaskStateUpdater{} 112 task := alloc.Job.TaskGroups[0].Tasks[0] 113 114 allocDir := allocdir.NewAllocDir(testlog.Logger(t), filepath.Join(conf.AllocDir, alloc.ID)) 115 if err := allocDir.Build(); err != nil { 116 t.Fatalf("error building alloc dir: %v", err) 117 return nil 118 } 119 120 //HACK to get FSIsolation and chroot without using AllocRunner, 121 // TaskRunner, or Drivers 122 fsi := cstructs.FSIsolationImage 123 switch task.Driver { 124 case "raw_exec": 125 fsi = cstructs.FSIsolationNone 126 case "exec", "java": 127 fsi = cstructs.FSIsolationChroot 128 } 129 taskDir := allocDir.NewTaskDir(task.Name) 130 if err := taskDir.Build(false, config.DefaultChrootEnv, fsi); err != nil { 131 t.Fatalf("error building task dir %q: %v", task.Name, err) 132 return nil 133 } 134 135 vclient := vaultclient.NewMockVaultClient() 136 cclient := consul.NewMockAgent() 137 serviceClient := consul.NewServiceClient(cclient, logger, true) 138 go serviceClient.Run() 139 tr := NewTaskRunner(logger, conf, db, upd.Update, taskDir, alloc, task, vclient, serviceClient) 140 if !restarts { 141 tr.restartTracker = noRestartsTracker() 142 } 143 return &taskRunnerTestCtx{ 144 upd: upd, 145 tr: tr, 146 allocDir: allocDir, 147 vault: vclient, 148 consul: cclient, 149 consulClient: serviceClient, 150 } 151 } 152 153 // testWaitForTaskToStart waits for the task to or fails the test 154 func testWaitForTaskToStart(t *testing.T, ctx *taskRunnerTestCtx) { 155 // Wait for the task to start 156 testutil.WaitForResult(func() (bool, error) { 157 l := len(ctx.upd.events) 158 if l < 2 { 159 return false, fmt.Errorf("Expect two events; got %v", l) 160 } 161 162 if ctx.upd.events[0].Type != structs.TaskReceived { 163 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 164 } 165 166 if l >= 3 { 167 if ctx.upd.events[1].Type != structs.TaskSetup { 168 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 169 } 170 if ctx.upd.events[2].Type != structs.TaskStarted { 171 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 172 } 173 } else { 174 if ctx.upd.events[1].Type != structs.TaskStarted { 175 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskStarted) 176 } 177 } 178 179 return true, nil 180 }, func(err error) { 181 t.Fatalf("err: %v", err) 182 }) 183 } 184 185 func TestTaskRunner_SimpleRun(t *testing.T) { 186 t.Parallel() 187 ctx := testTaskRunner(t, false) 188 ctx.tr.MarkReceived() 189 go ctx.tr.Run() 190 defer ctx.Cleanup() 191 192 select { 193 case <-ctx.tr.WaitCh(): 194 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 195 t.Fatalf("timeout") 196 } 197 198 if len(ctx.upd.events) != 4 { 199 t.Fatalf("should have 3 ctx.updates: %#v", ctx.upd.events) 200 } 201 202 if ctx.upd.state != structs.TaskStateDead { 203 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 204 } 205 206 event := ctx.upd.events[0] 207 208 if event.Type != structs.TaskReceived { 209 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 210 } 211 212 event = ctx.upd.events[1] 213 if event.Type != structs.TaskSetup { 214 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 215 } 216 displayMsg := event.DisplayMessage 217 218 if displayMsg != "Building Task Directory" { 219 t.Fatalf("Bad display message:%v", displayMsg) 220 } 221 222 event = ctx.upd.events[2] 223 if event.Type != structs.TaskStarted { 224 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 225 } 226 displayMsg = event.DisplayMessage 227 if displayMsg != "Task started by client" { 228 t.Fatalf("Bad display message:%v", displayMsg) 229 } 230 231 event = ctx.upd.events[3] 232 if event.Type != structs.TaskTerminated { 233 t.Fatalf("Third Event was %v; want %v", event.Type, structs.TaskTerminated) 234 } 235 displayMsg = event.DisplayMessage 236 if displayMsg != "Exit Code: 0" { 237 t.Fatalf("Bad display message:%v", displayMsg) 238 } 239 if event.Details["exit_code"] != "0" { 240 t.Fatalf("Bad details map :%v", event.Details) 241 } 242 243 } 244 245 func TestTaskRunner_Run_RecoverableStartError(t *testing.T) { 246 t.Parallel() 247 alloc := mock.Alloc() 248 task := alloc.Job.TaskGroups[0].Tasks[0] 249 task.Driver = "mock_driver" 250 task.Config = map[string]interface{}{ 251 "exit_code": 0, 252 "start_error": "driver failure", 253 "start_error_recoverable": true, 254 } 255 256 ctx := testTaskRunnerFromAlloc(t, true, alloc) 257 ctx.tr.MarkReceived() 258 go ctx.tr.Run() 259 defer ctx.Cleanup() 260 261 testutil.WaitForResult(func() (bool, error) { 262 if l := len(ctx.upd.events); l < 4 { 263 return false, fmt.Errorf("Expect at least four events; got %v", l) 264 } 265 266 if ctx.upd.events[0].Type != structs.TaskReceived { 267 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 268 } 269 270 if ctx.upd.events[1].Type != structs.TaskSetup { 271 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 272 } 273 274 if ctx.upd.events[2].Type != structs.TaskDriverFailure { 275 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDriverFailure) 276 } 277 278 if ctx.upd.events[3].Type != structs.TaskRestarting { 279 return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestarting) 280 } 281 282 return true, nil 283 }, func(err error) { 284 t.Fatalf("err: %v", err) 285 }) 286 } 287 288 func TestTaskRunner_Destroy(t *testing.T) { 289 t.Parallel() 290 alloc := mock.Alloc() 291 task := alloc.Job.TaskGroups[0].Tasks[0] 292 task.Driver = "mock_driver" 293 task.Config = map[string]interface{}{ 294 "run_for": "1000s", 295 } 296 297 ctx := testTaskRunnerFromAlloc(t, true, alloc) 298 ctx.tr.MarkReceived() 299 go ctx.tr.Run() 300 defer ctx.Cleanup() 301 302 // Wait for the task to start 303 testWaitForTaskToStart(t, ctx) 304 305 // Begin the tear down 306 ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 307 308 select { 309 case <-ctx.tr.WaitCh(): 310 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 311 t.Fatalf("timeout") 312 } 313 314 if len(ctx.upd.events) != 5 { 315 t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events) 316 } 317 318 if ctx.upd.state != structs.TaskStateDead { 319 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 320 } 321 322 if ctx.upd.events[3].Type != structs.TaskKilling { 323 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskKilling) 324 } 325 326 if ctx.upd.events[4].Type != structs.TaskKilled { 327 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilled) 328 } 329 } 330 331 func TestTaskRunner_Update(t *testing.T) { 332 t.Parallel() 333 alloc := mock.Alloc() 334 task := alloc.Job.TaskGroups[0].Tasks[0] 335 task.Services[0].Checks[0] = &structs.ServiceCheck{ 336 Name: "http-check", 337 Type: "http", 338 PortLabel: "http", 339 Path: "${NOMAD_META_foo}", 340 } 341 task.Driver = "mock_driver" 342 task.Config = map[string]interface{}{ 343 "run_for": "100s", 344 } 345 346 ctx := testTaskRunnerFromAlloc(t, true, alloc) 347 ctx.tr.MarkReceived() 348 go ctx.tr.Run() 349 defer ctx.Cleanup() 350 351 testWaitForTaskToStart(t, ctx) 352 353 // Update the task definition 354 updateAlloc := ctx.tr.alloc.Copy() 355 356 // Update the restart policy 357 newTG := updateAlloc.Job.TaskGroups[0] 358 newMode := "foo" 359 newTG.RestartPolicy.Mode = newMode 360 361 newTask := newTG.Tasks[0] 362 newTask.Driver = "mock_driver" 363 364 // Update meta to make sure service checks are interpolated correctly 365 // #2180 366 newTask.Meta["foo"] = "/UPDATE" 367 368 // Update the kill timeout 369 oldHandle := ctx.tr.handle.ID() 370 newTask.KillTimeout = time.Hour 371 ctx.tr.Update(updateAlloc) 372 373 // Wait for ctx.update to take place 374 testutil.WaitForResult(func() (bool, error) { 375 if ctx.tr.task == newTask { 376 return false, fmt.Errorf("We copied the pointer! This would be very bad") 377 } 378 if ctx.tr.task.Driver != newTask.Driver { 379 return false, fmt.Errorf("Task not copied") 380 } 381 if ctx.tr.restartTracker.GetPolicy().Mode != newMode { 382 return false, fmt.Errorf("expected restart policy %q but found %q", newMode, ctx.tr.restartTracker.GetPolicy().Mode) 383 } 384 if ctx.tr.handle.ID() == oldHandle { 385 return false, fmt.Errorf("handle not ctx.updated") 386 } 387 388 // Make sure Consul services were interpolated correctly during 389 // the update #2180 390 checks := ctx.consul.CheckRegs() 391 if n := len(checks); n != 1 { 392 return false, fmt.Errorf("expected 1 check but found %d", n) 393 } 394 for _, check := range checks { 395 if found := check.HTTP; !strings.HasSuffix(found, "/UPDATE") { 396 return false, fmt.Errorf("expected consul check path to end with /UPDATE but found: %q", found) 397 } 398 } 399 return true, nil 400 }, func(err error) { 401 t.Fatalf("err: %v", err) 402 }) 403 } 404 405 func TestTaskRunner_SaveRestoreState(t *testing.T) { 406 t.Parallel() 407 alloc := mock.Alloc() 408 task := alloc.Job.TaskGroups[0].Tasks[0] 409 task.Driver = "mock_driver" 410 task.Config = map[string]interface{}{ 411 "exit_code": "0", 412 "run_for": "5s", 413 } 414 415 // Give it a Vault token 416 task.Vault = &structs.Vault{Policies: []string{"default"}} 417 418 ctx := testTaskRunnerFromAlloc(t, false, alloc) 419 ctx.tr.MarkReceived() 420 go ctx.tr.Run() 421 defer ctx.Cleanup() 422 423 // Wait for the task to be running and then snapshot the state 424 testWaitForTaskToStart(t, ctx) 425 426 if err := ctx.tr.SaveState(); err != nil { 427 t.Fatalf("err: %v", err) 428 } 429 430 // Read the token from the file system 431 tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile) 432 data, err := ioutil.ReadFile(tokenPath) 433 if err != nil { 434 t.Fatalf("Failed to read file: %v", err) 435 } 436 token := string(data) 437 if len(token) == 0 { 438 t.Fatalf("Token not written to disk") 439 } 440 441 // Create a new task runner 442 task2 := &structs.Task{Name: ctx.tr.task.Name, Driver: ctx.tr.task.Driver, Vault: ctx.tr.task.Vault} 443 tr2 := NewTaskRunner(ctx.tr.logger, ctx.tr.config, ctx.tr.stateDB, ctx.upd.Update, 444 ctx.tr.taskDir, ctx.tr.alloc, task2, ctx.tr.vaultClient, ctx.tr.consul) 445 tr2.restartTracker = noRestartsTracker() 446 if _, err := tr2.RestoreState(); err != nil { 447 t.Fatalf("err: %v", err) 448 } 449 go tr2.Run() 450 defer tr2.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 451 452 // Destroy and wait 453 select { 454 case <-tr2.WaitCh(): 455 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 456 t.Fatalf("timeout") 457 } 458 459 // Check that we recovered the token 460 if act := tr2.vaultFuture.Get(); act != token { 461 t.Fatalf("Vault token not properly recovered") 462 } 463 } 464 465 func TestTaskRunner_Download_List(t *testing.T) { 466 t.Parallel() 467 ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir(".")))) 468 defer ts.Close() 469 470 // Create an allocation that has a task with a list of artifacts. 471 alloc := mock.Alloc() 472 task := alloc.Job.TaskGroups[0].Tasks[0] 473 task.Driver = "mock_driver" 474 task.Config = map[string]interface{}{ 475 "exit_code": "0", 476 "run_for": "10s", 477 } 478 f1 := "task_runner_test.go" 479 f2 := "task_runner.go" 480 artifact1 := structs.TaskArtifact{ 481 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1), 482 } 483 artifact2 := structs.TaskArtifact{ 484 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f2), 485 } 486 task.Artifacts = []*structs.TaskArtifact{&artifact1, &artifact2} 487 488 ctx := testTaskRunnerFromAlloc(t, false, alloc) 489 ctx.tr.MarkReceived() 490 go ctx.tr.Run() 491 defer ctx.Cleanup() 492 493 select { 494 case <-ctx.tr.WaitCh(): 495 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 496 t.Fatalf("timeout") 497 } 498 499 if len(ctx.upd.events) != 5 { 500 t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events) 501 } 502 503 if ctx.upd.state != structs.TaskStateDead { 504 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 505 } 506 507 if ctx.upd.events[0].Type != structs.TaskReceived { 508 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 509 } 510 511 if ctx.upd.events[1].Type != structs.TaskSetup { 512 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 513 } 514 515 if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts { 516 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts) 517 } 518 519 if ctx.upd.events[3].Type != structs.TaskStarted { 520 t.Fatalf("Forth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskStarted) 521 } 522 523 if ctx.upd.events[4].Type != structs.TaskTerminated { 524 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskTerminated) 525 } 526 527 // Check that both files exist. 528 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f1)); err != nil { 529 t.Fatalf("%v not downloaded", f1) 530 } 531 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f2)); err != nil { 532 t.Fatalf("%v not downloaded", f2) 533 } 534 } 535 536 func TestTaskRunner_Download_Retries(t *testing.T) { 537 t.Parallel() 538 // Create an allocation that has a task with bad artifacts. 539 alloc := mock.Alloc() 540 task := alloc.Job.TaskGroups[0].Tasks[0] 541 task.Driver = "mock_driver" 542 task.Config = map[string]interface{}{ 543 "exit_code": "0", 544 "run_for": "10s", 545 } 546 artifact := structs.TaskArtifact{ 547 GetterSource: "http://127.0.0.1:0/foo/bar/baz", 548 } 549 task.Artifacts = []*structs.TaskArtifact{&artifact} 550 551 // Make the restart policy try one ctx.update 552 alloc.Job.TaskGroups[0].RestartPolicy = &structs.RestartPolicy{ 553 Attempts: 1, 554 Interval: 10 * time.Minute, 555 Delay: 1 * time.Second, 556 Mode: structs.RestartPolicyModeFail, 557 } 558 559 ctx := testTaskRunnerFromAlloc(t, true, alloc) 560 ctx.tr.MarkReceived() 561 go ctx.tr.Run() 562 defer ctx.Cleanup() 563 564 select { 565 case <-ctx.tr.WaitCh(): 566 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 567 t.Fatalf("timeout") 568 } 569 570 if len(ctx.upd.events) != 8 { 571 t.Fatalf("should have 8 ctx.updates: %#v", ctx.upd.events) 572 } 573 574 if ctx.upd.state != structs.TaskStateDead { 575 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 576 } 577 578 if ctx.upd.events[0].Type != structs.TaskReceived { 579 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 580 } 581 582 if ctx.upd.events[1].Type != structs.TaskSetup { 583 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 584 } 585 586 if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts { 587 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts) 588 } 589 590 if ctx.upd.events[3].Type != structs.TaskArtifactDownloadFailed { 591 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskArtifactDownloadFailed) 592 } 593 594 if ctx.upd.events[4].Type != structs.TaskRestarting { 595 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskRestarting) 596 } 597 598 if ctx.upd.events[5].Type != structs.TaskDownloadingArtifacts { 599 t.Fatalf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskDownloadingArtifacts) 600 } 601 602 if ctx.upd.events[6].Type != structs.TaskArtifactDownloadFailed { 603 t.Fatalf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskArtifactDownloadFailed) 604 } 605 606 if ctx.upd.events[7].Type != structs.TaskNotRestarting { 607 t.Fatalf("Eighth Event was %v; want %v", ctx.upd.events[7].Type, structs.TaskNotRestarting) 608 } 609 } 610 611 // TestTaskRunner_UnregisterConsul_Retries asserts a task is unregistered from 612 // Consul when waiting to be retried. 613 func TestTaskRunner_UnregisterConsul_Retries(t *testing.T) { 614 t.Parallel() 615 // Create an allocation that has a task with bad artifacts. 616 alloc := mock.Alloc() 617 618 // Make the restart policy try one ctx.update 619 alloc.Job.TaskGroups[0].RestartPolicy = &structs.RestartPolicy{ 620 Attempts: 1, 621 Interval: 10 * time.Minute, 622 Delay: time.Nanosecond, 623 Mode: structs.RestartPolicyModeFail, 624 } 625 626 task := alloc.Job.TaskGroups[0].Tasks[0] 627 task.Driver = "mock_driver" 628 task.Config = map[string]interface{}{ 629 "exit_code": "1", 630 "run_for": "1ns", 631 } 632 633 ctx := testTaskRunnerFromAlloc(t, true, alloc) 634 635 // Use mockConsulServiceClient 636 consul := consulApi.NewMockConsulServiceClient(t) 637 ctx.tr.consul = consul 638 639 ctx.tr.MarkReceived() 640 ctx.tr.Run() 641 defer ctx.Cleanup() 642 643 // Assert it is properly registered and unregistered 644 if expected := 6; len(consul.Ops) != expected { 645 t.Errorf("expected %d consul ops but found: %d", expected, len(consul.Ops)) 646 } 647 if consul.Ops[0].Op != "add" { 648 t.Errorf("expected first Op to be add but found: %q", consul.Ops[0].Op) 649 } 650 if consul.Ops[1].Op != "remove" { 651 t.Errorf("expected second op to be remove but found: %q", consul.Ops[1].Op) 652 } 653 if consul.Ops[2].Op != "remove" { 654 t.Errorf("expected third op to be remove but found: %q", consul.Ops[2].Op) 655 } 656 if consul.Ops[3].Op != "add" { 657 t.Errorf("expected fourth op to be add but found: %q", consul.Ops[3].Op) 658 } 659 if consul.Ops[4].Op != "remove" { 660 t.Errorf("expected fifth op to be remove but found: %q", consul.Ops[4].Op) 661 } 662 if consul.Ops[5].Op != "remove" { 663 t.Errorf("expected sixth op to be remove but found: %q", consul.Ops[5].Op) 664 } 665 } 666 667 func TestTaskRunner_Validate_UserEnforcement(t *testing.T) { 668 t.Parallel() 669 ctx := testTaskRunner(t, false) 670 defer ctx.Cleanup() 671 672 // Try to run as root with exec. 673 ctx.tr.task.Driver = "exec" 674 ctx.tr.task.User = "root" 675 if err := ctx.tr.validateTask(); err == nil { 676 t.Fatalf("expected error running as root with exec") 677 } 678 679 // Try to run a non-blacklisted user with exec. 680 ctx.tr.task.Driver = "exec" 681 ctx.tr.task.User = "foobar" 682 if err := ctx.tr.validateTask(); err != nil { 683 t.Fatalf("unexpected error: %v", err) 684 } 685 686 // Try to run as root with docker. 687 ctx.tr.task.Driver = "docker" 688 ctx.tr.task.User = "root" 689 if err := ctx.tr.validateTask(); err != nil { 690 t.Fatalf("unexpected error: %v", err) 691 } 692 } 693 694 func TestTaskRunner_RestartTask(t *testing.T) { 695 t.Parallel() 696 alloc := mock.Alloc() 697 task := alloc.Job.TaskGroups[0].Tasks[0] 698 task.Driver = "mock_driver" 699 task.Config = map[string]interface{}{ 700 "exit_code": "0", 701 "run_for": "100s", 702 } 703 704 ctx := testTaskRunnerFromAlloc(t, true, alloc) 705 ctx.tr.MarkReceived() 706 go ctx.tr.Run() 707 defer ctx.Cleanup() 708 709 // Wait for it to start 710 go func() { 711 testWaitForTaskToStart(t, ctx) 712 ctx.tr.Restart("test", "restart", false) 713 714 // Wait for it to restart then kill 715 go func() { 716 // Wait for the task to start again 717 testutil.WaitForResult(func() (bool, error) { 718 if len(ctx.upd.events) != 8 { 719 return false, fmt.Errorf("task %q in alloc %q should have 8 ctx.updates: %#v", task.Name, alloc.ID, ctx.upd.events) 720 } 721 722 return true, nil 723 }, func(err error) { 724 t.Fatalf("err: %v", err) 725 }) 726 ctx.tr.Kill("test", "restart", false) 727 }() 728 }() 729 730 select { 731 case <-ctx.tr.WaitCh(): 732 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 733 t.Fatalf("timeout") 734 } 735 736 if len(ctx.upd.events) != 10 { 737 t.Fatalf("should have 10 ctx.updates: %#v", ctx.upd.events) 738 } 739 740 if ctx.upd.state != structs.TaskStateDead { 741 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 742 } 743 744 if ctx.upd.events[0].Type != structs.TaskReceived { 745 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 746 } 747 748 if ctx.upd.events[1].Type != structs.TaskSetup { 749 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 750 } 751 752 if ctx.upd.events[2].Type != structs.TaskStarted { 753 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 754 } 755 756 if ctx.upd.events[3].Type != structs.TaskRestartSignal { 757 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestartSignal) 758 } 759 760 if ctx.upd.events[4].Type != structs.TaskKilling { 761 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilling) 762 } 763 764 if ctx.upd.events[5].Type != structs.TaskKilled { 765 t.Fatalf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskKilled) 766 } 767 768 if ctx.upd.events[6].Type != structs.TaskRestarting { 769 t.Fatalf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskRestarting) 770 } 771 772 if ctx.upd.events[7].Type != structs.TaskStarted { 773 t.Fatalf("Eighth Event was %v; want %v", ctx.upd.events[8].Type, structs.TaskStarted) 774 } 775 if ctx.upd.events[8].Type != structs.TaskKilling { 776 t.Fatalf("Ninth Event was %v; want %v", ctx.upd.events[8].Type, structs.TaskKilling) 777 } 778 779 if ctx.upd.events[9].Type != structs.TaskKilled { 780 t.Fatalf("Tenth Event was %v; want %v", ctx.upd.events[9].Type, structs.TaskKilled) 781 } 782 } 783 784 func TestTaskRunner_KillTask(t *testing.T) { 785 t.Parallel() 786 alloc := mock.Alloc() 787 task := alloc.Job.TaskGroups[0].Tasks[0] 788 task.Driver = "mock_driver" 789 task.Config = map[string]interface{}{ 790 "exit_code": "0", 791 "run_for": "10s", 792 } 793 794 ctx := testTaskRunnerFromAlloc(t, false, alloc) 795 ctx.tr.MarkReceived() 796 go ctx.tr.Run() 797 defer ctx.Cleanup() 798 799 go func() { 800 testWaitForTaskToStart(t, ctx) 801 ctx.tr.Kill("test", "kill", true) 802 }() 803 804 select { 805 case <-ctx.tr.WaitCh(): 806 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 807 t.Fatalf("timeout") 808 } 809 810 if len(ctx.upd.events) != 5 { 811 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 812 } 813 814 if ctx.upd.state != structs.TaskStateDead { 815 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 816 } 817 818 if !ctx.upd.failed { 819 t.Fatalf("TaskState should be failed: %+v", ctx.upd) 820 } 821 822 if ctx.upd.events[0].Type != structs.TaskReceived { 823 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 824 } 825 826 if ctx.upd.events[1].Type != structs.TaskSetup { 827 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 828 } 829 830 if ctx.upd.events[2].Type != structs.TaskStarted { 831 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 832 } 833 834 if ctx.upd.events[3].Type != structs.TaskKilling { 835 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskKilling) 836 } 837 838 if ctx.upd.events[4].Type != structs.TaskKilled { 839 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilled) 840 } 841 } 842 843 func TestTaskRunner_SignalFailure(t *testing.T) { 844 t.Parallel() 845 alloc := mock.Alloc() 846 task := alloc.Job.TaskGroups[0].Tasks[0] 847 task.Driver = "mock_driver" 848 task.Config = map[string]interface{}{ 849 "exit_code": "0", 850 "run_for": "10s", 851 "signal_error": "test forcing failure", 852 } 853 854 ctx := testTaskRunnerFromAlloc(t, false, alloc) 855 ctx.tr.MarkReceived() 856 go ctx.tr.Run() 857 defer ctx.Cleanup() 858 859 // Wait for the task to start 860 testWaitForTaskToStart(t, ctx) 861 862 if err := ctx.tr.Signal("test", "test", syscall.SIGINT); err == nil { 863 t.Fatalf("Didn't receive error") 864 } 865 } 866 867 func TestTaskRunner_BlockForVault(t *testing.T) { 868 t.Parallel() 869 alloc := mock.Alloc() 870 task := alloc.Job.TaskGroups[0].Tasks[0] 871 task.Driver = "mock_driver" 872 task.Config = map[string]interface{}{ 873 "exit_code": "0", 874 "run_for": "1s", 875 } 876 task.Vault = &structs.Vault{Policies: []string{"default"}} 877 878 ctx := testTaskRunnerFromAlloc(t, false, alloc) 879 ctx.tr.MarkReceived() 880 defer ctx.Cleanup() 881 882 // Control when we get a Vault token 883 token := "1234" 884 waitCh := make(chan struct{}) 885 handler := func(*structs.Allocation, []string) (map[string]string, error) { 886 <-waitCh 887 return map[string]string{task.Name: token}, nil 888 } 889 ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler 890 891 go ctx.tr.Run() 892 893 select { 894 case <-ctx.tr.WaitCh(): 895 t.Fatalf("premature exit") 896 case <-time.After(1 * time.Second): 897 } 898 899 if len(ctx.upd.events) != 2 { 900 t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events) 901 } 902 903 if ctx.upd.state != structs.TaskStatePending { 904 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending) 905 } 906 907 if ctx.upd.events[0].Type != structs.TaskReceived { 908 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 909 } 910 911 if ctx.upd.events[1].Type != structs.TaskSetup { 912 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 913 } 914 915 // Unblock 916 close(waitCh) 917 918 select { 919 case <-ctx.tr.WaitCh(): 920 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 921 t.Fatalf("timeout") 922 } 923 924 if len(ctx.upd.events) != 4 { 925 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 926 } 927 928 if ctx.upd.state != structs.TaskStateDead { 929 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 930 } 931 932 if ctx.upd.events[0].Type != structs.TaskReceived { 933 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 934 } 935 936 if ctx.upd.events[1].Type != structs.TaskSetup { 937 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 938 } 939 940 if ctx.upd.events[2].Type != structs.TaskStarted { 941 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 942 } 943 944 if ctx.upd.events[3].Type != structs.TaskTerminated { 945 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 946 } 947 948 // Check that the token is on disk 949 tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile) 950 data, err := ioutil.ReadFile(tokenPath) 951 if err != nil { 952 t.Fatalf("Failed to read file: %v", err) 953 } 954 955 if act := string(data); act != token { 956 t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token) 957 } 958 959 // Check the token was revoked 960 m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 961 testutil.WaitForResult(func() (bool, error) { 962 if len(m.StoppedTokens) != 1 { 963 return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens) 964 } 965 966 if a := m.StoppedTokens[0]; a != token { 967 return false, fmt.Errorf("got stopped token %q; want %q", a, token) 968 } 969 return true, nil 970 }, func(err error) { 971 t.Fatalf("err: %v", err) 972 }) 973 } 974 975 func TestTaskRunner_DeriveToken_Retry(t *testing.T) { 976 t.Parallel() 977 alloc := mock.Alloc() 978 task := alloc.Job.TaskGroups[0].Tasks[0] 979 task.Driver = "mock_driver" 980 task.Config = map[string]interface{}{ 981 "exit_code": "0", 982 "run_for": "1s", 983 } 984 task.Vault = &structs.Vault{Policies: []string{"default"}} 985 986 ctx := testTaskRunnerFromAlloc(t, false, alloc) 987 ctx.tr.MarkReceived() 988 defer ctx.Cleanup() 989 990 // Control when we get a Vault token 991 token := "1234" 992 count := 0 993 handler := func(*structs.Allocation, []string) (map[string]string, error) { 994 if count > 0 { 995 return map[string]string{task.Name: token}, nil 996 } 997 998 count++ 999 return nil, structs.NewRecoverableError(fmt.Errorf("Want a retry"), true) 1000 } 1001 ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler 1002 go ctx.tr.Run() 1003 1004 select { 1005 case <-ctx.tr.WaitCh(): 1006 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1007 t.Fatalf("timeout") 1008 } 1009 1010 if len(ctx.upd.events) != 4 { 1011 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 1012 } 1013 1014 if ctx.upd.state != structs.TaskStateDead { 1015 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1016 } 1017 1018 if ctx.upd.events[0].Type != structs.TaskReceived { 1019 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1020 } 1021 1022 if ctx.upd.events[1].Type != structs.TaskSetup { 1023 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1024 } 1025 1026 if ctx.upd.events[2].Type != structs.TaskStarted { 1027 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1028 } 1029 1030 if ctx.upd.events[3].Type != structs.TaskTerminated { 1031 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 1032 } 1033 1034 // Check that the token is on disk 1035 tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile) 1036 data, err := ioutil.ReadFile(tokenPath) 1037 if err != nil { 1038 t.Fatalf("Failed to read file: %v", err) 1039 } 1040 1041 if act := string(data); act != token { 1042 t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token) 1043 } 1044 1045 // Check the token was revoked 1046 m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 1047 testutil.WaitForResult(func() (bool, error) { 1048 if len(m.StoppedTokens) != 1 { 1049 return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens) 1050 } 1051 1052 if a := m.StoppedTokens[0]; a != token { 1053 return false, fmt.Errorf("got stopped token %q; want %q", a, token) 1054 } 1055 return true, nil 1056 }, func(err error) { 1057 t.Fatalf("err: %v", err) 1058 }) 1059 } 1060 1061 func TestTaskRunner_DeriveToken_Unrecoverable(t *testing.T) { 1062 t.Parallel() 1063 alloc := mock.Alloc() 1064 task := alloc.Job.TaskGroups[0].Tasks[0] 1065 task.Driver = "mock_driver" 1066 task.Config = map[string]interface{}{ 1067 "exit_code": "0", 1068 "run_for": "10s", 1069 } 1070 task.Vault = &structs.Vault{ 1071 Policies: []string{"default"}, 1072 ChangeMode: structs.VaultChangeModeRestart, 1073 } 1074 1075 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1076 ctx.tr.MarkReceived() 1077 defer ctx.Cleanup() 1078 1079 // Error the token derivation 1080 vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient) 1081 vc.SetDeriveTokenError(alloc.ID, []string{task.Name}, fmt.Errorf("Non recoverable")) 1082 go ctx.tr.Run() 1083 1084 // Wait for the task to start 1085 testutil.WaitForResult(func() (bool, error) { 1086 if l := len(ctx.upd.events); l != 3 { 1087 return false, fmt.Errorf("Expect 3 events; got %v", l) 1088 } 1089 1090 if ctx.upd.events[0].Type != structs.TaskReceived { 1091 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1092 } 1093 1094 if ctx.upd.events[1].Type != structs.TaskSetup { 1095 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1096 } 1097 1098 if ctx.upd.events[2].Type != structs.TaskKilling { 1099 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskKilling) 1100 } 1101 1102 return true, nil 1103 }, func(err error) { 1104 t.Fatalf("err: %v", err) 1105 }) 1106 } 1107 1108 func TestTaskRunner_Template_Block(t *testing.T) { 1109 t.Parallel() 1110 alloc := mock.Alloc() 1111 task := alloc.Job.TaskGroups[0].Tasks[0] 1112 task.Driver = "mock_driver" 1113 task.Config = map[string]interface{}{ 1114 "exit_code": "0", 1115 "run_for": "1s", 1116 } 1117 task.Templates = []*structs.Template{ 1118 { 1119 EmbeddedTmpl: "{{key \"foo\"}}", 1120 DestPath: "local/test", 1121 ChangeMode: structs.TemplateChangeModeNoop, 1122 }, 1123 } 1124 1125 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1126 ctx.tr.MarkReceived() 1127 go ctx.tr.Run() 1128 defer ctx.Cleanup() 1129 1130 select { 1131 case <-ctx.tr.WaitCh(): 1132 t.Fatalf("premature exit") 1133 case <-time.After(1 * time.Second): 1134 } 1135 1136 if len(ctx.upd.events) != 2 { 1137 t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events) 1138 } 1139 1140 if ctx.upd.state != structs.TaskStatePending { 1141 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending) 1142 } 1143 1144 if ctx.upd.events[0].Type != structs.TaskReceived { 1145 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1146 } 1147 1148 if ctx.upd.events[1].Type != structs.TaskSetup { 1149 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1150 } 1151 1152 // Unblock 1153 ctx.tr.UnblockStart("test") 1154 1155 select { 1156 case <-ctx.tr.WaitCh(): 1157 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1158 t.Fatalf("timeout") 1159 } 1160 1161 if len(ctx.upd.events) != 4 { 1162 t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events) 1163 } 1164 1165 if ctx.upd.state != structs.TaskStateDead { 1166 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1167 } 1168 1169 if ctx.upd.events[0].Type != structs.TaskReceived { 1170 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1171 } 1172 1173 if ctx.upd.events[1].Type != structs.TaskSetup { 1174 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1175 } 1176 1177 if ctx.upd.events[2].Type != structs.TaskStarted { 1178 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1179 } 1180 1181 if ctx.upd.events[3].Type != structs.TaskTerminated { 1182 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 1183 } 1184 } 1185 1186 func TestTaskRunner_Template_Artifact(t *testing.T) { 1187 t.Parallel() 1188 dir, err := os.Getwd() 1189 if err != nil { 1190 t.Fatalf("bad: %v", err) 1191 } 1192 1193 ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(dir, "../../..")))) 1194 defer ts.Close() 1195 1196 alloc := mock.Alloc() 1197 task := alloc.Job.TaskGroups[0].Tasks[0] 1198 task.Driver = "mock_driver" 1199 task.Config = map[string]interface{}{ 1200 "exit_code": "0", 1201 "run_for": "1s", 1202 } 1203 // Create an allocation that has a task that renders a template from an 1204 // artifact 1205 f1 := "CHANGELOG.md" 1206 artifact := structs.TaskArtifact{ 1207 GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1), 1208 } 1209 task.Artifacts = []*structs.TaskArtifact{&artifact} 1210 task.Templates = []*structs.Template{ 1211 { 1212 SourcePath: "CHANGELOG.md", 1213 DestPath: "local/test", 1214 ChangeMode: structs.TemplateChangeModeNoop, 1215 }, 1216 } 1217 1218 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1219 ctx.tr.MarkReceived() 1220 defer ctx.Cleanup() 1221 go ctx.tr.Run() 1222 1223 select { 1224 case <-ctx.tr.WaitCh(): 1225 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1226 t.Fatalf("timeout") 1227 } 1228 1229 if len(ctx.upd.events) != 5 { 1230 t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events) 1231 } 1232 1233 if ctx.upd.state != structs.TaskStateDead { 1234 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1235 } 1236 1237 if ctx.upd.events[0].Type != structs.TaskReceived { 1238 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1239 } 1240 1241 if ctx.upd.events[1].Type != structs.TaskSetup { 1242 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1243 } 1244 1245 if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts { 1246 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts) 1247 } 1248 1249 if ctx.upd.events[3].Type != structs.TaskStarted { 1250 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskStarted) 1251 } 1252 1253 if ctx.upd.events[4].Type != structs.TaskTerminated { 1254 t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskTerminated) 1255 } 1256 1257 // Check that both files exist. 1258 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f1)); err != nil { 1259 t.Fatalf("%v not downloaded", f1) 1260 } 1261 if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.LocalDir, "test")); err != nil { 1262 t.Fatalf("template not rendered") 1263 } 1264 } 1265 1266 func TestTaskRunner_Template_NewVaultToken(t *testing.T) { 1267 t.Parallel() 1268 alloc := mock.Alloc() 1269 task := alloc.Job.TaskGroups[0].Tasks[0] 1270 task.Driver = "mock_driver" 1271 task.Config = map[string]interface{}{ 1272 "exit_code": "0", 1273 "run_for": "1s", 1274 } 1275 task.Templates = []*structs.Template{ 1276 { 1277 EmbeddedTmpl: "{{key \"foo\"}}", 1278 DestPath: "local/test", 1279 ChangeMode: structs.TemplateChangeModeNoop, 1280 }, 1281 } 1282 task.Vault = &structs.Vault{Policies: []string{"default"}} 1283 1284 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1285 ctx.tr.MarkReceived() 1286 defer ctx.Cleanup() 1287 go ctx.tr.Run() 1288 1289 // Wait for a Vault token 1290 var token string 1291 testutil.WaitForResult(func() (bool, error) { 1292 if token = ctx.tr.vaultFuture.Get(); token == "" { 1293 return false, fmt.Errorf("No Vault token") 1294 } 1295 1296 return true, nil 1297 }, func(err error) { 1298 t.Fatalf("err: %v", err) 1299 }) 1300 1301 // Error the token renewal 1302 renewalCh, ok := ctx.vault.RenewTokens[token] 1303 if !ok { 1304 t.Fatalf("no renewal channel") 1305 } 1306 1307 originalManager := ctx.tr.templateManager 1308 1309 renewalCh <- fmt.Errorf("Test killing") 1310 close(renewalCh) 1311 1312 // Wait for a new Vault token 1313 var token2 string 1314 testutil.WaitForResult(func() (bool, error) { 1315 if token2 = ctx.tr.vaultFuture.Get(); token2 == "" || token2 == token { 1316 return false, fmt.Errorf("No new Vault token") 1317 } 1318 1319 if originalManager == ctx.tr.templateManager { 1320 return false, fmt.Errorf("Template manager not ctx.updated") 1321 } 1322 1323 return true, nil 1324 }, func(err error) { 1325 t.Fatalf("err: %v", err) 1326 }) 1327 1328 // Check the token was revoked 1329 testutil.WaitForResult(func() (bool, error) { 1330 if len(ctx.vault.StoppedTokens) != 1 { 1331 return false, fmt.Errorf("Expected a stopped token: %v", ctx.vault.StoppedTokens) 1332 } 1333 1334 if a := ctx.vault.StoppedTokens[0]; a != token { 1335 return false, fmt.Errorf("got stopped token %q; want %q", a, token) 1336 } 1337 return true, nil 1338 }, func(err error) { 1339 t.Fatalf("err: %v", err) 1340 }) 1341 } 1342 1343 func TestTaskRunner_VaultManager_Restart(t *testing.T) { 1344 t.Parallel() 1345 alloc := mock.Alloc() 1346 task := alloc.Job.TaskGroups[0].Tasks[0] 1347 task.Driver = "mock_driver" 1348 task.Config = map[string]interface{}{ 1349 "exit_code": "0", 1350 "run_for": "10s", 1351 } 1352 task.Vault = &structs.Vault{ 1353 Policies: []string{"default"}, 1354 ChangeMode: structs.VaultChangeModeRestart, 1355 } 1356 1357 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1358 ctx.tr.MarkReceived() 1359 defer ctx.Cleanup() 1360 go ctx.tr.Run() 1361 1362 // Wait for the task to start 1363 testWaitForTaskToStart(t, ctx) 1364 1365 // Error the token renewal 1366 renewalCh, ok := ctx.vault.RenewTokens[ctx.tr.vaultFuture.Get()] 1367 if !ok { 1368 t.Fatalf("no renewal channel") 1369 } 1370 1371 renewalCh <- fmt.Errorf("Test killing") 1372 close(renewalCh) 1373 1374 // Ensure a restart 1375 testutil.WaitForResult(func() (bool, error) { 1376 if l := len(ctx.upd.events); l != 8 { 1377 return false, fmt.Errorf("Expect eight events; got %#v", ctx.upd.events) 1378 } 1379 1380 if ctx.upd.events[0].Type != structs.TaskReceived { 1381 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1382 } 1383 1384 if ctx.upd.events[1].Type != structs.TaskSetup { 1385 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskStarted) 1386 } 1387 1388 if ctx.upd.events[2].Type != structs.TaskStarted { 1389 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1390 } 1391 1392 if ctx.upd.events[3].Type != structs.TaskRestartSignal { 1393 return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestartSignal) 1394 } 1395 1396 if ctx.upd.events[4].Type != structs.TaskKilling { 1397 return false, fmt.Errorf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilling) 1398 } 1399 1400 if ctx.upd.events[5].Type != structs.TaskKilled { 1401 return false, fmt.Errorf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskKilled) 1402 } 1403 1404 if ctx.upd.events[6].Type != structs.TaskRestarting { 1405 return false, fmt.Errorf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskRestarting) 1406 } 1407 1408 if ctx.upd.events[7].Type != structs.TaskStarted { 1409 return false, fmt.Errorf("Eight Event was %v; want %v", ctx.upd.events[7].Type, structs.TaskStarted) 1410 } 1411 1412 return true, nil 1413 }, func(err error) { 1414 t.Fatalf("err: %v", err) 1415 }) 1416 } 1417 1418 func TestTaskRunner_VaultManager_Signal(t *testing.T) { 1419 t.Parallel() 1420 alloc := mock.Alloc() 1421 task := alloc.Job.TaskGroups[0].Tasks[0] 1422 task.Driver = "mock_driver" 1423 task.Config = map[string]interface{}{ 1424 "exit_code": "0", 1425 "run_for": "10s", 1426 } 1427 task.Vault = &structs.Vault{ 1428 Policies: []string{"default"}, 1429 ChangeMode: structs.VaultChangeModeSignal, 1430 ChangeSignal: "SIGUSR1", 1431 } 1432 1433 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1434 ctx.tr.MarkReceived() 1435 go ctx.tr.Run() 1436 defer ctx.Cleanup() 1437 1438 // Wait for the task to start 1439 testWaitForTaskToStart(t, ctx) 1440 1441 // Error the token renewal 1442 renewalCh, ok := ctx.vault.RenewTokens[ctx.tr.vaultFuture.Get()] 1443 if !ok { 1444 t.Fatalf("no renewal channel") 1445 } 1446 1447 renewalCh <- fmt.Errorf("Test killing") 1448 close(renewalCh) 1449 1450 // Ensure a restart 1451 testutil.WaitForResult(func() (bool, error) { 1452 if l := len(ctx.upd.events); l != 4 { 1453 return false, fmt.Errorf("Expect four events; got %#v", ctx.upd.events) 1454 } 1455 1456 if ctx.upd.events[0].Type != structs.TaskReceived { 1457 return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1458 } 1459 1460 if ctx.upd.events[1].Type != structs.TaskSetup { 1461 return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1462 } 1463 1464 if ctx.upd.events[2].Type != structs.TaskStarted { 1465 return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1466 } 1467 1468 if ctx.upd.events[3].Type != structs.TaskSignaling { 1469 return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskSignaling) 1470 } 1471 1472 return true, nil 1473 }, func(err error) { 1474 t.Fatalf("err: %v", err) 1475 }) 1476 } 1477 1478 // Test that the payload is written to disk 1479 func TestTaskRunner_SimpleRun_Dispatch(t *testing.T) { 1480 t.Parallel() 1481 alloc := mock.Alloc() 1482 task := alloc.Job.TaskGroups[0].Tasks[0] 1483 task.Driver = "mock_driver" 1484 task.Config = map[string]interface{}{ 1485 "exit_code": "0", 1486 "run_for": "1s", 1487 } 1488 fileName := "test" 1489 task.DispatchPayload = &structs.DispatchPayloadConfig{ 1490 File: fileName, 1491 } 1492 alloc.Job.ParameterizedJob = &structs.ParameterizedJobConfig{} 1493 1494 // Add an encrypted payload 1495 expected := []byte("hello world") 1496 compressed := snappy.Encode(nil, expected) 1497 alloc.Job.Payload = compressed 1498 1499 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1500 ctx.tr.MarkReceived() 1501 defer ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 1502 defer ctx.allocDir.Destroy() 1503 go ctx.tr.Run() 1504 1505 select { 1506 case <-ctx.tr.WaitCh(): 1507 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1508 t.Fatalf("timeout") 1509 } 1510 1511 if len(ctx.upd.events) != 4 { 1512 t.Fatalf("should have 4 updates: %#v", ctx.upd.events) 1513 } 1514 1515 if ctx.upd.state != structs.TaskStateDead { 1516 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1517 } 1518 1519 if ctx.upd.events[0].Type != structs.TaskReceived { 1520 t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived) 1521 } 1522 1523 if ctx.upd.events[1].Type != structs.TaskSetup { 1524 t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup) 1525 } 1526 1527 if ctx.upd.events[2].Type != structs.TaskStarted { 1528 t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted) 1529 } 1530 1531 if ctx.upd.events[3].Type != structs.TaskTerminated { 1532 t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated) 1533 } 1534 1535 // Check that the file was written to disk properly 1536 payloadPath := filepath.Join(ctx.tr.taskDir.LocalDir, fileName) 1537 data, err := ioutil.ReadFile(payloadPath) 1538 if err != nil { 1539 t.Fatalf("Failed to read file: %v", err) 1540 } 1541 if !reflect.DeepEqual(data, expected) { 1542 t.Fatalf("Bad; got %v; want %v", string(data), string(expected)) 1543 } 1544 } 1545 1546 // TestTaskRunner_CleanupEmpty ensures TaskRunner works when createdResources 1547 // is empty. 1548 func TestTaskRunner_CleanupEmpty(t *testing.T) { 1549 t.Parallel() 1550 alloc := mock.Alloc() 1551 task := alloc.Job.TaskGroups[0].Tasks[0] 1552 task.Driver = "mock_driver" 1553 1554 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1555 ctx.tr.MarkReceived() 1556 1557 defer ctx.Cleanup() 1558 ctx.tr.Run() 1559 1560 // Since we only failed once, createdResources should be empty 1561 if len(ctx.tr.createdResources.Resources) != 0 { 1562 t.Fatalf("createdResources should still be empty: %v", ctx.tr.createdResources) 1563 } 1564 } 1565 1566 func TestTaskRunner_CleanupOK(t *testing.T) { 1567 t.Parallel() 1568 alloc := mock.Alloc() 1569 task := alloc.Job.TaskGroups[0].Tasks[0] 1570 task.Driver = "mock_driver" 1571 key := "ERR" 1572 1573 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1574 ctx.tr.config.Options = map[string]string{ 1575 "cleanup_fail_on": key, 1576 "cleanup_fail_num": "1", 1577 } 1578 ctx.tr.MarkReceived() 1579 1580 ctx.tr.createdResources.Resources[key] = []string{"x", "y"} 1581 ctx.tr.createdResources.Resources["foo"] = []string{"z"} 1582 1583 defer ctx.Cleanup() 1584 ctx.tr.Run() 1585 1586 // Since we only failed once, createdResources should be empty 1587 if len(ctx.tr.createdResources.Resources) > 0 { 1588 t.Fatalf("expected all created resources to be removed: %#v", ctx.tr.createdResources.Resources) 1589 } 1590 } 1591 1592 func TestTaskRunner_CleanupFail(t *testing.T) { 1593 t.Parallel() 1594 alloc := mock.Alloc() 1595 task := alloc.Job.TaskGroups[0].Tasks[0] 1596 task.Driver = "mock_driver" 1597 key := "ERR" 1598 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1599 ctx.tr.config.Options = map[string]string{ 1600 "cleanup_fail_on": key, 1601 "cleanup_fail_num": "5", 1602 } 1603 ctx.tr.MarkReceived() 1604 1605 ctx.tr.createdResources.Resources[key] = []string{"x"} 1606 ctx.tr.createdResources.Resources["foo"] = []string{"y", "z"} 1607 1608 defer ctx.Cleanup() 1609 ctx.tr.Run() 1610 1611 // Since we failed > 3 times, the failed key should remain 1612 expected := map[string][]string{key: {"x"}} 1613 if !reflect.DeepEqual(expected, ctx.tr.createdResources.Resources) { 1614 t.Fatalf("expected %#v but found: %#v", expected, ctx.tr.createdResources.Resources) 1615 } 1616 } 1617 1618 func TestTaskRunner_Pre06ScriptCheck(t *testing.T) { 1619 t.Parallel() 1620 run := func(ver, driver, checkType string, exp bool) (string, func(t *testing.T)) { 1621 name := fmt.Sprintf("%s %s %s returns %t", ver, driver, checkType, exp) 1622 return name, func(t *testing.T) { 1623 services := []*structs.Service{ 1624 { 1625 Checks: []*structs.ServiceCheck{ 1626 { 1627 Type: checkType, 1628 }, 1629 }, 1630 }, 1631 } 1632 if act := pre06ScriptCheck(ver, driver, services); act != exp { 1633 t.Errorf("expected %t received %t", exp, act) 1634 } 1635 } 1636 } 1637 t.Run(run("0.5.6", "exec", "script", true)) 1638 t.Run(run("0.5.6", "java", "script", true)) 1639 t.Run(run("0.5.6", "mock_driver", "script", true)) 1640 t.Run(run("0.5.9", "exec", "script", true)) 1641 t.Run(run("0.5.9", "java", "script", true)) 1642 t.Run(run("0.5.9", "mock_driver", "script", true)) 1643 1644 t.Run(run("0.6.0dev", "exec", "script", false)) 1645 t.Run(run("0.6.0dev", "java", "script", false)) 1646 t.Run(run("0.6.0dev", "mock_driver", "script", false)) 1647 t.Run(run("0.6.0", "exec", "script", false)) 1648 t.Run(run("0.6.0", "java", "script", false)) 1649 t.Run(run("0.6.0", "mock_driver", "script", false)) 1650 t.Run(run("1.0.0", "exec", "script", false)) 1651 t.Run(run("1.0.0", "java", "script", false)) 1652 t.Run(run("1.0.0", "mock_driver", "script", false)) 1653 1654 t.Run(run("0.5.6", "rkt", "script", false)) 1655 t.Run(run("0.5.6", "docker", "script", false)) 1656 t.Run(run("0.5.6", "qemu", "script", false)) 1657 t.Run(run("0.5.6", "raw_exec", "script", false)) 1658 t.Run(run("0.5.6", "invalid", "script", false)) 1659 1660 t.Run(run("0.5.6", "exec", "tcp", false)) 1661 t.Run(run("0.5.6", "java", "tcp", false)) 1662 t.Run(run("0.5.6", "mock_driver", "tcp", false)) 1663 } 1664 1665 func TestTaskRunner_interpolateServices(t *testing.T) { 1666 t.Parallel() 1667 task := &structs.Task{ 1668 Services: []*structs.Service{ 1669 { 1670 Name: "${name}", 1671 PortLabel: "${portlabel}", 1672 Tags: []string{"${tags}"}, 1673 Checks: []*structs.ServiceCheck{ 1674 { 1675 Name: "${checkname}", 1676 Type: "${checktype}", 1677 Command: "${checkcmd}", 1678 Args: []string{"${checkarg}"}, 1679 Path: "${checkstr}", 1680 Protocol: "${checkproto}", 1681 PortLabel: "${checklabel}", 1682 InitialStatus: "${checkstatus}", 1683 Method: "${checkmethod}", 1684 Header: map[string][]string{ 1685 "${checkheaderk}": {"${checkheaderv}"}, 1686 }, 1687 }, 1688 }, 1689 }, 1690 }, 1691 } 1692 1693 env := &env.TaskEnv{ 1694 EnvMap: map[string]string{ 1695 "name": "name", 1696 "portlabel": "portlabel", 1697 "tags": "tags", 1698 "checkname": "checkname", 1699 "checktype": "checktype", 1700 "checkcmd": "checkcmd", 1701 "checkarg": "checkarg", 1702 "checkstr": "checkstr", 1703 "checkpath": "checkpath", 1704 "checkproto": "checkproto", 1705 "checklabel": "checklabel", 1706 "checkstatus": "checkstatus", 1707 "checkmethod": "checkmethod", 1708 "checkheaderk": "checkheaderk", 1709 "checkheaderv": "checkheaderv", 1710 }, 1711 } 1712 1713 interpTask := interpolateServices(env, task) 1714 1715 exp := &structs.Task{ 1716 Services: []*structs.Service{ 1717 { 1718 Name: "name", 1719 PortLabel: "portlabel", 1720 Tags: []string{"tags"}, 1721 Checks: []*structs.ServiceCheck{ 1722 { 1723 Name: "checkname", 1724 Type: "checktype", 1725 Command: "checkcmd", 1726 Args: []string{"checkarg"}, 1727 Path: "checkstr", 1728 Protocol: "checkproto", 1729 PortLabel: "checklabel", 1730 InitialStatus: "checkstatus", 1731 Method: "checkmethod", 1732 Header: map[string][]string{ 1733 "checkheaderk": {"checkheaderv"}, 1734 }, 1735 }, 1736 }, 1737 }, 1738 }, 1739 } 1740 1741 if diff := pretty.Diff(interpTask, exp); len(diff) > 0 { 1742 t.Fatalf("diff:\n%s\n", strings.Join(diff, "\n")) 1743 } 1744 } 1745 1746 func TestTaskRunner_ShutdownDelay(t *testing.T) { 1747 t.Parallel() 1748 1749 alloc := mock.Alloc() 1750 task := alloc.Job.TaskGroups[0].Tasks[0] 1751 task.Services[0].Tags = []string{"tag1"} 1752 task.Services = task.Services[:1] // only need 1 for this test 1753 task.Driver = "mock_driver" 1754 task.Config = map[string]interface{}{ 1755 "run_for": "1000s", 1756 } 1757 1758 // No shutdown escape hatch for this delay, so don't set it too high 1759 task.ShutdownDelay = 500 * time.Duration(testutil.TestMultiplier()) * time.Millisecond 1760 1761 ctx := testTaskRunnerFromAlloc(t, true, alloc) 1762 ctx.tr.MarkReceived() 1763 go ctx.tr.Run() 1764 defer ctx.Cleanup() 1765 1766 // Wait for the task to start 1767 testWaitForTaskToStart(t, ctx) 1768 1769 testutil.WaitForResult(func() (bool, error) { 1770 services, _ := ctx.consul.Services() 1771 if n := len(services); n != 1 { 1772 return false, fmt.Errorf("expected 1 service found %d", n) 1773 } 1774 for _, s := range services { 1775 if !reflect.DeepEqual(s.Tags, task.Services[0].Tags) { 1776 return false, fmt.Errorf("expected tags=%q but found %q", 1777 strings.Join(task.Services[0].Tags, ","), strings.Join(s.Tags, ",")) 1778 } 1779 } 1780 return true, nil 1781 }, func(err error) { 1782 services, _ := ctx.consul.Services() 1783 for _, s := range services { 1784 t.Logf("Service: %#v", s) 1785 } 1786 t.Fatalf("err: %v", err) 1787 }) 1788 1789 // Begin the tear down 1790 ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled)) 1791 destroyed := time.Now() 1792 1793 testutil.WaitForResult(func() (bool, error) { 1794 services, _ := ctx.consul.Services() 1795 if n := len(services); n == 1 { 1796 return false, fmt.Errorf("expected 0 services found %d", n) 1797 } 1798 return true, nil 1799 }, func(err error) { 1800 t.Fatalf("err: %v", err) 1801 }) 1802 1803 // Wait for actual exit 1804 select { 1805 case <-ctx.tr.WaitCh(): 1806 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1807 t.Fatalf("timeout") 1808 } 1809 1810 // It should be impossible to reach here in less time than the shutdown delay 1811 if time.Now().Before(destroyed.Add(task.ShutdownDelay)) { 1812 t.Fatalf("task exited before shutdown delay") 1813 } 1814 } 1815 1816 // TestTaskRunner_CheckWatcher_Restart asserts that when enabled an unhealthy 1817 // Consul check will cause a task to restart following restart policy rules. 1818 func TestTaskRunner_CheckWatcher_Restart(t *testing.T) { 1819 t.Parallel() 1820 1821 alloc := mock.Alloc() 1822 1823 // Make the restart policy fail within this test 1824 tg := alloc.Job.TaskGroups[0] 1825 tg.RestartPolicy.Attempts = 2 1826 tg.RestartPolicy.Interval = 1 * time.Minute 1827 tg.RestartPolicy.Delay = 10 * time.Millisecond 1828 tg.RestartPolicy.Mode = structs.RestartPolicyModeFail 1829 1830 task := tg.Tasks[0] 1831 task.Driver = "mock_driver" 1832 task.Config = map[string]interface{}{ 1833 "exit_code": "0", 1834 "run_for": "100s", 1835 } 1836 1837 // Make the task register a check that fails 1838 task.Services[0].Checks[0] = &structs.ServiceCheck{ 1839 Name: "test-restarts", 1840 Type: structs.ServiceCheckTCP, 1841 Interval: 50 * time.Millisecond, 1842 CheckRestart: &structs.CheckRestart{ 1843 Limit: 2, 1844 Grace: 100 * time.Millisecond, 1845 }, 1846 } 1847 1848 ctx := testTaskRunnerFromAlloc(t, true, alloc) 1849 1850 // Replace mock Consul ServiceClient, with the real ServiceClient 1851 // backed by a mock consul whose checks are always unhealthy. 1852 consulAgent := consul.NewMockAgent() 1853 consulAgent.SetStatus("critical") 1854 consulClient := consul.NewServiceClient(consulAgent, ctx.tr.logger, true) 1855 go consulClient.Run() 1856 defer consulClient.Shutdown() 1857 1858 ctx.tr.consul = consulClient 1859 ctx.consul = nil // prevent accidental use of old mock 1860 1861 ctx.tr.MarkReceived() 1862 go ctx.tr.Run() 1863 defer ctx.Cleanup() 1864 1865 select { 1866 case <-ctx.tr.WaitCh(): 1867 case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second): 1868 t.Fatalf("timeout") 1869 } 1870 1871 expected := []string{ 1872 "Received", 1873 "Task Setup", 1874 "Started", 1875 "Restart Signaled", 1876 "Killing", 1877 "Killed", 1878 "Restarting", 1879 "Started", 1880 "Restart Signaled", 1881 "Killing", 1882 "Killed", 1883 "Restarting", 1884 "Started", 1885 "Restart Signaled", 1886 "Killing", 1887 "Killed", 1888 "Not Restarting", 1889 } 1890 1891 if n := len(ctx.upd.events); n != len(expected) { 1892 t.Fatalf("should have %d ctx.updates found %d: %s", len(expected), n, ctx.upd) 1893 } 1894 1895 if ctx.upd.state != structs.TaskStateDead { 1896 t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead) 1897 } 1898 1899 if !ctx.upd.failed { 1900 t.Fatalf("expected failed") 1901 } 1902 1903 for i, actual := range ctx.upd.events { 1904 if actual.Type != expected[i] { 1905 t.Errorf("%.2d - Expected %q but found %q", i, expected[i], actual.Type) 1906 } 1907 } 1908 } 1909 1910 // TestTaskRunner_DriverNetwork asserts that a driver's network is properly 1911 // used in services and checks. 1912 func TestTaskRunner_DriverNetwork(t *testing.T) { 1913 t.Parallel() 1914 1915 alloc := mock.Alloc() 1916 task := alloc.Job.TaskGroups[0].Tasks[0] 1917 task.Driver = "mock_driver" 1918 task.Config = map[string]interface{}{ 1919 "exit_code": 0, 1920 "run_for": "100s", 1921 "driver_ip": "10.1.2.3", 1922 "driver_port_map": "http:80", 1923 } 1924 1925 // Create services and checks with custom address modes to exercise 1926 // address detection logic 1927 task.Services = []*structs.Service{ 1928 { 1929 Name: "host-service", 1930 PortLabel: "http", 1931 AddressMode: "host", 1932 Checks: []*structs.ServiceCheck{ 1933 { 1934 Name: "driver-check", 1935 Type: "tcp", 1936 PortLabel: "1234", 1937 AddressMode: "driver", 1938 }, 1939 }, 1940 }, 1941 { 1942 Name: "driver-service", 1943 PortLabel: "5678", 1944 AddressMode: "driver", 1945 Checks: []*structs.ServiceCheck{ 1946 { 1947 Name: "host-check", 1948 Type: "tcp", 1949 PortLabel: "http", 1950 }, 1951 { 1952 Name: "driver-label-check", 1953 Type: "tcp", 1954 PortLabel: "http", 1955 AddressMode: "driver", 1956 }, 1957 }, 1958 }, 1959 } 1960 1961 ctx := testTaskRunnerFromAlloc(t, false, alloc) 1962 ctx.tr.MarkReceived() 1963 go ctx.tr.Run() 1964 defer ctx.Cleanup() 1965 1966 // Wait for the task to start 1967 testWaitForTaskToStart(t, ctx) 1968 1969 testutil.WaitForResult(func() (bool, error) { 1970 services, _ := ctx.consul.Services() 1971 if n := len(services); n != 2 { 1972 return false, fmt.Errorf("expected 2 services, but found %d", n) 1973 } 1974 for _, s := range services { 1975 switch s.Service { 1976 case "host-service": 1977 if expected := "192.168.0.100"; s.Address != expected { 1978 return false, fmt.Errorf("expected host-service to have IP=%s but found %s", 1979 expected, s.Address) 1980 } 1981 case "driver-service": 1982 if expected := "10.1.2.3"; s.Address != expected { 1983 return false, fmt.Errorf("expected driver-service to have IP=%s but found %s", 1984 expected, s.Address) 1985 } 1986 if expected := 5678; s.Port != expected { 1987 return false, fmt.Errorf("expected driver-service to have port=%d but found %d", 1988 expected, s.Port) 1989 } 1990 default: 1991 return false, fmt.Errorf("unexpected service: %q", s.Service) 1992 } 1993 1994 } 1995 1996 checks := ctx.consul.CheckRegs() 1997 if n := len(checks); n != 3 { 1998 return false, fmt.Errorf("expected 3 checks, but found %d", n) 1999 } 2000 for _, check := range checks { 2001 switch check.Name { 2002 case "driver-check": 2003 if expected := "10.1.2.3:1234"; check.TCP != expected { 2004 return false, fmt.Errorf("expected driver-check to have address %q but found %q", expected, check.TCP) 2005 } 2006 case "driver-label-check": 2007 if expected := "10.1.2.3:80"; check.TCP != expected { 2008 return false, fmt.Errorf("expected driver-label-check to have address %q but found %q", expected, check.TCP) 2009 } 2010 case "host-check": 2011 if expected := "192.168.0.100:"; !strings.HasPrefix(check.TCP, expected) { 2012 return false, fmt.Errorf("expected host-check to have address start with %q but found %q", expected, check.TCP) 2013 } 2014 default: 2015 return false, fmt.Errorf("unexpected check: %q", check.Name) 2016 } 2017 } 2018 2019 return true, nil 2020 }, func(err error) { 2021 services, _ := ctx.consul.Services() 2022 for _, s := range services { 2023 t.Logf(pretty.Sprint("Service: ", s)) 2024 } 2025 for _, c := range ctx.consul.CheckRegs() { 2026 t.Logf(pretty.Sprint("Check: ", c)) 2027 } 2028 t.Fatalf("error: %v", err) 2029 }) 2030 }