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