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