github.com/anuvu/nomad@v0.8.7-atom1/nomad/state/state_store_test.go (about) 1 package state 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 "sort" 8 "strings" 9 "testing" 10 "time" 11 12 memdb "github.com/hashicorp/go-memdb" 13 "github.com/hashicorp/nomad/helper" 14 "github.com/hashicorp/nomad/helper/uuid" 15 "github.com/hashicorp/nomad/nomad/mock" 16 "github.com/hashicorp/nomad/nomad/structs" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func testStateStore(t *testing.T) *StateStore { 22 return TestStateStore(t) 23 } 24 25 func TestStateStore_Blocking_Error(t *testing.T) { 26 t.Parallel() 27 expected := fmt.Errorf("test error") 28 errFn := func(memdb.WatchSet, *StateStore) (interface{}, uint64, error) { 29 return nil, 0, expected 30 } 31 32 state := testStateStore(t) 33 _, idx, err := state.BlockingQuery(errFn, 10, context.Background()) 34 assert.EqualError(t, err, expected.Error()) 35 assert.Zero(t, idx) 36 } 37 38 func TestStateStore_Blocking_Timeout(t *testing.T) { 39 t.Parallel() 40 noopFn := func(memdb.WatchSet, *StateStore) (interface{}, uint64, error) { 41 return nil, 5, nil 42 } 43 44 state := testStateStore(t) 45 timeout := time.Now().Add(250 * time.Millisecond) 46 deadlineCtx, cancel := context.WithDeadline(context.Background(), timeout) 47 defer cancel() 48 49 _, idx, err := state.BlockingQuery(noopFn, 10, deadlineCtx) 50 assert.EqualError(t, err, context.DeadlineExceeded.Error()) 51 assert.EqualValues(t, 5, idx) 52 assert.WithinDuration(t, timeout, time.Now(), 100*time.Millisecond) 53 } 54 55 func TestStateStore_Blocking_MinQuery(t *testing.T) { 56 node := mock.Node() 57 count := 0 58 queryFn := func(ws memdb.WatchSet, s *StateStore) (interface{}, uint64, error) { 59 _, err := s.NodeByID(ws, node.ID) 60 if err != nil { 61 return nil, 0, err 62 } 63 64 count++ 65 if count == 1 { 66 return false, 5, nil 67 } else if count > 2 { 68 return false, 20, fmt.Errorf("called too many times") 69 } 70 71 return true, 11, nil 72 } 73 74 state := testStateStore(t) 75 timeout := time.Now().Add(100 * time.Millisecond) 76 deadlineCtx, cancel := context.WithDeadline(context.Background(), timeout) 77 defer cancel() 78 79 time.AfterFunc(5*time.Millisecond, func() { 80 state.UpsertNode(11, node) 81 }) 82 83 resp, idx, err := state.BlockingQuery(queryFn, 10, deadlineCtx) 84 if assert.Nil(t, err) { 85 assert.Equal(t, 2, count) 86 assert.EqualValues(t, 11, idx) 87 assert.True(t, resp.(bool)) 88 } 89 } 90 91 // This test checks that: 92 // 1) The job is denormalized 93 // 2) Allocations are created 94 func TestStateStore_UpsertPlanResults_AllocationsCreated_Denormalized(t *testing.T) { 95 state := testStateStore(t) 96 alloc := mock.Alloc() 97 job := alloc.Job 98 alloc.Job = nil 99 100 if err := state.UpsertJob(999, job); err != nil { 101 t.Fatalf("err: %v", err) 102 } 103 104 eval := mock.Eval() 105 eval.JobID = job.ID 106 107 // Create an eval 108 if err := state.UpsertEvals(1, []*structs.Evaluation{eval}); err != nil { 109 t.Fatalf("err: %v", err) 110 } 111 112 // Create a plan result 113 res := structs.ApplyPlanResultsRequest{ 114 AllocUpdateRequest: structs.AllocUpdateRequest{ 115 Alloc: []*structs.Allocation{alloc}, 116 Job: job, 117 }, 118 EvalID: eval.ID, 119 } 120 assert := assert.New(t) 121 err := state.UpsertPlanResults(1000, &res) 122 assert.Nil(err) 123 124 ws := memdb.NewWatchSet() 125 out, err := state.AllocByID(ws, alloc.ID) 126 assert.Nil(err) 127 assert.Equal(alloc, out) 128 129 index, err := state.Index("allocs") 130 assert.Nil(err) 131 assert.EqualValues(1000, index) 132 133 if watchFired(ws) { 134 t.Fatalf("bad") 135 } 136 137 evalOut, err := state.EvalByID(ws, eval.ID) 138 assert.Nil(err) 139 assert.NotNil(evalOut) 140 assert.EqualValues(1000, evalOut.ModifyIndex) 141 } 142 143 // This test checks that the deployment is created and allocations count towards 144 // the deployment 145 func TestStateStore_UpsertPlanResults_Deployment(t *testing.T) { 146 state := testStateStore(t) 147 alloc := mock.Alloc() 148 alloc2 := mock.Alloc() 149 job := alloc.Job 150 alloc.Job = nil 151 alloc2.Job = nil 152 153 d := mock.Deployment() 154 alloc.DeploymentID = d.ID 155 alloc2.DeploymentID = d.ID 156 157 if err := state.UpsertJob(999, job); err != nil { 158 t.Fatalf("err: %v", err) 159 } 160 161 eval := mock.Eval() 162 eval.JobID = job.ID 163 164 // Create an eval 165 if err := state.UpsertEvals(1, []*structs.Evaluation{eval}); err != nil { 166 t.Fatalf("err: %v", err) 167 } 168 169 // Create a plan result 170 res := structs.ApplyPlanResultsRequest{ 171 AllocUpdateRequest: structs.AllocUpdateRequest{ 172 Alloc: []*structs.Allocation{alloc, alloc2}, 173 Job: job, 174 }, 175 Deployment: d, 176 EvalID: eval.ID, 177 } 178 179 err := state.UpsertPlanResults(1000, &res) 180 if err != nil { 181 t.Fatalf("err: %v", err) 182 } 183 184 ws := memdb.NewWatchSet() 185 assert := assert.New(t) 186 out, err := state.AllocByID(ws, alloc.ID) 187 assert.Nil(err) 188 assert.Equal(alloc, out) 189 190 dout, err := state.DeploymentByID(ws, d.ID) 191 assert.Nil(err) 192 assert.NotNil(dout) 193 194 tg, ok := dout.TaskGroups[alloc.TaskGroup] 195 assert.True(ok) 196 assert.NotNil(tg) 197 assert.Equal(2, tg.PlacedAllocs) 198 199 evalOut, err := state.EvalByID(ws, eval.ID) 200 assert.Nil(err) 201 assert.NotNil(evalOut) 202 assert.EqualValues(1000, evalOut.ModifyIndex) 203 204 if watchFired(ws) { 205 t.Fatalf("bad") 206 } 207 208 // Update the allocs to be part of a new deployment 209 d2 := d.Copy() 210 d2.ID = uuid.Generate() 211 212 allocNew := alloc.Copy() 213 allocNew.DeploymentID = d2.ID 214 allocNew2 := alloc2.Copy() 215 allocNew2.DeploymentID = d2.ID 216 217 // Create another plan 218 res = structs.ApplyPlanResultsRequest{ 219 AllocUpdateRequest: structs.AllocUpdateRequest{ 220 Alloc: []*structs.Allocation{allocNew, allocNew2}, 221 Job: job, 222 }, 223 Deployment: d2, 224 EvalID: eval.ID, 225 } 226 227 err = state.UpsertPlanResults(1001, &res) 228 if err != nil { 229 t.Fatalf("err: %v", err) 230 } 231 232 dout, err = state.DeploymentByID(ws, d2.ID) 233 assert.Nil(err) 234 assert.NotNil(dout) 235 236 tg, ok = dout.TaskGroups[alloc.TaskGroup] 237 assert.True(ok) 238 assert.NotNil(tg) 239 assert.Equal(2, tg.PlacedAllocs) 240 241 evalOut, err = state.EvalByID(ws, eval.ID) 242 assert.Nil(err) 243 assert.NotNil(evalOut) 244 assert.EqualValues(1001, evalOut.ModifyIndex) 245 } 246 247 // This test checks that deployment updates are applied correctly 248 func TestStateStore_UpsertPlanResults_DeploymentUpdates(t *testing.T) { 249 state := testStateStore(t) 250 251 // Create a job that applies to all 252 job := mock.Job() 253 if err := state.UpsertJob(998, job); err != nil { 254 t.Fatalf("err: %v", err) 255 } 256 257 // Create a deployment that we will update its status 258 doutstanding := mock.Deployment() 259 doutstanding.JobID = job.ID 260 261 if err := state.UpsertDeployment(1000, doutstanding); err != nil { 262 t.Fatalf("err: %v", err) 263 } 264 265 eval := mock.Eval() 266 eval.JobID = job.ID 267 268 // Create an eval 269 if err := state.UpsertEvals(1, []*structs.Evaluation{eval}); err != nil { 270 t.Fatalf("err: %v", err) 271 } 272 alloc := mock.Alloc() 273 alloc.Job = nil 274 275 dnew := mock.Deployment() 276 dnew.JobID = job.ID 277 alloc.DeploymentID = dnew.ID 278 279 // Update the old deployment 280 update := &structs.DeploymentStatusUpdate{ 281 DeploymentID: doutstanding.ID, 282 Status: "foo", 283 StatusDescription: "bar", 284 } 285 286 // Create a plan result 287 res := structs.ApplyPlanResultsRequest{ 288 AllocUpdateRequest: structs.AllocUpdateRequest{ 289 Alloc: []*structs.Allocation{alloc}, 290 Job: job, 291 }, 292 Deployment: dnew, 293 DeploymentUpdates: []*structs.DeploymentStatusUpdate{update}, 294 EvalID: eval.ID, 295 } 296 297 err := state.UpsertPlanResults(1000, &res) 298 if err != nil { 299 t.Fatalf("err: %v", err) 300 } 301 assert := assert.New(t) 302 ws := memdb.NewWatchSet() 303 304 // Check the deployments are correctly updated. 305 dout, err := state.DeploymentByID(ws, dnew.ID) 306 assert.Nil(err) 307 assert.NotNil(dout) 308 309 tg, ok := dout.TaskGroups[alloc.TaskGroup] 310 assert.True(ok) 311 assert.NotNil(tg) 312 assert.Equal(1, tg.PlacedAllocs) 313 314 doutstandingout, err := state.DeploymentByID(ws, doutstanding.ID) 315 assert.Nil(err) 316 assert.NotNil(doutstandingout) 317 assert.Equal(update.Status, doutstandingout.Status) 318 assert.Equal(update.StatusDescription, doutstandingout.StatusDescription) 319 assert.EqualValues(1000, doutstandingout.ModifyIndex) 320 321 evalOut, err := state.EvalByID(ws, eval.ID) 322 assert.Nil(err) 323 assert.NotNil(evalOut) 324 assert.EqualValues(1000, evalOut.ModifyIndex) 325 if watchFired(ws) { 326 t.Fatalf("bad") 327 } 328 } 329 330 func TestStateStore_UpsertDeployment(t *testing.T) { 331 state := testStateStore(t) 332 deployment := mock.Deployment() 333 334 // Create a watchset so we can test that upsert fires the watch 335 ws := memdb.NewWatchSet() 336 _, err := state.DeploymentsByJobID(ws, deployment.Namespace, deployment.ID) 337 if err != nil { 338 t.Fatalf("bad: %v", err) 339 } 340 341 err = state.UpsertDeployment(1000, deployment) 342 if err != nil { 343 t.Fatalf("err: %v", err) 344 } 345 if !watchFired(ws) { 346 t.Fatalf("bad") 347 } 348 349 ws = memdb.NewWatchSet() 350 out, err := state.DeploymentByID(ws, deployment.ID) 351 if err != nil { 352 t.Fatalf("err: %v", err) 353 } 354 355 if !reflect.DeepEqual(deployment, out) { 356 t.Fatalf("bad: %#v %#v", deployment, out) 357 } 358 359 index, err := state.Index("deployment") 360 if err != nil { 361 t.Fatalf("err: %v", err) 362 } 363 if index != 1000 { 364 t.Fatalf("bad: %d", index) 365 } 366 367 if watchFired(ws) { 368 t.Fatalf("bad") 369 } 370 } 371 372 func TestStateStore_DeleteDeployment(t *testing.T) { 373 state := testStateStore(t) 374 d1 := mock.Deployment() 375 d2 := mock.Deployment() 376 377 err := state.UpsertDeployment(1000, d1) 378 if err != nil { 379 t.Fatalf("err: %v", err) 380 } 381 if err := state.UpsertDeployment(1001, d2); err != nil { 382 t.Fatalf("err: %v", err) 383 } 384 385 // Create a watchset so we can test that delete fires the watch 386 ws := memdb.NewWatchSet() 387 if _, err := state.DeploymentByID(ws, d1.ID); err != nil { 388 t.Fatalf("bad: %v", err) 389 } 390 391 err = state.DeleteDeployment(1002, []string{d1.ID, d2.ID}) 392 if err != nil { 393 t.Fatalf("err: %v", err) 394 } 395 396 if !watchFired(ws) { 397 t.Fatalf("bad") 398 } 399 400 ws = memdb.NewWatchSet() 401 out, err := state.DeploymentByID(ws, d1.ID) 402 if err != nil { 403 t.Fatalf("err: %v", err) 404 } 405 406 if out != nil { 407 t.Fatalf("bad: %#v %#v", d1, out) 408 } 409 410 index, err := state.Index("deployment") 411 if err != nil { 412 t.Fatalf("err: %v", err) 413 } 414 if index != 1002 { 415 t.Fatalf("bad: %d", index) 416 } 417 418 if watchFired(ws) { 419 t.Fatalf("bad") 420 } 421 } 422 423 func TestStateStore_Deployments(t *testing.T) { 424 state := testStateStore(t) 425 var deployments []*structs.Deployment 426 427 for i := 0; i < 10; i++ { 428 deployment := mock.Deployment() 429 deployments = append(deployments, deployment) 430 431 err := state.UpsertDeployment(1000+uint64(i), deployment) 432 if err != nil { 433 t.Fatalf("err: %v", err) 434 } 435 } 436 437 ws := memdb.NewWatchSet() 438 iter, err := state.Deployments(ws) 439 if err != nil { 440 t.Fatalf("err: %v", err) 441 } 442 443 var out []*structs.Deployment 444 for { 445 raw := iter.Next() 446 if raw == nil { 447 break 448 } 449 out = append(out, raw.(*structs.Deployment)) 450 } 451 452 lessThan := func(i, j int) bool { 453 return deployments[i].ID < deployments[j].ID 454 } 455 sort.Slice(deployments, lessThan) 456 sort.Slice(out, lessThan) 457 458 if !reflect.DeepEqual(deployments, out) { 459 t.Fatalf("bad: %#v %#v", deployments, out) 460 } 461 462 if watchFired(ws) { 463 t.Fatalf("bad") 464 } 465 } 466 467 func TestStateStore_DeploymentsByIDPrefix(t *testing.T) { 468 state := testStateStore(t) 469 deploy := mock.Deployment() 470 471 deploy.ID = "11111111-662e-d0ab-d1c9-3e434af7bdb4" 472 err := state.UpsertDeployment(1000, deploy) 473 if err != nil { 474 t.Fatalf("err: %v", err) 475 } 476 477 // Create a watchset so we can test that getters don't cause it to fire 478 ws := memdb.NewWatchSet() 479 iter, err := state.DeploymentsByIDPrefix(ws, deploy.Namespace, deploy.ID) 480 if err != nil { 481 t.Fatalf("err: %v", err) 482 } 483 484 gatherDeploys := func(iter memdb.ResultIterator) []*structs.Deployment { 485 var deploys []*structs.Deployment 486 for { 487 raw := iter.Next() 488 if raw == nil { 489 break 490 } 491 deploy := raw.(*structs.Deployment) 492 deploys = append(deploys, deploy) 493 } 494 return deploys 495 } 496 497 deploys := gatherDeploys(iter) 498 if len(deploys) != 1 { 499 t.Fatalf("err: %v", err) 500 } 501 502 if watchFired(ws) { 503 t.Fatalf("bad") 504 } 505 506 iter, err = state.DeploymentsByIDPrefix(ws, deploy.Namespace, "11") 507 if err != nil { 508 t.Fatalf("err: %v", err) 509 } 510 511 deploys = gatherDeploys(iter) 512 if len(deploys) != 1 { 513 t.Fatalf("err: %v", err) 514 } 515 516 deploy = mock.Deployment() 517 deploy.ID = "11222222-662e-d0ab-d1c9-3e434af7bdb4" 518 err = state.UpsertDeployment(1001, deploy) 519 if err != nil { 520 t.Fatalf("err: %v", err) 521 } 522 523 if !watchFired(ws) { 524 t.Fatalf("bad") 525 } 526 527 ws = memdb.NewWatchSet() 528 iter, err = state.DeploymentsByIDPrefix(ws, deploy.Namespace, "11") 529 if err != nil { 530 t.Fatalf("err: %v", err) 531 } 532 533 deploys = gatherDeploys(iter) 534 if len(deploys) != 2 { 535 t.Fatalf("err: %v", err) 536 } 537 538 iter, err = state.DeploymentsByIDPrefix(ws, deploy.Namespace, "1111") 539 if err != nil { 540 t.Fatalf("err: %v", err) 541 } 542 543 deploys = gatherDeploys(iter) 544 if len(deploys) != 1 { 545 t.Fatalf("err: %v", err) 546 } 547 548 if watchFired(ws) { 549 t.Fatalf("bad") 550 } 551 } 552 553 func TestStateStore_UpsertNode_Node(t *testing.T) { 554 require := require.New(t) 555 state := testStateStore(t) 556 node := mock.Node() 557 558 // Create a watchset so we can test that upsert fires the watch 559 ws := memdb.NewWatchSet() 560 _, err := state.NodeByID(ws, node.ID) 561 require.NoError(err) 562 563 require.NoError(state.UpsertNode(1000, node)) 564 require.True(watchFired(ws)) 565 566 ws = memdb.NewWatchSet() 567 out, err := state.NodeByID(ws, node.ID) 568 require.NoError(err) 569 570 out2, err := state.NodeBySecretID(ws, node.SecretID) 571 require.NoError(err) 572 require.EqualValues(node, out) 573 require.EqualValues(node, out2) 574 require.Len(out.Events, 1) 575 require.Equal(NodeRegisterEventRegistered, out.Events[0].Message) 576 577 index, err := state.Index("nodes") 578 require.NoError(err) 579 require.EqualValues(1000, index) 580 require.False(watchFired(ws)) 581 582 // Transition the node to down and then up and ensure we get a re-register 583 // event 584 down := out.Copy() 585 down.Status = structs.NodeStatusDown 586 require.NoError(state.UpsertNode(1001, down)) 587 require.NoError(state.UpsertNode(1002, out)) 588 589 out, err = state.NodeByID(ws, node.ID) 590 require.NoError(err) 591 require.Len(out.Events, 2) 592 require.Equal(NodeRegisterEventReregistered, out.Events[1].Message) 593 } 594 595 func TestStateStore_DeleteNode_Node(t *testing.T) { 596 state := testStateStore(t) 597 node := mock.Node() 598 599 err := state.UpsertNode(1000, node) 600 if err != nil { 601 t.Fatalf("err: %v", err) 602 } 603 604 // Create a watchset so we can test that delete fires the watch 605 ws := memdb.NewWatchSet() 606 if _, err := state.NodeByID(ws, node.ID); err != nil { 607 t.Fatalf("bad: %v", err) 608 } 609 610 err = state.DeleteNode(1001, node.ID) 611 if err != nil { 612 t.Fatalf("err: %v", err) 613 } 614 615 if !watchFired(ws) { 616 t.Fatalf("bad") 617 } 618 619 ws = memdb.NewWatchSet() 620 out, err := state.NodeByID(ws, node.ID) 621 if err != nil { 622 t.Fatalf("err: %v", err) 623 } 624 625 if out != nil { 626 t.Fatalf("bad: %#v %#v", node, out) 627 } 628 629 index, err := state.Index("nodes") 630 if err != nil { 631 t.Fatalf("err: %v", err) 632 } 633 if index != 1001 { 634 t.Fatalf("bad: %d", index) 635 } 636 637 if watchFired(ws) { 638 t.Fatalf("bad") 639 } 640 } 641 642 func TestStateStore_UpdateNodeStatus_Node(t *testing.T) { 643 require := require.New(t) 644 state := testStateStore(t) 645 node := mock.Node() 646 647 require.NoError(state.UpsertNode(800, node)) 648 649 // Create a watchset so we can test that update node status fires the watch 650 ws := memdb.NewWatchSet() 651 _, err := state.NodeByID(ws, node.ID) 652 require.NoError(err) 653 654 event := &structs.NodeEvent{ 655 Message: "Node ready foo", 656 Subsystem: structs.NodeEventSubsystemCluster, 657 Timestamp: time.Now(), 658 } 659 660 require.NoError(state.UpdateNodeStatus(801, node.ID, structs.NodeStatusReady, event)) 661 require.True(watchFired(ws)) 662 663 ws = memdb.NewWatchSet() 664 out, err := state.NodeByID(ws, node.ID) 665 require.NoError(err) 666 require.Equal(structs.NodeStatusReady, out.Status) 667 require.EqualValues(801, out.ModifyIndex) 668 require.Len(out.Events, 2) 669 require.Equal(event.Message, out.Events[1].Message) 670 671 index, err := state.Index("nodes") 672 require.NoError(err) 673 require.EqualValues(801, index) 674 require.False(watchFired(ws)) 675 } 676 677 func TestStateStore_BatchUpdateNodeDrain(t *testing.T) { 678 require := require.New(t) 679 state := testStateStore(t) 680 681 n1, n2 := mock.Node(), mock.Node() 682 require.Nil(state.UpsertNode(1000, n1)) 683 require.Nil(state.UpsertNode(1001, n2)) 684 685 // Create a watchset so we can test that update node drain fires the watch 686 ws := memdb.NewWatchSet() 687 _, err := state.NodeByID(ws, n1.ID) 688 require.Nil(err) 689 690 expectedDrain := &structs.DrainStrategy{ 691 DrainSpec: structs.DrainSpec{ 692 Deadline: -1 * time.Second, 693 }, 694 } 695 696 update := map[string]*structs.DrainUpdate{ 697 n1.ID: { 698 DrainStrategy: expectedDrain, 699 }, 700 n2.ID: { 701 DrainStrategy: expectedDrain, 702 }, 703 } 704 705 event := &structs.NodeEvent{ 706 Message: "Drain strategy enabled", 707 Subsystem: structs.NodeEventSubsystemDrain, 708 Timestamp: time.Now(), 709 } 710 events := map[string]*structs.NodeEvent{ 711 n1.ID: event, 712 n2.ID: event, 713 } 714 715 require.Nil(state.BatchUpdateNodeDrain(1002, update, events)) 716 require.True(watchFired(ws)) 717 718 ws = memdb.NewWatchSet() 719 for _, id := range []string{n1.ID, n2.ID} { 720 out, err := state.NodeByID(ws, id) 721 require.Nil(err) 722 require.True(out.Drain) 723 require.NotNil(out.DrainStrategy) 724 require.Equal(out.DrainStrategy, expectedDrain) 725 require.Len(out.Events, 2) 726 require.EqualValues(1002, out.ModifyIndex) 727 } 728 729 index, err := state.Index("nodes") 730 require.Nil(err) 731 require.EqualValues(1002, index) 732 require.False(watchFired(ws)) 733 } 734 735 func TestStateStore_UpdateNodeDrain_Node(t *testing.T) { 736 require := require.New(t) 737 state := testStateStore(t) 738 node := mock.Node() 739 740 require.Nil(state.UpsertNode(1000, node)) 741 742 // Create a watchset so we can test that update node drain fires the watch 743 ws := memdb.NewWatchSet() 744 _, err := state.NodeByID(ws, node.ID) 745 require.Nil(err) 746 747 expectedDrain := &structs.DrainStrategy{ 748 DrainSpec: structs.DrainSpec{ 749 Deadline: -1 * time.Second, 750 }, 751 } 752 753 event := &structs.NodeEvent{ 754 Message: "Drain strategy enabled", 755 Subsystem: structs.NodeEventSubsystemDrain, 756 Timestamp: time.Now(), 757 } 758 require.Nil(state.UpdateNodeDrain(1001, node.ID, expectedDrain, false, event)) 759 require.True(watchFired(ws)) 760 761 ws = memdb.NewWatchSet() 762 out, err := state.NodeByID(ws, node.ID) 763 require.Nil(err) 764 require.True(out.Drain) 765 require.NotNil(out.DrainStrategy) 766 require.Equal(out.DrainStrategy, expectedDrain) 767 require.Len(out.Events, 2) 768 require.EqualValues(1001, out.ModifyIndex) 769 770 index, err := state.Index("nodes") 771 require.Nil(err) 772 require.EqualValues(1001, index) 773 require.False(watchFired(ws)) 774 } 775 776 func TestStateStore_AddSingleNodeEvent(t *testing.T) { 777 require := require.New(t) 778 state := testStateStore(t) 779 780 node := mock.Node() 781 782 // We create a new node event every time we register a node 783 err := state.UpsertNode(1000, node) 784 require.Nil(err) 785 786 require.Equal(1, len(node.Events)) 787 require.Equal(structs.NodeEventSubsystemCluster, node.Events[0].Subsystem) 788 require.Equal(NodeRegisterEventRegistered, node.Events[0].Message) 789 790 // Create a watchset so we can test that AddNodeEvent fires the watch 791 ws := memdb.NewWatchSet() 792 _, err = state.NodeByID(ws, node.ID) 793 require.Nil(err) 794 795 nodeEvent := &structs.NodeEvent{ 796 Message: "failed", 797 Subsystem: "Driver", 798 Timestamp: time.Now(), 799 } 800 nodeEvents := map[string][]*structs.NodeEvent{ 801 node.ID: {nodeEvent}, 802 } 803 err = state.UpsertNodeEvents(uint64(1001), nodeEvents) 804 require.Nil(err) 805 806 require.True(watchFired(ws)) 807 808 ws = memdb.NewWatchSet() 809 out, err := state.NodeByID(ws, node.ID) 810 require.Nil(err) 811 812 require.Equal(2, len(out.Events)) 813 require.Equal(nodeEvent, out.Events[1]) 814 } 815 816 // To prevent stale node events from accumulating, we limit the number of 817 // stored node events to 10. 818 func TestStateStore_NodeEvents_RetentionWindow(t *testing.T) { 819 require := require.New(t) 820 state := testStateStore(t) 821 822 node := mock.Node() 823 824 err := state.UpsertNode(1000, node) 825 if err != nil { 826 t.Fatalf("err: %v", err) 827 } 828 require.Equal(1, len(node.Events)) 829 require.Equal(structs.NodeEventSubsystemCluster, node.Events[0].Subsystem) 830 require.Equal(NodeRegisterEventRegistered, node.Events[0].Message) 831 832 var out *structs.Node 833 for i := 1; i <= 20; i++ { 834 ws := memdb.NewWatchSet() 835 out, err = state.NodeByID(ws, node.ID) 836 require.Nil(err) 837 838 nodeEvent := &structs.NodeEvent{ 839 Message: fmt.Sprintf("%dith failed", i), 840 Subsystem: "Driver", 841 Timestamp: time.Now(), 842 } 843 844 nodeEvents := map[string][]*structs.NodeEvent{ 845 out.ID: {nodeEvent}, 846 } 847 err := state.UpsertNodeEvents(uint64(i), nodeEvents) 848 require.Nil(err) 849 850 require.True(watchFired(ws)) 851 ws = memdb.NewWatchSet() 852 out, err = state.NodeByID(ws, node.ID) 853 require.Nil(err) 854 } 855 856 ws := memdb.NewWatchSet() 857 out, err = state.NodeByID(ws, node.ID) 858 require.Nil(err) 859 860 require.Equal(10, len(out.Events)) 861 require.Equal(uint64(11), out.Events[0].CreateIndex) 862 require.Equal(uint64(20), out.Events[len(out.Events)-1].CreateIndex) 863 } 864 865 func TestStateStore_UpdateNodeDrain_ResetEligiblity(t *testing.T) { 866 require := require.New(t) 867 state := testStateStore(t) 868 node := mock.Node() 869 require.Nil(state.UpsertNode(1000, node)) 870 871 // Create a watchset so we can test that update node drain fires the watch 872 ws := memdb.NewWatchSet() 873 _, err := state.NodeByID(ws, node.ID) 874 require.Nil(err) 875 876 drain := &structs.DrainStrategy{ 877 DrainSpec: structs.DrainSpec{ 878 Deadline: -1 * time.Second, 879 }, 880 } 881 882 event1 := &structs.NodeEvent{ 883 Message: "Drain strategy enabled", 884 Subsystem: structs.NodeEventSubsystemDrain, 885 Timestamp: time.Now(), 886 } 887 require.Nil(state.UpdateNodeDrain(1001, node.ID, drain, false, event1)) 888 require.True(watchFired(ws)) 889 890 // Remove the drain 891 event2 := &structs.NodeEvent{ 892 Message: "Drain strategy disabled", 893 Subsystem: structs.NodeEventSubsystemDrain, 894 Timestamp: time.Now(), 895 } 896 require.Nil(state.UpdateNodeDrain(1002, node.ID, nil, true, event2)) 897 898 ws = memdb.NewWatchSet() 899 out, err := state.NodeByID(ws, node.ID) 900 require.Nil(err) 901 require.False(out.Drain) 902 require.Nil(out.DrainStrategy) 903 require.Equal(out.SchedulingEligibility, structs.NodeSchedulingEligible) 904 require.Len(out.Events, 3) 905 require.EqualValues(1002, out.ModifyIndex) 906 907 index, err := state.Index("nodes") 908 require.Nil(err) 909 require.EqualValues(1002, index) 910 require.False(watchFired(ws)) 911 } 912 913 func TestStateStore_UpdateNodeEligibility(t *testing.T) { 914 require := require.New(t) 915 state := testStateStore(t) 916 node := mock.Node() 917 918 err := state.UpsertNode(1000, node) 919 if err != nil { 920 t.Fatalf("err: %v", err) 921 } 922 923 expectedEligibility := structs.NodeSchedulingIneligible 924 925 // Create a watchset so we can test that update node drain fires the watch 926 ws := memdb.NewWatchSet() 927 if _, err := state.NodeByID(ws, node.ID); err != nil { 928 t.Fatalf("bad: %v", err) 929 } 930 931 event := &structs.NodeEvent{ 932 Message: "Node marked as ineligible", 933 Subsystem: structs.NodeEventSubsystemCluster, 934 Timestamp: time.Now(), 935 } 936 require.Nil(state.UpdateNodeEligibility(1001, node.ID, expectedEligibility, event)) 937 require.True(watchFired(ws)) 938 939 ws = memdb.NewWatchSet() 940 out, err := state.NodeByID(ws, node.ID) 941 require.Nil(err) 942 require.Equal(out.SchedulingEligibility, expectedEligibility) 943 require.Len(out.Events, 2) 944 require.Equal(out.Events[1], event) 945 require.EqualValues(1001, out.ModifyIndex) 946 947 index, err := state.Index("nodes") 948 require.Nil(err) 949 require.EqualValues(1001, index) 950 require.False(watchFired(ws)) 951 952 // Set a drain strategy 953 expectedDrain := &structs.DrainStrategy{ 954 DrainSpec: structs.DrainSpec{ 955 Deadline: -1 * time.Second, 956 }, 957 } 958 require.Nil(state.UpdateNodeDrain(1002, node.ID, expectedDrain, false, nil)) 959 960 // Try to set the node to eligible 961 err = state.UpdateNodeEligibility(1003, node.ID, structs.NodeSchedulingEligible, nil) 962 require.NotNil(err) 963 require.Contains(err.Error(), "while it is draining") 964 } 965 966 func TestStateStore_Nodes(t *testing.T) { 967 state := testStateStore(t) 968 var nodes []*structs.Node 969 970 for i := 0; i < 10; i++ { 971 node := mock.Node() 972 nodes = append(nodes, node) 973 974 err := state.UpsertNode(1000+uint64(i), node) 975 if err != nil { 976 t.Fatalf("err: %v", err) 977 } 978 } 979 980 // Create a watchset so we can test that getters don't cause it to fire 981 ws := memdb.NewWatchSet() 982 iter, err := state.Nodes(ws) 983 if err != nil { 984 t.Fatalf("bad: %v", err) 985 } 986 987 var out []*structs.Node 988 for { 989 raw := iter.Next() 990 if raw == nil { 991 break 992 } 993 out = append(out, raw.(*structs.Node)) 994 } 995 996 sort.Sort(NodeIDSort(nodes)) 997 sort.Sort(NodeIDSort(out)) 998 999 if !reflect.DeepEqual(nodes, out) { 1000 t.Fatalf("bad: %#v %#v", nodes, out) 1001 } 1002 1003 if watchFired(ws) { 1004 t.Fatalf("bad") 1005 } 1006 } 1007 1008 func TestStateStore_NodesByIDPrefix(t *testing.T) { 1009 state := testStateStore(t) 1010 node := mock.Node() 1011 1012 node.ID = "11111111-662e-d0ab-d1c9-3e434af7bdb4" 1013 err := state.UpsertNode(1000, node) 1014 if err != nil { 1015 t.Fatalf("err: %v", err) 1016 } 1017 1018 // Create a watchset so we can test that getters don't cause it to fire 1019 ws := memdb.NewWatchSet() 1020 iter, err := state.NodesByIDPrefix(ws, node.ID) 1021 if err != nil { 1022 t.Fatalf("err: %v", err) 1023 } 1024 1025 gatherNodes := func(iter memdb.ResultIterator) []*structs.Node { 1026 var nodes []*structs.Node 1027 for { 1028 raw := iter.Next() 1029 if raw == nil { 1030 break 1031 } 1032 node := raw.(*structs.Node) 1033 nodes = append(nodes, node) 1034 } 1035 return nodes 1036 } 1037 1038 nodes := gatherNodes(iter) 1039 if len(nodes) != 1 { 1040 t.Fatalf("err: %v", err) 1041 } 1042 1043 if watchFired(ws) { 1044 t.Fatalf("bad") 1045 } 1046 1047 iter, err = state.NodesByIDPrefix(ws, "11") 1048 if err != nil { 1049 t.Fatalf("err: %v", err) 1050 } 1051 1052 nodes = gatherNodes(iter) 1053 if len(nodes) != 1 { 1054 t.Fatalf("err: %v", err) 1055 } 1056 1057 node = mock.Node() 1058 node.ID = "11222222-662e-d0ab-d1c9-3e434af7bdb4" 1059 err = state.UpsertNode(1001, node) 1060 if err != nil { 1061 t.Fatalf("err: %v", err) 1062 } 1063 1064 if !watchFired(ws) { 1065 t.Fatalf("bad") 1066 } 1067 1068 ws = memdb.NewWatchSet() 1069 iter, err = state.NodesByIDPrefix(ws, "11") 1070 if err != nil { 1071 t.Fatalf("err: %v", err) 1072 } 1073 1074 nodes = gatherNodes(iter) 1075 if len(nodes) != 2 { 1076 t.Fatalf("err: %v", err) 1077 } 1078 1079 iter, err = state.NodesByIDPrefix(ws, "1111") 1080 if err != nil { 1081 t.Fatalf("err: %v", err) 1082 } 1083 1084 nodes = gatherNodes(iter) 1085 if len(nodes) != 1 { 1086 t.Fatalf("err: %v", err) 1087 } 1088 1089 if watchFired(ws) { 1090 t.Fatalf("bad") 1091 } 1092 } 1093 1094 func TestStateStore_RestoreNode(t *testing.T) { 1095 state := testStateStore(t) 1096 node := mock.Node() 1097 1098 restore, err := state.Restore() 1099 if err != nil { 1100 t.Fatalf("err: %v", err) 1101 } 1102 1103 err = restore.NodeRestore(node) 1104 if err != nil { 1105 t.Fatalf("err: %v", err) 1106 } 1107 restore.Commit() 1108 1109 ws := memdb.NewWatchSet() 1110 out, err := state.NodeByID(ws, node.ID) 1111 if err != nil { 1112 t.Fatalf("err: %v", err) 1113 } 1114 1115 if !reflect.DeepEqual(out, node) { 1116 t.Fatalf("Bad: %#v %#v", out, node) 1117 } 1118 } 1119 1120 func TestStateStore_UpsertJob_Job(t *testing.T) { 1121 state := testStateStore(t) 1122 job := mock.Job() 1123 1124 // Create a watchset so we can test that upsert fires the watch 1125 ws := memdb.NewWatchSet() 1126 _, err := state.JobByID(ws, job.Namespace, job.ID) 1127 if err != nil { 1128 t.Fatalf("bad: %v", err) 1129 } 1130 1131 if err := state.UpsertJob(1000, job); err != nil { 1132 t.Fatalf("err: %v", err) 1133 } 1134 if !watchFired(ws) { 1135 t.Fatalf("bad") 1136 } 1137 1138 ws = memdb.NewWatchSet() 1139 out, err := state.JobByID(ws, job.Namespace, job.ID) 1140 if err != nil { 1141 t.Fatalf("err: %v", err) 1142 } 1143 1144 if !reflect.DeepEqual(job, out) { 1145 t.Fatalf("bad: %#v %#v", job, out) 1146 } 1147 1148 index, err := state.Index("jobs") 1149 if err != nil { 1150 t.Fatalf("err: %v", err) 1151 } 1152 if index != 1000 { 1153 t.Fatalf("bad: %d", index) 1154 } 1155 1156 summary, err := state.JobSummaryByID(ws, job.Namespace, job.ID) 1157 if err != nil { 1158 t.Fatalf("err: %v", err) 1159 } 1160 if summary == nil { 1161 t.Fatalf("nil summary") 1162 } 1163 if summary.JobID != job.ID { 1164 t.Fatalf("bad summary id: %v", summary.JobID) 1165 } 1166 _, ok := summary.Summary["web"] 1167 if !ok { 1168 t.Fatalf("nil summary for task group") 1169 } 1170 if watchFired(ws) { 1171 t.Fatalf("bad") 1172 } 1173 1174 // Check the job versions 1175 allVersions, err := state.JobVersionsByID(ws, job.Namespace, job.ID) 1176 if err != nil { 1177 t.Fatalf("err: %v", err) 1178 } 1179 if len(allVersions) != 1 { 1180 t.Fatalf("got %d; want 1", len(allVersions)) 1181 } 1182 1183 if a := allVersions[0]; a.ID != job.ID || a.Version != 0 { 1184 t.Fatalf("bad: %v", a) 1185 } 1186 1187 // Test the looking up the job by version returns the same results 1188 vout, err := state.JobByIDAndVersion(ws, job.Namespace, job.ID, 0) 1189 if err != nil { 1190 t.Fatalf("err: %v", err) 1191 } 1192 1193 if !reflect.DeepEqual(out, vout) { 1194 t.Fatalf("bad: %#v %#v", out, vout) 1195 } 1196 } 1197 1198 func TestStateStore_UpdateUpsertJob_Job(t *testing.T) { 1199 state := testStateStore(t) 1200 job := mock.Job() 1201 1202 // Create a watchset so we can test that upsert fires the watch 1203 ws := memdb.NewWatchSet() 1204 _, err := state.JobByID(ws, job.Namespace, job.ID) 1205 if err != nil { 1206 t.Fatalf("bad: %v", err) 1207 } 1208 1209 if err := state.UpsertJob(1000, job); err != nil { 1210 t.Fatalf("err: %v", err) 1211 } 1212 1213 job2 := mock.Job() 1214 job2.ID = job.ID 1215 job2.AllAtOnce = true 1216 err = state.UpsertJob(1001, job2) 1217 if err != nil { 1218 t.Fatalf("err: %v", err) 1219 } 1220 1221 if !watchFired(ws) { 1222 t.Fatalf("bad") 1223 } 1224 1225 ws = memdb.NewWatchSet() 1226 out, err := state.JobByID(ws, job.Namespace, job.ID) 1227 if err != nil { 1228 t.Fatalf("err: %v", err) 1229 } 1230 1231 if !reflect.DeepEqual(job2, out) { 1232 t.Fatalf("bad: %#v %#v", job2, out) 1233 } 1234 1235 if out.CreateIndex != 1000 { 1236 t.Fatalf("bad: %#v", out) 1237 } 1238 if out.ModifyIndex != 1001 { 1239 t.Fatalf("bad: %#v", out) 1240 } 1241 if out.Version != 1 { 1242 t.Fatalf("bad: %#v", out) 1243 } 1244 1245 index, err := state.Index("jobs") 1246 if err != nil { 1247 t.Fatalf("err: %v", err) 1248 } 1249 if index != 1001 { 1250 t.Fatalf("bad: %d", index) 1251 } 1252 1253 // Test the looking up the job by version returns the same results 1254 vout, err := state.JobByIDAndVersion(ws, job.Namespace, job.ID, 1) 1255 if err != nil { 1256 t.Fatalf("err: %v", err) 1257 } 1258 1259 if !reflect.DeepEqual(out, vout) { 1260 t.Fatalf("bad: %#v %#v", out, vout) 1261 } 1262 1263 // Test that the job summary remains the same if the job is updated but 1264 // count remains same 1265 summary, err := state.JobSummaryByID(ws, job.Namespace, job.ID) 1266 if err != nil { 1267 t.Fatalf("err: %v", err) 1268 } 1269 if summary == nil { 1270 t.Fatalf("nil summary") 1271 } 1272 if summary.JobID != job.ID { 1273 t.Fatalf("bad summary id: %v", summary.JobID) 1274 } 1275 _, ok := summary.Summary["web"] 1276 if !ok { 1277 t.Fatalf("nil summary for task group") 1278 } 1279 1280 // Check the job versions 1281 allVersions, err := state.JobVersionsByID(ws, job.Namespace, job.ID) 1282 if err != nil { 1283 t.Fatalf("err: %v", err) 1284 } 1285 if len(allVersions) != 2 { 1286 t.Fatalf("got %d; want 1", len(allVersions)) 1287 } 1288 1289 if a := allVersions[0]; a.ID != job.ID || a.Version != 1 || !a.AllAtOnce { 1290 t.Fatalf("bad: %+v", a) 1291 } 1292 if a := allVersions[1]; a.ID != job.ID || a.Version != 0 || a.AllAtOnce { 1293 t.Fatalf("bad: %+v", a) 1294 } 1295 1296 if watchFired(ws) { 1297 t.Fatalf("bad") 1298 } 1299 } 1300 1301 func TestStateStore_UpdateUpsertJob_PeriodicJob(t *testing.T) { 1302 state := testStateStore(t) 1303 job := mock.PeriodicJob() 1304 1305 // Create a watchset so we can test that upsert fires the watch 1306 ws := memdb.NewWatchSet() 1307 _, err := state.JobByID(ws, job.Namespace, job.ID) 1308 if err != nil { 1309 t.Fatalf("bad: %v", err) 1310 } 1311 1312 if err := state.UpsertJob(1000, job); err != nil { 1313 t.Fatalf("err: %v", err) 1314 } 1315 1316 // Create a child and an evaluation 1317 job2 := job.Copy() 1318 job2.Periodic = nil 1319 job2.ID = fmt.Sprintf("%v/%s-1490635020", job.ID, structs.PeriodicLaunchSuffix) 1320 err = state.UpsertJob(1001, job2) 1321 if err != nil { 1322 t.Fatalf("err: %v", err) 1323 } 1324 1325 eval := mock.Eval() 1326 eval.JobID = job2.ID 1327 err = state.UpsertEvals(1002, []*structs.Evaluation{eval}) 1328 if err != nil { 1329 t.Fatalf("err: %v", err) 1330 } 1331 1332 job3 := job.Copy() 1333 job3.TaskGroups[0].Tasks[0].Name = "new name" 1334 err = state.UpsertJob(1003, job3) 1335 if err != nil { 1336 t.Fatalf("err: %v", err) 1337 } 1338 1339 if !watchFired(ws) { 1340 t.Fatalf("bad") 1341 } 1342 1343 ws = memdb.NewWatchSet() 1344 out, err := state.JobByID(ws, job.Namespace, job.ID) 1345 if err != nil { 1346 t.Fatalf("err: %v", err) 1347 } 1348 1349 if s, e := out.Status, structs.JobStatusRunning; s != e { 1350 t.Fatalf("got status %v; want %v", s, e) 1351 } 1352 1353 } 1354 1355 // This test ensures that UpsertJob creates the EphemeralDisk is a job doesn't have 1356 // one and clear out the task's disk resource asks 1357 // COMPAT 0.4.1 -> 0.5 1358 func TestStateStore_UpsertJob_NoEphemeralDisk(t *testing.T) { 1359 state := testStateStore(t) 1360 job := mock.Job() 1361 1362 // Set the EphemeralDisk to nil and set the tasks's DiskMB to 150 1363 job.TaskGroups[0].EphemeralDisk = nil 1364 job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150 1365 1366 err := state.UpsertJob(1000, job) 1367 if err != nil { 1368 t.Fatalf("err: %v", err) 1369 } 1370 1371 ws := memdb.NewWatchSet() 1372 out, err := state.JobByID(ws, job.Namespace, job.ID) 1373 if err != nil { 1374 t.Fatalf("err: %v", err) 1375 } 1376 1377 // Expect the state store to create the EphemeralDisk and clear out Tasks's 1378 // DiskMB 1379 expected := job.Copy() 1380 expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{ 1381 SizeMB: 150, 1382 } 1383 expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 1384 1385 if !reflect.DeepEqual(expected, out) { 1386 t.Fatalf("bad: %#v %#v", expected, out) 1387 } 1388 } 1389 1390 func TestStateStore_UpsertJob_BadNamespace(t *testing.T) { 1391 assert := assert.New(t) 1392 state := testStateStore(t) 1393 job := mock.Job() 1394 job.Namespace = "foo" 1395 1396 err := state.UpsertJob(1000, job) 1397 assert.Contains(err.Error(), "nonexistent namespace") 1398 1399 ws := memdb.NewWatchSet() 1400 out, err := state.JobByID(ws, job.Namespace, job.ID) 1401 assert.Nil(err) 1402 assert.Nil(out) 1403 } 1404 1405 // Upsert a job that is the child of a parent job and ensures its summary gets 1406 // updated. 1407 func TestStateStore_UpsertJob_ChildJob(t *testing.T) { 1408 state := testStateStore(t) 1409 1410 // Create a watchset so we can test that upsert fires the watch 1411 parent := mock.Job() 1412 ws := memdb.NewWatchSet() 1413 _, err := state.JobByID(ws, parent.Namespace, parent.ID) 1414 if err != nil { 1415 t.Fatalf("bad: %v", err) 1416 } 1417 1418 if err := state.UpsertJob(1000, parent); err != nil { 1419 t.Fatalf("err: %v", err) 1420 } 1421 1422 child := mock.Job() 1423 child.ParentID = parent.ID 1424 if err := state.UpsertJob(1001, child); err != nil { 1425 t.Fatalf("err: %v", err) 1426 } 1427 1428 summary, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID) 1429 if err != nil { 1430 t.Fatalf("err: %v", err) 1431 } 1432 if summary == nil { 1433 t.Fatalf("nil summary") 1434 } 1435 if summary.JobID != parent.ID { 1436 t.Fatalf("bad summary id: %v", parent.ID) 1437 } 1438 if summary.Children == nil { 1439 t.Fatalf("nil children summary") 1440 } 1441 if summary.Children.Pending != 1 || summary.Children.Running != 0 || summary.Children.Dead != 0 { 1442 t.Fatalf("bad children summary: %v", summary.Children) 1443 } 1444 if !watchFired(ws) { 1445 t.Fatalf("bad") 1446 } 1447 } 1448 1449 func TestStateStore_UpdateUpsertJob_JobVersion(t *testing.T) { 1450 state := testStateStore(t) 1451 1452 // Create a job and mark it as stable 1453 job := mock.Job() 1454 job.Stable = true 1455 job.Name = "0" 1456 1457 // Create a watchset so we can test that upsert fires the watch 1458 ws := memdb.NewWatchSet() 1459 _, err := state.JobVersionsByID(ws, job.Namespace, job.ID) 1460 if err != nil { 1461 t.Fatalf("bad: %v", err) 1462 } 1463 1464 if err := state.UpsertJob(1000, job); err != nil { 1465 t.Fatalf("err: %v", err) 1466 } 1467 1468 if !watchFired(ws) { 1469 t.Fatalf("bad") 1470 } 1471 1472 var finalJob *structs.Job 1473 for i := 1; i < 300; i++ { 1474 finalJob = mock.Job() 1475 finalJob.ID = job.ID 1476 finalJob.Name = fmt.Sprintf("%d", i) 1477 err = state.UpsertJob(uint64(1000+i), finalJob) 1478 if err != nil { 1479 t.Fatalf("err: %v", err) 1480 } 1481 } 1482 1483 ws = memdb.NewWatchSet() 1484 out, err := state.JobByID(ws, job.Namespace, job.ID) 1485 if err != nil { 1486 t.Fatalf("err: %v", err) 1487 } 1488 1489 if !reflect.DeepEqual(finalJob, out) { 1490 t.Fatalf("bad: %#v %#v", finalJob, out) 1491 } 1492 1493 if out.CreateIndex != 1000 { 1494 t.Fatalf("bad: %#v", out) 1495 } 1496 if out.ModifyIndex != 1299 { 1497 t.Fatalf("bad: %#v", out) 1498 } 1499 if out.Version != 299 { 1500 t.Fatalf("bad: %#v", out) 1501 } 1502 1503 index, err := state.Index("job_version") 1504 if err != nil { 1505 t.Fatalf("err: %v", err) 1506 } 1507 if index != 1299 { 1508 t.Fatalf("bad: %d", index) 1509 } 1510 1511 // Check the job versions 1512 allVersions, err := state.JobVersionsByID(ws, job.Namespace, job.ID) 1513 if err != nil { 1514 t.Fatalf("err: %v", err) 1515 } 1516 if len(allVersions) != structs.JobTrackedVersions { 1517 t.Fatalf("got %d; want %d", len(allVersions), structs.JobTrackedVersions) 1518 } 1519 1520 if a := allVersions[0]; a.ID != job.ID || a.Version != 299 || a.Name != "299" { 1521 t.Fatalf("bad: %+v", a) 1522 } 1523 if a := allVersions[1]; a.ID != job.ID || a.Version != 298 || a.Name != "298" { 1524 t.Fatalf("bad: %+v", a) 1525 } 1526 1527 // Ensure we didn't delete the stable job 1528 if a := allVersions[structs.JobTrackedVersions-1]; a.ID != job.ID || 1529 a.Version != 0 || a.Name != "0" || !a.Stable { 1530 t.Fatalf("bad: %+v", a) 1531 } 1532 1533 if watchFired(ws) { 1534 t.Fatalf("bad") 1535 } 1536 } 1537 1538 func TestStateStore_DeleteJob_Job(t *testing.T) { 1539 state := testStateStore(t) 1540 job := mock.Job() 1541 1542 err := state.UpsertJob(1000, job) 1543 if err != nil { 1544 t.Fatalf("err: %v", err) 1545 } 1546 1547 // Create a watchset so we can test that delete fires the watch 1548 ws := memdb.NewWatchSet() 1549 if _, err := state.JobByID(ws, job.Namespace, job.ID); err != nil { 1550 t.Fatalf("bad: %v", err) 1551 } 1552 1553 err = state.DeleteJob(1001, job.Namespace, job.ID) 1554 if err != nil { 1555 t.Fatalf("err: %v", err) 1556 } 1557 1558 if !watchFired(ws) { 1559 t.Fatalf("bad") 1560 } 1561 1562 ws = memdb.NewWatchSet() 1563 out, err := state.JobByID(ws, job.Namespace, job.ID) 1564 if err != nil { 1565 t.Fatalf("err: %v", err) 1566 } 1567 1568 if out != nil { 1569 t.Fatalf("bad: %#v %#v", job, out) 1570 } 1571 1572 index, err := state.Index("jobs") 1573 if err != nil { 1574 t.Fatalf("err: %v", err) 1575 } 1576 if index != 1001 { 1577 t.Fatalf("bad: %d", index) 1578 } 1579 1580 summary, err := state.JobSummaryByID(ws, job.Namespace, job.ID) 1581 if err != nil { 1582 t.Fatalf("err: %v", err) 1583 } 1584 if summary != nil { 1585 t.Fatalf("expected summary to be nil, but got: %v", summary) 1586 } 1587 1588 index, err = state.Index("job_summary") 1589 if err != nil { 1590 t.Fatalf("err: %v", err) 1591 } 1592 if index != 1001 { 1593 t.Fatalf("bad: %d", index) 1594 } 1595 1596 versions, err := state.JobVersionsByID(ws, job.Namespace, job.ID) 1597 if err != nil { 1598 t.Fatalf("err: %v", err) 1599 } 1600 if len(versions) != 0 { 1601 t.Fatalf("expected no job versions") 1602 } 1603 1604 index, err = state.Index("job_summary") 1605 if err != nil { 1606 t.Fatalf("err: %v", err) 1607 } 1608 if index != 1001 { 1609 t.Fatalf("bad: %d", index) 1610 } 1611 1612 if watchFired(ws) { 1613 t.Fatalf("bad") 1614 } 1615 } 1616 1617 func TestStateStore_DeleteJobTxn_BatchDeletes(t *testing.T) { 1618 state := testStateStore(t) 1619 1620 const testJobCount = 10 1621 const jobVersionCount = 4 1622 1623 stateIndex := uint64(1000) 1624 1625 jobs := make([]*structs.Job, testJobCount) 1626 for i := 0; i < testJobCount; i++ { 1627 stateIndex++ 1628 job := mock.BatchJob() 1629 1630 err := state.UpsertJob(stateIndex, job) 1631 require.NoError(t, err) 1632 1633 jobs[i] = job 1634 1635 // Create some versions 1636 for vi := 1; vi < jobVersionCount; vi++ { 1637 stateIndex++ 1638 1639 job := job.Copy() 1640 job.TaskGroups[0].Tasks[0].Env = map[string]string{ 1641 "Version": fmt.Sprintf("%d", vi), 1642 } 1643 1644 require.NoError(t, state.UpsertJob(stateIndex, job)) 1645 } 1646 } 1647 1648 ws := memdb.NewWatchSet() 1649 1650 // Sanity check that jobs are present in DB 1651 job, err := state.JobByID(ws, jobs[0].Namespace, jobs[0].ID) 1652 require.NoError(t, err) 1653 require.Equal(t, jobs[0].ID, job.ID) 1654 1655 jobVersions, err := state.JobVersionsByID(ws, jobs[0].Namespace, jobs[0].ID) 1656 require.NoError(t, err) 1657 require.Equal(t, jobVersionCount, len(jobVersions)) 1658 1659 // Actually delete 1660 const deletionIndex = uint64(10001) 1661 err = state.WithWriteTransaction(func(txn Txn) error { 1662 for i, job := range jobs { 1663 err := state.DeleteJobTxn(deletionIndex, job.Namespace, job.ID, txn) 1664 require.NoError(t, err, "failed at %d %e", i, err) 1665 } 1666 return nil 1667 }) 1668 assert.NoError(t, err) 1669 1670 assert.True(t, watchFired(ws)) 1671 1672 ws = memdb.NewWatchSet() 1673 out, err := state.JobByID(ws, jobs[0].Namespace, jobs[0].ID) 1674 require.NoError(t, err) 1675 require.Nil(t, out) 1676 1677 jobVersions, err = state.JobVersionsByID(ws, jobs[0].Namespace, jobs[0].ID) 1678 require.NoError(t, err) 1679 require.Empty(t, jobVersions) 1680 1681 index, err := state.Index("jobs") 1682 require.NoError(t, err) 1683 require.Equal(t, deletionIndex, index) 1684 } 1685 1686 func TestStateStore_DeleteJob_MultipleVersions(t *testing.T) { 1687 state := testStateStore(t) 1688 assert := assert.New(t) 1689 1690 // Create a job and mark it as stable 1691 job := mock.Job() 1692 job.Stable = true 1693 job.Priority = 0 1694 1695 // Create a watchset so we can test that upsert fires the watch 1696 ws := memdb.NewWatchSet() 1697 _, err := state.JobVersionsByID(ws, job.Namespace, job.ID) 1698 assert.Nil(err) 1699 assert.Nil(state.UpsertJob(1000, job)) 1700 assert.True(watchFired(ws)) 1701 1702 var finalJob *structs.Job 1703 for i := 1; i < 20; i++ { 1704 finalJob = mock.Job() 1705 finalJob.ID = job.ID 1706 finalJob.Priority = i 1707 assert.Nil(state.UpsertJob(uint64(1000+i), finalJob)) 1708 } 1709 1710 assert.Nil(state.DeleteJob(1020, job.Namespace, job.ID)) 1711 assert.True(watchFired(ws)) 1712 1713 ws = memdb.NewWatchSet() 1714 out, err := state.JobByID(ws, job.Namespace, job.ID) 1715 assert.Nil(err) 1716 assert.Nil(out) 1717 1718 index, err := state.Index("jobs") 1719 assert.Nil(err) 1720 assert.EqualValues(1020, index) 1721 1722 summary, err := state.JobSummaryByID(ws, job.Namespace, job.ID) 1723 assert.Nil(err) 1724 assert.Nil(summary) 1725 1726 index, err = state.Index("job_version") 1727 assert.Nil(err) 1728 assert.EqualValues(1020, index) 1729 1730 versions, err := state.JobVersionsByID(ws, job.Namespace, job.ID) 1731 assert.Nil(err) 1732 assert.Len(versions, 0) 1733 1734 index, err = state.Index("job_summary") 1735 assert.Nil(err) 1736 assert.EqualValues(1020, index) 1737 1738 assert.False(watchFired(ws)) 1739 } 1740 1741 func TestStateStore_DeleteJob_ChildJob(t *testing.T) { 1742 state := testStateStore(t) 1743 1744 parent := mock.Job() 1745 if err := state.UpsertJob(998, parent); err != nil { 1746 t.Fatalf("err: %v", err) 1747 } 1748 1749 child := mock.Job() 1750 child.ParentID = parent.ID 1751 1752 if err := state.UpsertJob(999, child); err != nil { 1753 t.Fatalf("err: %v", err) 1754 } 1755 1756 // Create a watchset so we can test that delete fires the watch 1757 ws := memdb.NewWatchSet() 1758 if _, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID); err != nil { 1759 t.Fatalf("bad: %v", err) 1760 } 1761 1762 err := state.DeleteJob(1001, child.Namespace, child.ID) 1763 if err != nil { 1764 t.Fatalf("err: %v", err) 1765 } 1766 if !watchFired(ws) { 1767 t.Fatalf("bad") 1768 } 1769 1770 ws = memdb.NewWatchSet() 1771 summary, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID) 1772 if err != nil { 1773 t.Fatalf("err: %v", err) 1774 } 1775 if summary == nil { 1776 t.Fatalf("nil summary") 1777 } 1778 if summary.JobID != parent.ID { 1779 t.Fatalf("bad summary id: %v", parent.ID) 1780 } 1781 if summary.Children == nil { 1782 t.Fatalf("nil children summary") 1783 } 1784 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 1785 t.Fatalf("bad children summary: %v", summary.Children) 1786 } 1787 if watchFired(ws) { 1788 t.Fatalf("bad") 1789 } 1790 } 1791 1792 func TestStateStore_Jobs(t *testing.T) { 1793 state := testStateStore(t) 1794 var jobs []*structs.Job 1795 1796 for i := 0; i < 10; i++ { 1797 job := mock.Job() 1798 jobs = append(jobs, job) 1799 1800 err := state.UpsertJob(1000+uint64(i), job) 1801 if err != nil { 1802 t.Fatalf("err: %v", err) 1803 } 1804 } 1805 1806 ws := memdb.NewWatchSet() 1807 iter, err := state.Jobs(ws) 1808 if err != nil { 1809 t.Fatalf("err: %v", err) 1810 } 1811 1812 var out []*structs.Job 1813 for { 1814 raw := iter.Next() 1815 if raw == nil { 1816 break 1817 } 1818 out = append(out, raw.(*structs.Job)) 1819 } 1820 1821 sort.Sort(JobIDSort(jobs)) 1822 sort.Sort(JobIDSort(out)) 1823 1824 if !reflect.DeepEqual(jobs, out) { 1825 t.Fatalf("bad: %#v %#v", jobs, out) 1826 } 1827 if watchFired(ws) { 1828 t.Fatalf("bad") 1829 } 1830 } 1831 1832 func TestStateStore_JobVersions(t *testing.T) { 1833 state := testStateStore(t) 1834 var jobs []*structs.Job 1835 1836 for i := 0; i < 10; i++ { 1837 job := mock.Job() 1838 jobs = append(jobs, job) 1839 1840 err := state.UpsertJob(1000+uint64(i), job) 1841 if err != nil { 1842 t.Fatalf("err: %v", err) 1843 } 1844 } 1845 1846 ws := memdb.NewWatchSet() 1847 iter, err := state.JobVersions(ws) 1848 if err != nil { 1849 t.Fatalf("err: %v", err) 1850 } 1851 1852 var out []*structs.Job 1853 for { 1854 raw := iter.Next() 1855 if raw == nil { 1856 break 1857 } 1858 out = append(out, raw.(*structs.Job)) 1859 } 1860 1861 sort.Sort(JobIDSort(jobs)) 1862 sort.Sort(JobIDSort(out)) 1863 1864 if !reflect.DeepEqual(jobs, out) { 1865 t.Fatalf("bad: %#v %#v", jobs, out) 1866 } 1867 if watchFired(ws) { 1868 t.Fatalf("bad") 1869 } 1870 } 1871 1872 func TestStateStore_JobsByIDPrefix(t *testing.T) { 1873 state := testStateStore(t) 1874 job := mock.Job() 1875 1876 job.ID = "redis" 1877 err := state.UpsertJob(1000, job) 1878 if err != nil { 1879 t.Fatalf("err: %v", err) 1880 } 1881 1882 ws := memdb.NewWatchSet() 1883 iter, err := state.JobsByIDPrefix(ws, job.Namespace, job.ID) 1884 if err != nil { 1885 t.Fatalf("err: %v", err) 1886 } 1887 1888 gatherJobs := func(iter memdb.ResultIterator) []*structs.Job { 1889 var jobs []*structs.Job 1890 for { 1891 raw := iter.Next() 1892 if raw == nil { 1893 break 1894 } 1895 jobs = append(jobs, raw.(*structs.Job)) 1896 } 1897 return jobs 1898 } 1899 1900 jobs := gatherJobs(iter) 1901 if len(jobs) != 1 { 1902 t.Fatalf("err: %v", err) 1903 } 1904 1905 iter, err = state.JobsByIDPrefix(ws, job.Namespace, "re") 1906 if err != nil { 1907 t.Fatalf("err: %v", err) 1908 } 1909 1910 jobs = gatherJobs(iter) 1911 if len(jobs) != 1 { 1912 t.Fatalf("err: %v", err) 1913 } 1914 if watchFired(ws) { 1915 t.Fatalf("bad") 1916 } 1917 1918 job = mock.Job() 1919 job.ID = "riak" 1920 err = state.UpsertJob(1001, job) 1921 if err != nil { 1922 t.Fatalf("err: %v", err) 1923 } 1924 1925 if !watchFired(ws) { 1926 t.Fatalf("bad") 1927 } 1928 1929 ws = memdb.NewWatchSet() 1930 iter, err = state.JobsByIDPrefix(ws, job.Namespace, "r") 1931 if err != nil { 1932 t.Fatalf("err: %v", err) 1933 } 1934 1935 jobs = gatherJobs(iter) 1936 if len(jobs) != 2 { 1937 t.Fatalf("err: %v", err) 1938 } 1939 1940 iter, err = state.JobsByIDPrefix(ws, job.Namespace, "ri") 1941 if err != nil { 1942 t.Fatalf("err: %v", err) 1943 } 1944 1945 jobs = gatherJobs(iter) 1946 if len(jobs) != 1 { 1947 t.Fatalf("err: %v", err) 1948 } 1949 if watchFired(ws) { 1950 t.Fatalf("bad") 1951 } 1952 } 1953 1954 func TestStateStore_JobsByPeriodic(t *testing.T) { 1955 state := testStateStore(t) 1956 var periodic, nonPeriodic []*structs.Job 1957 1958 for i := 0; i < 10; i++ { 1959 job := mock.Job() 1960 nonPeriodic = append(nonPeriodic, job) 1961 1962 err := state.UpsertJob(1000+uint64(i), job) 1963 if err != nil { 1964 t.Fatalf("err: %v", err) 1965 } 1966 } 1967 1968 for i := 0; i < 10; i++ { 1969 job := mock.PeriodicJob() 1970 periodic = append(periodic, job) 1971 1972 err := state.UpsertJob(2000+uint64(i), job) 1973 if err != nil { 1974 t.Fatalf("err: %v", err) 1975 } 1976 } 1977 1978 ws := memdb.NewWatchSet() 1979 iter, err := state.JobsByPeriodic(ws, true) 1980 if err != nil { 1981 t.Fatalf("err: %v", err) 1982 } 1983 1984 var outPeriodic []*structs.Job 1985 for { 1986 raw := iter.Next() 1987 if raw == nil { 1988 break 1989 } 1990 outPeriodic = append(outPeriodic, raw.(*structs.Job)) 1991 } 1992 1993 iter, err = state.JobsByPeriodic(ws, false) 1994 if err != nil { 1995 t.Fatalf("err: %v", err) 1996 } 1997 1998 var outNonPeriodic []*structs.Job 1999 for { 2000 raw := iter.Next() 2001 if raw == nil { 2002 break 2003 } 2004 outNonPeriodic = append(outNonPeriodic, raw.(*structs.Job)) 2005 } 2006 2007 sort.Sort(JobIDSort(periodic)) 2008 sort.Sort(JobIDSort(nonPeriodic)) 2009 sort.Sort(JobIDSort(outPeriodic)) 2010 sort.Sort(JobIDSort(outNonPeriodic)) 2011 2012 if !reflect.DeepEqual(periodic, outPeriodic) { 2013 t.Fatalf("bad: %#v %#v", periodic, outPeriodic) 2014 } 2015 2016 if !reflect.DeepEqual(nonPeriodic, outNonPeriodic) { 2017 t.Fatalf("bad: %#v %#v", nonPeriodic, outNonPeriodic) 2018 } 2019 if watchFired(ws) { 2020 t.Fatalf("bad") 2021 } 2022 } 2023 2024 func TestStateStore_JobsByScheduler(t *testing.T) { 2025 state := testStateStore(t) 2026 var serviceJobs []*structs.Job 2027 var sysJobs []*structs.Job 2028 2029 for i := 0; i < 10; i++ { 2030 job := mock.Job() 2031 serviceJobs = append(serviceJobs, job) 2032 2033 err := state.UpsertJob(1000+uint64(i), job) 2034 if err != nil { 2035 t.Fatalf("err: %v", err) 2036 } 2037 } 2038 2039 for i := 0; i < 10; i++ { 2040 job := mock.SystemJob() 2041 job.Status = structs.JobStatusRunning 2042 sysJobs = append(sysJobs, job) 2043 2044 err := state.UpsertJob(2000+uint64(i), job) 2045 if err != nil { 2046 t.Fatalf("err: %v", err) 2047 } 2048 } 2049 2050 ws := memdb.NewWatchSet() 2051 iter, err := state.JobsByScheduler(ws, "service") 2052 if err != nil { 2053 t.Fatalf("err: %v", err) 2054 } 2055 2056 var outService []*structs.Job 2057 for { 2058 raw := iter.Next() 2059 if raw == nil { 2060 break 2061 } 2062 outService = append(outService, raw.(*structs.Job)) 2063 } 2064 2065 iter, err = state.JobsByScheduler(ws, "system") 2066 if err != nil { 2067 t.Fatalf("err: %v", err) 2068 } 2069 2070 var outSystem []*structs.Job 2071 for { 2072 raw := iter.Next() 2073 if raw == nil { 2074 break 2075 } 2076 outSystem = append(outSystem, raw.(*structs.Job)) 2077 } 2078 2079 sort.Sort(JobIDSort(serviceJobs)) 2080 sort.Sort(JobIDSort(sysJobs)) 2081 sort.Sort(JobIDSort(outService)) 2082 sort.Sort(JobIDSort(outSystem)) 2083 2084 if !reflect.DeepEqual(serviceJobs, outService) { 2085 t.Fatalf("bad: %#v %#v", serviceJobs, outService) 2086 } 2087 2088 if !reflect.DeepEqual(sysJobs, outSystem) { 2089 t.Fatalf("bad: %#v %#v", sysJobs, outSystem) 2090 } 2091 if watchFired(ws) { 2092 t.Fatalf("bad") 2093 } 2094 } 2095 2096 func TestStateStore_JobsByGC(t *testing.T) { 2097 state := testStateStore(t) 2098 gc, nonGc := make(map[string]struct{}), make(map[string]struct{}) 2099 2100 for i := 0; i < 20; i++ { 2101 var job *structs.Job 2102 if i%2 == 0 { 2103 job = mock.Job() 2104 } else { 2105 job = mock.PeriodicJob() 2106 } 2107 nonGc[job.ID] = struct{}{} 2108 2109 if err := state.UpsertJob(1000+uint64(i), job); err != nil { 2110 t.Fatalf("err: %v", err) 2111 } 2112 } 2113 2114 for i := 0; i < 20; i += 2 { 2115 job := mock.Job() 2116 job.Type = structs.JobTypeBatch 2117 gc[job.ID] = struct{}{} 2118 2119 if err := state.UpsertJob(2000+uint64(i), job); err != nil { 2120 t.Fatalf("err: %v", err) 2121 } 2122 2123 // Create an eval for it 2124 eval := mock.Eval() 2125 eval.JobID = job.ID 2126 eval.Status = structs.EvalStatusComplete 2127 if err := state.UpsertEvals(2000+uint64(i+1), []*structs.Evaluation{eval}); err != nil { 2128 t.Fatalf("err: %v", err) 2129 } 2130 2131 } 2132 2133 ws := memdb.NewWatchSet() 2134 iter, err := state.JobsByGC(ws, true) 2135 if err != nil { 2136 t.Fatalf("err: %v", err) 2137 } 2138 2139 outGc := make(map[string]struct{}) 2140 for i := iter.Next(); i != nil; i = iter.Next() { 2141 j := i.(*structs.Job) 2142 outGc[j.ID] = struct{}{} 2143 } 2144 2145 iter, err = state.JobsByGC(ws, false) 2146 if err != nil { 2147 t.Fatalf("err: %v", err) 2148 } 2149 2150 outNonGc := make(map[string]struct{}) 2151 for i := iter.Next(); i != nil; i = iter.Next() { 2152 j := i.(*structs.Job) 2153 outNonGc[j.ID] = struct{}{} 2154 } 2155 2156 if !reflect.DeepEqual(gc, outGc) { 2157 t.Fatalf("bad: %#v %#v", gc, outGc) 2158 } 2159 2160 if !reflect.DeepEqual(nonGc, outNonGc) { 2161 t.Fatalf("bad: %#v %#v", nonGc, outNonGc) 2162 } 2163 if watchFired(ws) { 2164 t.Fatalf("bad") 2165 } 2166 } 2167 2168 func TestStateStore_RestoreJob(t *testing.T) { 2169 state := testStateStore(t) 2170 job := mock.Job() 2171 2172 restore, err := state.Restore() 2173 if err != nil { 2174 t.Fatalf("err: %v", err) 2175 } 2176 2177 err = restore.JobRestore(job) 2178 if err != nil { 2179 t.Fatalf("err: %v", err) 2180 } 2181 restore.Commit() 2182 2183 ws := memdb.NewWatchSet() 2184 out, err := state.JobByID(ws, job.Namespace, job.ID) 2185 if err != nil { 2186 t.Fatalf("err: %v", err) 2187 } 2188 2189 if !reflect.DeepEqual(out, job) { 2190 t.Fatalf("Bad: %#v %#v", out, job) 2191 } 2192 } 2193 2194 // This test ensures that the state restore creates the EphemeralDisk for a job if 2195 // it doesn't have one 2196 // COMPAT 0.4.1 -> 0.5 2197 func TestStateStore_Jobs_NoEphemeralDisk(t *testing.T) { 2198 state := testStateStore(t) 2199 job := mock.Job() 2200 2201 // Set EphemeralDisk to nil and set the DiskMB to 150 2202 job.TaskGroups[0].EphemeralDisk = nil 2203 job.TaskGroups[0].Tasks[0].Resources.DiskMB = 150 2204 2205 restore, err := state.Restore() 2206 if err != nil { 2207 t.Fatalf("err: %v", err) 2208 } 2209 2210 err = restore.JobRestore(job) 2211 if err != nil { 2212 t.Fatalf("err: %v", err) 2213 } 2214 restore.Commit() 2215 2216 ws := memdb.NewWatchSet() 2217 out, err := state.JobByID(ws, job.Namespace, job.ID) 2218 if err != nil { 2219 t.Fatalf("err: %v", err) 2220 } 2221 2222 // Expect job to have local disk and clear out the task's disk resource ask 2223 expected := job.Copy() 2224 expected.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{ 2225 SizeMB: 150, 2226 } 2227 expected.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 2228 if !reflect.DeepEqual(out, expected) { 2229 t.Fatalf("Bad: %#v %#v", out, job) 2230 } 2231 } 2232 2233 func TestStateStore_UpsertPeriodicLaunch(t *testing.T) { 2234 state := testStateStore(t) 2235 job := mock.Job() 2236 launch := &structs.PeriodicLaunch{ 2237 ID: job.ID, 2238 Namespace: job.Namespace, 2239 Launch: time.Now(), 2240 } 2241 2242 // Create a watchset so we can test that upsert fires the watch 2243 ws := memdb.NewWatchSet() 2244 if _, err := state.PeriodicLaunchByID(ws, job.Namespace, launch.ID); err != nil { 2245 t.Fatalf("bad: %v", err) 2246 } 2247 2248 err := state.UpsertPeriodicLaunch(1000, launch) 2249 if err != nil { 2250 t.Fatalf("err: %v", err) 2251 } 2252 2253 if !watchFired(ws) { 2254 t.Fatalf("bad") 2255 } 2256 2257 ws = memdb.NewWatchSet() 2258 out, err := state.PeriodicLaunchByID(ws, job.Namespace, job.ID) 2259 if err != nil { 2260 t.Fatalf("err: %v", err) 2261 } 2262 if out.CreateIndex != 1000 { 2263 t.Fatalf("bad: %#v", out) 2264 } 2265 if out.ModifyIndex != 1000 { 2266 t.Fatalf("bad: %#v", out) 2267 } 2268 2269 if !reflect.DeepEqual(launch, out) { 2270 t.Fatalf("bad: %#v %#v", job, out) 2271 } 2272 2273 index, err := state.Index("periodic_launch") 2274 if err != nil { 2275 t.Fatalf("err: %v", err) 2276 } 2277 if index != 1000 { 2278 t.Fatalf("bad: %d", index) 2279 } 2280 2281 if watchFired(ws) { 2282 t.Fatalf("bad") 2283 } 2284 } 2285 2286 func TestStateStore_UpdateUpsertPeriodicLaunch(t *testing.T) { 2287 state := testStateStore(t) 2288 job := mock.Job() 2289 launch := &structs.PeriodicLaunch{ 2290 ID: job.ID, 2291 Namespace: job.Namespace, 2292 Launch: time.Now(), 2293 } 2294 2295 err := state.UpsertPeriodicLaunch(1000, launch) 2296 if err != nil { 2297 t.Fatalf("err: %v", err) 2298 } 2299 2300 // Create a watchset so we can test that upsert fires the watch 2301 ws := memdb.NewWatchSet() 2302 if _, err := state.PeriodicLaunchByID(ws, job.Namespace, launch.ID); err != nil { 2303 t.Fatalf("bad: %v", err) 2304 } 2305 2306 launch2 := &structs.PeriodicLaunch{ 2307 ID: job.ID, 2308 Namespace: job.Namespace, 2309 Launch: launch.Launch.Add(1 * time.Second), 2310 } 2311 err = state.UpsertPeriodicLaunch(1001, launch2) 2312 if err != nil { 2313 t.Fatalf("err: %v", err) 2314 } 2315 2316 if !watchFired(ws) { 2317 t.Fatalf("bad") 2318 } 2319 2320 ws = memdb.NewWatchSet() 2321 out, err := state.PeriodicLaunchByID(ws, job.Namespace, job.ID) 2322 if err != nil { 2323 t.Fatalf("err: %v", err) 2324 } 2325 if out.CreateIndex != 1000 { 2326 t.Fatalf("bad: %#v", out) 2327 } 2328 if out.ModifyIndex != 1001 { 2329 t.Fatalf("bad: %#v", out) 2330 } 2331 2332 if !reflect.DeepEqual(launch2, out) { 2333 t.Fatalf("bad: %#v %#v", launch2, out) 2334 } 2335 2336 index, err := state.Index("periodic_launch") 2337 if err != nil { 2338 t.Fatalf("err: %v", err) 2339 } 2340 if index != 1001 { 2341 t.Fatalf("bad: %d", index) 2342 } 2343 2344 if watchFired(ws) { 2345 t.Fatalf("bad") 2346 } 2347 } 2348 2349 func TestStateStore_DeletePeriodicLaunch(t *testing.T) { 2350 state := testStateStore(t) 2351 job := mock.Job() 2352 launch := &structs.PeriodicLaunch{ 2353 ID: job.ID, 2354 Namespace: job.Namespace, 2355 Launch: time.Now(), 2356 } 2357 2358 err := state.UpsertPeriodicLaunch(1000, launch) 2359 if err != nil { 2360 t.Fatalf("err: %v", err) 2361 } 2362 2363 // Create a watchset so we can test that delete fires the watch 2364 ws := memdb.NewWatchSet() 2365 if _, err := state.PeriodicLaunchByID(ws, job.Namespace, launch.ID); err != nil { 2366 t.Fatalf("bad: %v", err) 2367 } 2368 2369 err = state.DeletePeriodicLaunch(1001, launch.Namespace, launch.ID) 2370 if err != nil { 2371 t.Fatalf("err: %v", err) 2372 } 2373 2374 if !watchFired(ws) { 2375 t.Fatalf("bad") 2376 } 2377 2378 ws = memdb.NewWatchSet() 2379 out, err := state.PeriodicLaunchByID(ws, job.Namespace, job.ID) 2380 if err != nil { 2381 t.Fatalf("err: %v", err) 2382 } 2383 2384 if out != nil { 2385 t.Fatalf("bad: %#v %#v", job, out) 2386 } 2387 2388 index, err := state.Index("periodic_launch") 2389 if err != nil { 2390 t.Fatalf("err: %v", err) 2391 } 2392 if index != 1001 { 2393 t.Fatalf("bad: %d", index) 2394 } 2395 2396 if watchFired(ws) { 2397 t.Fatalf("bad") 2398 } 2399 } 2400 2401 func TestStateStore_PeriodicLaunches(t *testing.T) { 2402 state := testStateStore(t) 2403 var launches []*structs.PeriodicLaunch 2404 2405 for i := 0; i < 10; i++ { 2406 job := mock.Job() 2407 launch := &structs.PeriodicLaunch{ 2408 ID: job.ID, 2409 Namespace: job.Namespace, 2410 Launch: time.Now(), 2411 } 2412 launches = append(launches, launch) 2413 2414 err := state.UpsertPeriodicLaunch(1000+uint64(i), launch) 2415 if err != nil { 2416 t.Fatalf("err: %v", err) 2417 } 2418 } 2419 2420 ws := memdb.NewWatchSet() 2421 iter, err := state.PeriodicLaunches(ws) 2422 if err != nil { 2423 t.Fatalf("err: %v", err) 2424 } 2425 2426 out := make(map[string]*structs.PeriodicLaunch, 10) 2427 for { 2428 raw := iter.Next() 2429 if raw == nil { 2430 break 2431 } 2432 launch := raw.(*structs.PeriodicLaunch) 2433 if _, ok := out[launch.ID]; ok { 2434 t.Fatalf("duplicate: %v", launch.ID) 2435 } 2436 2437 out[launch.ID] = launch 2438 } 2439 2440 for _, launch := range launches { 2441 l, ok := out[launch.ID] 2442 if !ok { 2443 t.Fatalf("bad %v", launch.ID) 2444 } 2445 2446 if !reflect.DeepEqual(launch, l) { 2447 t.Fatalf("bad: %#v %#v", launch, l) 2448 } 2449 2450 delete(out, launch.ID) 2451 } 2452 2453 if len(out) != 0 { 2454 t.Fatalf("leftover: %#v", out) 2455 } 2456 2457 if watchFired(ws) { 2458 t.Fatalf("bad") 2459 } 2460 } 2461 2462 func TestStateStore_RestorePeriodicLaunch(t *testing.T) { 2463 state := testStateStore(t) 2464 job := mock.Job() 2465 launch := &structs.PeriodicLaunch{ 2466 ID: job.ID, 2467 Namespace: job.Namespace, 2468 Launch: time.Now(), 2469 } 2470 2471 restore, err := state.Restore() 2472 if err != nil { 2473 t.Fatalf("err: %v", err) 2474 } 2475 2476 err = restore.PeriodicLaunchRestore(launch) 2477 if err != nil { 2478 t.Fatalf("err: %v", err) 2479 } 2480 restore.Commit() 2481 2482 ws := memdb.NewWatchSet() 2483 out, err := state.PeriodicLaunchByID(ws, job.Namespace, job.ID) 2484 if err != nil { 2485 t.Fatalf("err: %v", err) 2486 } 2487 2488 if !reflect.DeepEqual(out, launch) { 2489 t.Fatalf("Bad: %#v %#v", out, job) 2490 } 2491 2492 if watchFired(ws) { 2493 t.Fatalf("bad") 2494 } 2495 } 2496 2497 func TestStateStore_RestoreJobVersion(t *testing.T) { 2498 state := testStateStore(t) 2499 job := mock.Job() 2500 2501 restore, err := state.Restore() 2502 if err != nil { 2503 t.Fatalf("err: %v", err) 2504 } 2505 2506 err = restore.JobVersionRestore(job) 2507 if err != nil { 2508 t.Fatalf("err: %v", err) 2509 } 2510 restore.Commit() 2511 2512 ws := memdb.NewWatchSet() 2513 out, err := state.JobByIDAndVersion(ws, job.Namespace, job.ID, job.Version) 2514 if err != nil { 2515 t.Fatalf("err: %v", err) 2516 } 2517 2518 if !reflect.DeepEqual(out, job) { 2519 t.Fatalf("Bad: %#v %#v", out, job) 2520 } 2521 2522 if watchFired(ws) { 2523 t.Fatalf("bad") 2524 } 2525 } 2526 2527 func TestStateStore_RestoreDeployment(t *testing.T) { 2528 state := testStateStore(t) 2529 d := mock.Deployment() 2530 2531 restore, err := state.Restore() 2532 if err != nil { 2533 t.Fatalf("err: %v", err) 2534 } 2535 2536 err = restore.DeploymentRestore(d) 2537 if err != nil { 2538 t.Fatalf("err: %v", err) 2539 } 2540 restore.Commit() 2541 2542 ws := memdb.NewWatchSet() 2543 out, err := state.DeploymentByID(ws, d.ID) 2544 if err != nil { 2545 t.Fatalf("err: %v", err) 2546 } 2547 2548 if !reflect.DeepEqual(out, d) { 2549 t.Fatalf("Bad: %#v %#v", out, d) 2550 } 2551 2552 if watchFired(ws) { 2553 t.Fatalf("bad") 2554 } 2555 } 2556 2557 func TestStateStore_RestoreJobSummary(t *testing.T) { 2558 state := testStateStore(t) 2559 job := mock.Job() 2560 jobSummary := &structs.JobSummary{ 2561 JobID: job.ID, 2562 Namespace: job.Namespace, 2563 Summary: map[string]structs.TaskGroupSummary{ 2564 "web": { 2565 Starting: 10, 2566 }, 2567 }, 2568 } 2569 restore, err := state.Restore() 2570 if err != nil { 2571 t.Fatalf("err: %v", err) 2572 } 2573 2574 err = restore.JobSummaryRestore(jobSummary) 2575 if err != nil { 2576 t.Fatalf("err: %v", err) 2577 } 2578 restore.Commit() 2579 2580 ws := memdb.NewWatchSet() 2581 out, err := state.JobSummaryByID(ws, job.Namespace, job.ID) 2582 if err != nil { 2583 t.Fatalf("err: %v", err) 2584 } 2585 2586 if !reflect.DeepEqual(out, jobSummary) { 2587 t.Fatalf("Bad: %#v %#v", out, jobSummary) 2588 } 2589 } 2590 2591 func TestStateStore_Indexes(t *testing.T) { 2592 state := testStateStore(t) 2593 node := mock.Node() 2594 2595 err := state.UpsertNode(1000, node) 2596 if err != nil { 2597 t.Fatalf("err: %v", err) 2598 } 2599 2600 iter, err := state.Indexes() 2601 if err != nil { 2602 t.Fatalf("err: %v", err) 2603 } 2604 2605 var out []*IndexEntry 2606 for { 2607 raw := iter.Next() 2608 if raw == nil { 2609 break 2610 } 2611 out = append(out, raw.(*IndexEntry)) 2612 } 2613 2614 expect := &IndexEntry{"nodes", 1000} 2615 if l := len(out); l != 1 && l != 2 { 2616 t.Fatalf("unexpected number of index entries: %v", out) 2617 } 2618 2619 for _, index := range out { 2620 if index.Key != expect.Key { 2621 continue 2622 } 2623 if index.Value != expect.Value { 2624 t.Fatalf("bad index; got %d; want %d", index.Value, expect.Value) 2625 } 2626 2627 // We matched 2628 return 2629 } 2630 2631 t.Fatal("did not find expected index entry") 2632 } 2633 2634 func TestStateStore_LatestIndex(t *testing.T) { 2635 state := testStateStore(t) 2636 2637 if err := state.UpsertNode(1000, mock.Node()); err != nil { 2638 t.Fatalf("err: %v", err) 2639 } 2640 2641 exp := uint64(2000) 2642 if err := state.UpsertJob(exp, mock.Job()); err != nil { 2643 t.Fatalf("err: %v", err) 2644 } 2645 2646 latest, err := state.LatestIndex() 2647 if err != nil { 2648 t.Fatalf("err: %v", err) 2649 } 2650 2651 if latest != exp { 2652 t.Fatalf("LatestIndex() returned %d; want %d", latest, exp) 2653 } 2654 } 2655 2656 func TestStateStore_RestoreIndex(t *testing.T) { 2657 state := testStateStore(t) 2658 2659 restore, err := state.Restore() 2660 if err != nil { 2661 t.Fatalf("err: %v", err) 2662 } 2663 2664 index := &IndexEntry{"jobs", 1000} 2665 err = restore.IndexRestore(index) 2666 if err != nil { 2667 t.Fatalf("err: %v", err) 2668 } 2669 2670 restore.Commit() 2671 2672 out, err := state.Index("jobs") 2673 if err != nil { 2674 t.Fatalf("err: %v", err) 2675 } 2676 2677 if out != 1000 { 2678 t.Fatalf("Bad: %#v %#v", out, 1000) 2679 } 2680 } 2681 2682 func TestStateStore_UpsertEvals_Eval(t *testing.T) { 2683 state := testStateStore(t) 2684 eval := mock.Eval() 2685 2686 // Create a watchset so we can test that upsert fires the watch 2687 ws := memdb.NewWatchSet() 2688 if _, err := state.EvalByID(ws, eval.ID); err != nil { 2689 t.Fatalf("bad: %v", err) 2690 } 2691 2692 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 2693 if err != nil { 2694 t.Fatalf("err: %v", err) 2695 } 2696 2697 if !watchFired(ws) { 2698 t.Fatalf("bad") 2699 } 2700 2701 ws = memdb.NewWatchSet() 2702 out, err := state.EvalByID(ws, eval.ID) 2703 if err != nil { 2704 t.Fatalf("err: %v", err) 2705 } 2706 2707 if !reflect.DeepEqual(eval, out) { 2708 t.Fatalf("bad: %#v %#v", eval, out) 2709 } 2710 2711 index, err := state.Index("evals") 2712 if err != nil { 2713 t.Fatalf("err: %v", err) 2714 } 2715 if index != 1000 { 2716 t.Fatalf("bad: %d", index) 2717 } 2718 2719 if watchFired(ws) { 2720 t.Fatalf("bad") 2721 } 2722 } 2723 2724 func TestStateStore_UpsertEvals_CancelBlocked(t *testing.T) { 2725 state := testStateStore(t) 2726 2727 // Create two blocked evals for the same job 2728 j := "test-job" 2729 b1, b2 := mock.Eval(), mock.Eval() 2730 b1.JobID = j 2731 b1.Status = structs.EvalStatusBlocked 2732 b2.JobID = j 2733 b2.Status = structs.EvalStatusBlocked 2734 2735 err := state.UpsertEvals(999, []*structs.Evaluation{b1, b2}) 2736 if err != nil { 2737 t.Fatalf("err: %v", err) 2738 } 2739 2740 // Create one complete and successful eval for the job 2741 eval := mock.Eval() 2742 eval.JobID = j 2743 eval.Status = structs.EvalStatusComplete 2744 2745 // Create a watchset so we can test that the upsert of the complete eval 2746 // fires the watch 2747 ws := memdb.NewWatchSet() 2748 if _, err := state.EvalByID(ws, b1.ID); err != nil { 2749 t.Fatalf("bad: %v", err) 2750 } 2751 if _, err := state.EvalByID(ws, b2.ID); err != nil { 2752 t.Fatalf("bad: %v", err) 2753 } 2754 2755 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 2756 t.Fatalf("err: %v", err) 2757 } 2758 2759 if !watchFired(ws) { 2760 t.Fatalf("bad") 2761 } 2762 2763 ws = memdb.NewWatchSet() 2764 out, err := state.EvalByID(ws, eval.ID) 2765 if err != nil { 2766 t.Fatalf("err: %v", err) 2767 } 2768 2769 if !reflect.DeepEqual(eval, out) { 2770 t.Fatalf("bad: %#v %#v", eval, out) 2771 } 2772 2773 index, err := state.Index("evals") 2774 if err != nil { 2775 t.Fatalf("err: %v", err) 2776 } 2777 if index != 1000 { 2778 t.Fatalf("bad: %d", index) 2779 } 2780 2781 // Get b1/b2 and check they are cancelled 2782 out1, err := state.EvalByID(ws, b1.ID) 2783 if err != nil { 2784 t.Fatalf("err: %v", err) 2785 } 2786 2787 out2, err := state.EvalByID(ws, b2.ID) 2788 if err != nil { 2789 t.Fatalf("err: %v", err) 2790 } 2791 2792 if out1.Status != structs.EvalStatusCancelled || out2.Status != structs.EvalStatusCancelled { 2793 t.Fatalf("bad: %#v %#v", out1, out2) 2794 } 2795 2796 if watchFired(ws) { 2797 t.Fatalf("bad") 2798 } 2799 } 2800 2801 func TestStateStore_Update_UpsertEvals_Eval(t *testing.T) { 2802 state := testStateStore(t) 2803 eval := mock.Eval() 2804 2805 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 2806 if err != nil { 2807 t.Fatalf("err: %v", err) 2808 } 2809 2810 // Create a watchset so we can test that delete fires the watch 2811 ws := memdb.NewWatchSet() 2812 ws2 := memdb.NewWatchSet() 2813 if _, err := state.EvalByID(ws, eval.ID); err != nil { 2814 t.Fatalf("bad: %v", err) 2815 } 2816 2817 if _, err := state.EvalsByJob(ws2, eval.Namespace, eval.JobID); err != nil { 2818 t.Fatalf("bad: %v", err) 2819 } 2820 2821 eval2 := mock.Eval() 2822 eval2.ID = eval.ID 2823 eval2.JobID = eval.JobID 2824 err = state.UpsertEvals(1001, []*structs.Evaluation{eval2}) 2825 if err != nil { 2826 t.Fatalf("err: %v", err) 2827 } 2828 2829 if !watchFired(ws) { 2830 t.Fatalf("bad") 2831 } 2832 if !watchFired(ws2) { 2833 t.Fatalf("bad") 2834 } 2835 2836 ws = memdb.NewWatchSet() 2837 out, err := state.EvalByID(ws, eval.ID) 2838 if err != nil { 2839 t.Fatalf("err: %v", err) 2840 } 2841 2842 if !reflect.DeepEqual(eval2, out) { 2843 t.Fatalf("bad: %#v %#v", eval2, out) 2844 } 2845 2846 if out.CreateIndex != 1000 { 2847 t.Fatalf("bad: %#v", out) 2848 } 2849 if out.ModifyIndex != 1001 { 2850 t.Fatalf("bad: %#v", out) 2851 } 2852 2853 index, err := state.Index("evals") 2854 if err != nil { 2855 t.Fatalf("err: %v", err) 2856 } 2857 if index != 1001 { 2858 t.Fatalf("bad: %d", index) 2859 } 2860 2861 if watchFired(ws) { 2862 t.Fatalf("bad") 2863 } 2864 } 2865 2866 func TestStateStore_UpsertEvals_Eval_ChildJob(t *testing.T) { 2867 state := testStateStore(t) 2868 2869 parent := mock.Job() 2870 if err := state.UpsertJob(998, parent); err != nil { 2871 t.Fatalf("err: %v", err) 2872 } 2873 2874 child := mock.Job() 2875 child.ParentID = parent.ID 2876 2877 if err := state.UpsertJob(999, child); err != nil { 2878 t.Fatalf("err: %v", err) 2879 } 2880 2881 eval := mock.Eval() 2882 eval.Status = structs.EvalStatusComplete 2883 eval.JobID = child.ID 2884 2885 // Create watchsets so we can test that upsert fires the watch 2886 ws := memdb.NewWatchSet() 2887 ws2 := memdb.NewWatchSet() 2888 ws3 := memdb.NewWatchSet() 2889 if _, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID); err != nil { 2890 t.Fatalf("bad: %v", err) 2891 } 2892 if _, err := state.EvalByID(ws2, eval.ID); err != nil { 2893 t.Fatalf("bad: %v", err) 2894 } 2895 if _, err := state.EvalsByJob(ws3, eval.Namespace, eval.JobID); err != nil { 2896 t.Fatalf("bad: %v", err) 2897 } 2898 2899 err := state.UpsertEvals(1000, []*structs.Evaluation{eval}) 2900 if err != nil { 2901 t.Fatalf("err: %v", err) 2902 } 2903 2904 if !watchFired(ws) { 2905 t.Fatalf("bad") 2906 } 2907 if !watchFired(ws2) { 2908 t.Fatalf("bad") 2909 } 2910 if !watchFired(ws3) { 2911 t.Fatalf("bad") 2912 } 2913 2914 ws = memdb.NewWatchSet() 2915 out, err := state.EvalByID(ws, eval.ID) 2916 if err != nil { 2917 t.Fatalf("err: %v", err) 2918 } 2919 2920 if !reflect.DeepEqual(eval, out) { 2921 t.Fatalf("bad: %#v %#v", eval, out) 2922 } 2923 2924 index, err := state.Index("evals") 2925 if err != nil { 2926 t.Fatalf("err: %v", err) 2927 } 2928 if index != 1000 { 2929 t.Fatalf("bad: %d", index) 2930 } 2931 2932 summary, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID) 2933 if err != nil { 2934 t.Fatalf("err: %v", err) 2935 } 2936 if summary == nil { 2937 t.Fatalf("nil summary") 2938 } 2939 if summary.JobID != parent.ID { 2940 t.Fatalf("bad summary id: %v", parent.ID) 2941 } 2942 if summary.Children == nil { 2943 t.Fatalf("nil children summary") 2944 } 2945 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 2946 t.Fatalf("bad children summary: %v", summary.Children) 2947 } 2948 2949 if watchFired(ws) { 2950 t.Fatalf("bad") 2951 } 2952 } 2953 2954 func TestStateStore_DeleteEval_Eval(t *testing.T) { 2955 state := testStateStore(t) 2956 eval1 := mock.Eval() 2957 eval2 := mock.Eval() 2958 alloc1 := mock.Alloc() 2959 alloc2 := mock.Alloc() 2960 2961 // Create watchsets so we can test that upsert fires the watch 2962 watches := make([]memdb.WatchSet, 12) 2963 for i := 0; i < 12; i++ { 2964 watches[i] = memdb.NewWatchSet() 2965 } 2966 if _, err := state.EvalByID(watches[0], eval1.ID); err != nil { 2967 t.Fatalf("bad: %v", err) 2968 } 2969 if _, err := state.EvalByID(watches[1], eval2.ID); err != nil { 2970 t.Fatalf("bad: %v", err) 2971 } 2972 if _, err := state.EvalsByJob(watches[2], eval1.Namespace, eval1.JobID); err != nil { 2973 t.Fatalf("bad: %v", err) 2974 } 2975 if _, err := state.EvalsByJob(watches[3], eval2.Namespace, eval2.JobID); err != nil { 2976 t.Fatalf("bad: %v", err) 2977 } 2978 if _, err := state.AllocByID(watches[4], alloc1.ID); err != nil { 2979 t.Fatalf("bad: %v", err) 2980 } 2981 if _, err := state.AllocByID(watches[5], alloc2.ID); err != nil { 2982 t.Fatalf("bad: %v", err) 2983 } 2984 if _, err := state.AllocsByEval(watches[6], alloc1.EvalID); err != nil { 2985 t.Fatalf("bad: %v", err) 2986 } 2987 if _, err := state.AllocsByEval(watches[7], alloc2.EvalID); err != nil { 2988 t.Fatalf("bad: %v", err) 2989 } 2990 if _, err := state.AllocsByJob(watches[8], alloc1.Namespace, alloc1.JobID, false); err != nil { 2991 t.Fatalf("bad: %v", err) 2992 } 2993 if _, err := state.AllocsByJob(watches[9], alloc2.Namespace, alloc2.JobID, false); err != nil { 2994 t.Fatalf("bad: %v", err) 2995 } 2996 if _, err := state.AllocsByNode(watches[10], alloc1.NodeID); err != nil { 2997 t.Fatalf("bad: %v", err) 2998 } 2999 if _, err := state.AllocsByNode(watches[11], alloc2.NodeID); err != nil { 3000 t.Fatalf("bad: %v", err) 3001 } 3002 3003 state.UpsertJobSummary(900, mock.JobSummary(eval1.JobID)) 3004 state.UpsertJobSummary(901, mock.JobSummary(eval2.JobID)) 3005 state.UpsertJobSummary(902, mock.JobSummary(alloc1.JobID)) 3006 state.UpsertJobSummary(903, mock.JobSummary(alloc2.JobID)) 3007 err := state.UpsertEvals(1000, []*structs.Evaluation{eval1, eval2}) 3008 if err != nil { 3009 t.Fatalf("err: %v", err) 3010 } 3011 3012 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1, alloc2}) 3013 if err != nil { 3014 t.Fatalf("err: %v", err) 3015 } 3016 3017 err = state.DeleteEval(1002, []string{eval1.ID, eval2.ID}, []string{alloc1.ID, alloc2.ID}) 3018 if err != nil { 3019 t.Fatalf("err: %v", err) 3020 } 3021 3022 for i, ws := range watches { 3023 if !watchFired(ws) { 3024 t.Fatalf("bad %d", i) 3025 } 3026 } 3027 3028 ws := memdb.NewWatchSet() 3029 out, err := state.EvalByID(ws, eval1.ID) 3030 if err != nil { 3031 t.Fatalf("err: %v", err) 3032 } 3033 3034 if out != nil { 3035 t.Fatalf("bad: %#v %#v", eval1, out) 3036 } 3037 3038 out, err = state.EvalByID(ws, eval2.ID) 3039 if err != nil { 3040 t.Fatalf("err: %v", err) 3041 } 3042 3043 if out != nil { 3044 t.Fatalf("bad: %#v %#v", eval1, out) 3045 } 3046 3047 outA, err := state.AllocByID(ws, alloc1.ID) 3048 if err != nil { 3049 t.Fatalf("err: %v", err) 3050 } 3051 3052 if out != nil { 3053 t.Fatalf("bad: %#v %#v", alloc1, outA) 3054 } 3055 3056 outA, err = state.AllocByID(ws, alloc2.ID) 3057 if err != nil { 3058 t.Fatalf("err: %v", err) 3059 } 3060 3061 if out != nil { 3062 t.Fatalf("bad: %#v %#v", alloc1, outA) 3063 } 3064 3065 index, err := state.Index("evals") 3066 if err != nil { 3067 t.Fatalf("err: %v", err) 3068 } 3069 if index != 1002 { 3070 t.Fatalf("bad: %d", index) 3071 } 3072 3073 index, err = state.Index("allocs") 3074 if err != nil { 3075 t.Fatalf("err: %v", err) 3076 } 3077 if index != 1002 { 3078 t.Fatalf("bad: %d", index) 3079 } 3080 3081 if watchFired(ws) { 3082 t.Fatalf("bad") 3083 } 3084 } 3085 3086 func TestStateStore_DeleteEval_ChildJob(t *testing.T) { 3087 state := testStateStore(t) 3088 3089 parent := mock.Job() 3090 if err := state.UpsertJob(998, parent); err != nil { 3091 t.Fatalf("err: %v", err) 3092 } 3093 3094 child := mock.Job() 3095 child.ParentID = parent.ID 3096 3097 if err := state.UpsertJob(999, child); err != nil { 3098 t.Fatalf("err: %v", err) 3099 } 3100 3101 eval1 := mock.Eval() 3102 eval1.JobID = child.ID 3103 alloc1 := mock.Alloc() 3104 alloc1.JobID = child.ID 3105 3106 err := state.UpsertEvals(1000, []*structs.Evaluation{eval1}) 3107 if err != nil { 3108 t.Fatalf("err: %v", err) 3109 } 3110 3111 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc1}) 3112 if err != nil { 3113 t.Fatalf("err: %v", err) 3114 } 3115 3116 // Create watchsets so we can test that delete fires the watch 3117 ws := memdb.NewWatchSet() 3118 if _, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID); err != nil { 3119 t.Fatalf("bad: %v", err) 3120 } 3121 3122 err = state.DeleteEval(1002, []string{eval1.ID}, []string{alloc1.ID}) 3123 if err != nil { 3124 t.Fatalf("err: %v", err) 3125 } 3126 3127 if !watchFired(ws) { 3128 t.Fatalf("bad") 3129 } 3130 3131 ws = memdb.NewWatchSet() 3132 summary, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID) 3133 if err != nil { 3134 t.Fatalf("err: %v", err) 3135 } 3136 if summary == nil { 3137 t.Fatalf("nil summary") 3138 } 3139 if summary.JobID != parent.ID { 3140 t.Fatalf("bad summary id: %v", parent.ID) 3141 } 3142 if summary.Children == nil { 3143 t.Fatalf("nil children summary") 3144 } 3145 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 3146 t.Fatalf("bad children summary: %v", summary.Children) 3147 } 3148 3149 if watchFired(ws) { 3150 t.Fatalf("bad") 3151 } 3152 } 3153 3154 func TestStateStore_EvalsByJob(t *testing.T) { 3155 state := testStateStore(t) 3156 3157 eval1 := mock.Eval() 3158 eval2 := mock.Eval() 3159 eval2.JobID = eval1.JobID 3160 eval3 := mock.Eval() 3161 evals := []*structs.Evaluation{eval1, eval2} 3162 3163 err := state.UpsertEvals(1000, evals) 3164 if err != nil { 3165 t.Fatalf("err: %v", err) 3166 } 3167 err = state.UpsertEvals(1001, []*structs.Evaluation{eval3}) 3168 if err != nil { 3169 t.Fatalf("err: %v", err) 3170 } 3171 3172 ws := memdb.NewWatchSet() 3173 out, err := state.EvalsByJob(ws, eval1.Namespace, eval1.JobID) 3174 if err != nil { 3175 t.Fatalf("err: %v", err) 3176 } 3177 3178 sort.Sort(EvalIDSort(evals)) 3179 sort.Sort(EvalIDSort(out)) 3180 3181 if !reflect.DeepEqual(evals, out) { 3182 t.Fatalf("bad: %#v %#v", evals, out) 3183 } 3184 3185 if watchFired(ws) { 3186 t.Fatalf("bad") 3187 } 3188 } 3189 3190 func TestStateStore_Evals(t *testing.T) { 3191 state := testStateStore(t) 3192 var evals []*structs.Evaluation 3193 3194 for i := 0; i < 10; i++ { 3195 eval := mock.Eval() 3196 evals = append(evals, eval) 3197 3198 err := state.UpsertEvals(1000+uint64(i), []*structs.Evaluation{eval}) 3199 if err != nil { 3200 t.Fatalf("err: %v", err) 3201 } 3202 } 3203 3204 ws := memdb.NewWatchSet() 3205 iter, err := state.Evals(ws) 3206 if err != nil { 3207 t.Fatalf("err: %v", err) 3208 } 3209 3210 var out []*structs.Evaluation 3211 for { 3212 raw := iter.Next() 3213 if raw == nil { 3214 break 3215 } 3216 out = append(out, raw.(*structs.Evaluation)) 3217 } 3218 3219 sort.Sort(EvalIDSort(evals)) 3220 sort.Sort(EvalIDSort(out)) 3221 3222 if !reflect.DeepEqual(evals, out) { 3223 t.Fatalf("bad: %#v %#v", evals, out) 3224 } 3225 3226 if watchFired(ws) { 3227 t.Fatalf("bad") 3228 } 3229 } 3230 3231 func TestStateStore_EvalsByIDPrefix(t *testing.T) { 3232 state := testStateStore(t) 3233 var evals []*structs.Evaluation 3234 3235 ids := []string{ 3236 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 3237 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 3238 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 3239 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 3240 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 3241 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 3242 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 3243 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 3244 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 3245 } 3246 for i := 0; i < 9; i++ { 3247 eval := mock.Eval() 3248 eval.ID = ids[i] 3249 evals = append(evals, eval) 3250 } 3251 3252 err := state.UpsertEvals(1000, evals) 3253 if err != nil { 3254 t.Fatalf("err: %v", err) 3255 } 3256 3257 ws := memdb.NewWatchSet() 3258 iter, err := state.EvalsByIDPrefix(ws, structs.DefaultNamespace, "aaaa") 3259 if err != nil { 3260 t.Fatalf("err: %v", err) 3261 } 3262 3263 gatherEvals := func(iter memdb.ResultIterator) []*structs.Evaluation { 3264 var evals []*structs.Evaluation 3265 for { 3266 raw := iter.Next() 3267 if raw == nil { 3268 break 3269 } 3270 evals = append(evals, raw.(*structs.Evaluation)) 3271 } 3272 return evals 3273 } 3274 3275 out := gatherEvals(iter) 3276 if len(out) != 5 { 3277 t.Fatalf("bad: expected five evaluations, got: %#v", out) 3278 } 3279 3280 sort.Sort(EvalIDSort(evals)) 3281 3282 for index, eval := range out { 3283 if ids[index] != eval.ID { 3284 t.Fatalf("bad: got unexpected id: %s", eval.ID) 3285 } 3286 } 3287 3288 iter, err = state.EvalsByIDPrefix(ws, structs.DefaultNamespace, "b-a7bfb") 3289 if err != nil { 3290 t.Fatalf("err: %v", err) 3291 } 3292 3293 out = gatherEvals(iter) 3294 if len(out) != 0 { 3295 t.Fatalf("bad: unexpected zero evaluations, got: %#v", out) 3296 } 3297 3298 if watchFired(ws) { 3299 t.Fatalf("bad") 3300 } 3301 } 3302 3303 func TestStateStore_RestoreEval(t *testing.T) { 3304 state := testStateStore(t) 3305 eval := mock.Eval() 3306 3307 restore, err := state.Restore() 3308 if err != nil { 3309 t.Fatalf("err: %v", err) 3310 } 3311 3312 err = restore.EvalRestore(eval) 3313 if err != nil { 3314 t.Fatalf("err: %v", err) 3315 } 3316 restore.Commit() 3317 3318 ws := memdb.NewWatchSet() 3319 out, err := state.EvalByID(ws, eval.ID) 3320 if err != nil { 3321 t.Fatalf("err: %v", err) 3322 } 3323 3324 if !reflect.DeepEqual(out, eval) { 3325 t.Fatalf("Bad: %#v %#v", out, eval) 3326 } 3327 } 3328 3329 func TestStateStore_UpdateAllocsFromClient(t *testing.T) { 3330 state := testStateStore(t) 3331 parent := mock.Job() 3332 if err := state.UpsertJob(998, parent); err != nil { 3333 t.Fatalf("err: %v", err) 3334 } 3335 3336 child := mock.Job() 3337 child.ParentID = parent.ID 3338 if err := state.UpsertJob(999, child); err != nil { 3339 t.Fatalf("err: %v", err) 3340 } 3341 3342 alloc := mock.Alloc() 3343 alloc.JobID = child.ID 3344 alloc.Job = child 3345 3346 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3347 if err != nil { 3348 t.Fatalf("err: %v", err) 3349 } 3350 3351 ws := memdb.NewWatchSet() 3352 summary, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID) 3353 if err != nil { 3354 t.Fatalf("err: %v", err) 3355 } 3356 if summary == nil { 3357 t.Fatalf("nil summary") 3358 } 3359 if summary.JobID != parent.ID { 3360 t.Fatalf("bad summary id: %v", parent.ID) 3361 } 3362 if summary.Children == nil { 3363 t.Fatalf("nil children summary") 3364 } 3365 if summary.Children.Pending != 0 || summary.Children.Running != 1 || summary.Children.Dead != 0 { 3366 t.Fatalf("bad children summary: %v", summary.Children) 3367 } 3368 3369 // Create watchsets so we can test that update fires the watch 3370 ws = memdb.NewWatchSet() 3371 if _, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID); err != nil { 3372 t.Fatalf("bad: %v", err) 3373 } 3374 3375 // Create the delta updates 3376 ts := map[string]*structs.TaskState{"web": {State: structs.TaskStateRunning}} 3377 update := &structs.Allocation{ 3378 ID: alloc.ID, 3379 ClientStatus: structs.AllocClientStatusComplete, 3380 TaskStates: ts, 3381 JobID: alloc.JobID, 3382 TaskGroup: alloc.TaskGroup, 3383 } 3384 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update}) 3385 if err != nil { 3386 t.Fatalf("err: %v", err) 3387 } 3388 3389 if !watchFired(ws) { 3390 t.Fatalf("bad") 3391 } 3392 3393 ws = memdb.NewWatchSet() 3394 summary, err = state.JobSummaryByID(ws, parent.Namespace, parent.ID) 3395 if err != nil { 3396 t.Fatalf("err: %v", err) 3397 } 3398 if summary == nil { 3399 t.Fatalf("nil summary") 3400 } 3401 if summary.JobID != parent.ID { 3402 t.Fatalf("bad summary id: %v", parent.ID) 3403 } 3404 if summary.Children == nil { 3405 t.Fatalf("nil children summary") 3406 } 3407 if summary.Children.Pending != 0 || summary.Children.Running != 0 || summary.Children.Dead != 1 { 3408 t.Fatalf("bad children summary: %v", summary.Children) 3409 } 3410 3411 if watchFired(ws) { 3412 t.Fatalf("bad") 3413 } 3414 } 3415 3416 func TestStateStore_UpdateAllocsFromClient_ChildJob(t *testing.T) { 3417 state := testStateStore(t) 3418 alloc1 := mock.Alloc() 3419 alloc2 := mock.Alloc() 3420 3421 if err := state.UpsertJob(999, alloc1.Job); err != nil { 3422 t.Fatalf("err: %v", err) 3423 } 3424 if err := state.UpsertJob(999, alloc2.Job); err != nil { 3425 t.Fatalf("err: %v", err) 3426 } 3427 3428 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc1, alloc2}) 3429 if err != nil { 3430 t.Fatalf("err: %v", err) 3431 } 3432 3433 // Create watchsets so we can test that update fires the watch 3434 watches := make([]memdb.WatchSet, 8) 3435 for i := 0; i < 8; i++ { 3436 watches[i] = memdb.NewWatchSet() 3437 } 3438 if _, err := state.AllocByID(watches[0], alloc1.ID); err != nil { 3439 t.Fatalf("bad: %v", err) 3440 } 3441 if _, err := state.AllocByID(watches[1], alloc2.ID); err != nil { 3442 t.Fatalf("bad: %v", err) 3443 } 3444 if _, err := state.AllocsByEval(watches[2], alloc1.EvalID); err != nil { 3445 t.Fatalf("bad: %v", err) 3446 } 3447 if _, err := state.AllocsByEval(watches[3], alloc2.EvalID); err != nil { 3448 t.Fatalf("bad: %v", err) 3449 } 3450 if _, err := state.AllocsByJob(watches[4], alloc1.Namespace, alloc1.JobID, false); err != nil { 3451 t.Fatalf("bad: %v", err) 3452 } 3453 if _, err := state.AllocsByJob(watches[5], alloc2.Namespace, alloc2.JobID, false); err != nil { 3454 t.Fatalf("bad: %v", err) 3455 } 3456 if _, err := state.AllocsByNode(watches[6], alloc1.NodeID); err != nil { 3457 t.Fatalf("bad: %v", err) 3458 } 3459 if _, err := state.AllocsByNode(watches[7], alloc2.NodeID); err != nil { 3460 t.Fatalf("bad: %v", err) 3461 } 3462 3463 // Create the delta updates 3464 ts := map[string]*structs.TaskState{"web": {State: structs.TaskStatePending}} 3465 update := &structs.Allocation{ 3466 ID: alloc1.ID, 3467 ClientStatus: structs.AllocClientStatusFailed, 3468 TaskStates: ts, 3469 JobID: alloc1.JobID, 3470 TaskGroup: alloc1.TaskGroup, 3471 } 3472 update2 := &structs.Allocation{ 3473 ID: alloc2.ID, 3474 ClientStatus: structs.AllocClientStatusRunning, 3475 TaskStates: ts, 3476 JobID: alloc2.JobID, 3477 TaskGroup: alloc2.TaskGroup, 3478 } 3479 3480 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 3481 if err != nil { 3482 t.Fatalf("err: %v", err) 3483 } 3484 3485 for i, ws := range watches { 3486 if !watchFired(ws) { 3487 t.Fatalf("bad %d", i) 3488 } 3489 } 3490 3491 ws := memdb.NewWatchSet() 3492 out, err := state.AllocByID(ws, alloc1.ID) 3493 if err != nil { 3494 t.Fatalf("err: %v", err) 3495 } 3496 3497 alloc1.CreateIndex = 1000 3498 alloc1.ModifyIndex = 1001 3499 alloc1.TaskStates = ts 3500 alloc1.ClientStatus = structs.AllocClientStatusFailed 3501 if !reflect.DeepEqual(alloc1, out) { 3502 t.Fatalf("bad: %#v %#v", alloc1, out) 3503 } 3504 3505 out, err = state.AllocByID(ws, alloc2.ID) 3506 if err != nil { 3507 t.Fatalf("err: %v", err) 3508 } 3509 3510 alloc2.ModifyIndex = 1000 3511 alloc2.ModifyIndex = 1001 3512 alloc2.ClientStatus = structs.AllocClientStatusRunning 3513 alloc2.TaskStates = ts 3514 if !reflect.DeepEqual(alloc2, out) { 3515 t.Fatalf("bad: %#v %#v", alloc2, out) 3516 } 3517 3518 index, err := state.Index("allocs") 3519 if err != nil { 3520 t.Fatalf("err: %v", err) 3521 } 3522 if index != 1001 { 3523 t.Fatalf("bad: %d", index) 3524 } 3525 3526 // Ensure summaries have been updated 3527 summary, err := state.JobSummaryByID(ws, alloc1.Namespace, alloc1.JobID) 3528 if err != nil { 3529 t.Fatalf("err: %v", err) 3530 } 3531 tgSummary := summary.Summary["web"] 3532 if tgSummary.Failed != 1 { 3533 t.Fatalf("expected failed: %v, actual: %v, summary: %#v", 1, tgSummary.Failed, tgSummary) 3534 } 3535 3536 summary2, err := state.JobSummaryByID(ws, alloc2.Namespace, alloc2.JobID) 3537 if err != nil { 3538 t.Fatalf("err: %v", err) 3539 } 3540 tgSummary2 := summary2.Summary["web"] 3541 if tgSummary2.Running != 1 { 3542 t.Fatalf("expected running: %v, actual: %v", 1, tgSummary2.Running) 3543 } 3544 3545 if watchFired(ws) { 3546 t.Fatalf("bad") 3547 } 3548 } 3549 3550 func TestStateStore_UpdateMultipleAllocsFromClient(t *testing.T) { 3551 state := testStateStore(t) 3552 alloc := mock.Alloc() 3553 3554 if err := state.UpsertJob(999, alloc.Job); err != nil { 3555 t.Fatalf("err: %v", err) 3556 } 3557 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3558 if err != nil { 3559 t.Fatalf("err: %v", err) 3560 } 3561 3562 // Create the delta updates 3563 ts := map[string]*structs.TaskState{"web": {State: structs.TaskStatePending}} 3564 update := &structs.Allocation{ 3565 ID: alloc.ID, 3566 ClientStatus: structs.AllocClientStatusRunning, 3567 TaskStates: ts, 3568 JobID: alloc.JobID, 3569 TaskGroup: alloc.TaskGroup, 3570 } 3571 update2 := &structs.Allocation{ 3572 ID: alloc.ID, 3573 ClientStatus: structs.AllocClientStatusPending, 3574 TaskStates: ts, 3575 JobID: alloc.JobID, 3576 TaskGroup: alloc.TaskGroup, 3577 } 3578 3579 err = state.UpdateAllocsFromClient(1001, []*structs.Allocation{update, update2}) 3580 if err != nil { 3581 t.Fatalf("err: %v", err) 3582 } 3583 3584 ws := memdb.NewWatchSet() 3585 out, err := state.AllocByID(ws, alloc.ID) 3586 if err != nil { 3587 t.Fatalf("err: %v", err) 3588 } 3589 3590 alloc.CreateIndex = 1000 3591 alloc.ModifyIndex = 1001 3592 alloc.TaskStates = ts 3593 alloc.ClientStatus = structs.AllocClientStatusPending 3594 if !reflect.DeepEqual(alloc, out) { 3595 t.Fatalf("bad: %#v , actual:%#v", alloc, out) 3596 } 3597 3598 summary, err := state.JobSummaryByID(ws, alloc.Namespace, alloc.JobID) 3599 expectedSummary := &structs.JobSummary{ 3600 JobID: alloc.JobID, 3601 Namespace: alloc.Namespace, 3602 Summary: map[string]structs.TaskGroupSummary{ 3603 "web": { 3604 Starting: 1, 3605 }, 3606 }, 3607 Children: new(structs.JobChildrenSummary), 3608 CreateIndex: 999, 3609 ModifyIndex: 1001, 3610 } 3611 if err != nil { 3612 t.Fatalf("err: %v", err) 3613 } 3614 if !reflect.DeepEqual(summary, expectedSummary) { 3615 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 3616 } 3617 } 3618 3619 func TestStateStore_UpdateAllocsFromClient_Deployment(t *testing.T) { 3620 require := require.New(t) 3621 state := testStateStore(t) 3622 3623 alloc := mock.Alloc() 3624 now := time.Now() 3625 alloc.CreateTime = now.UnixNano() 3626 pdeadline := 5 * time.Minute 3627 deployment := mock.Deployment() 3628 deployment.TaskGroups[alloc.TaskGroup].ProgressDeadline = pdeadline 3629 alloc.DeploymentID = deployment.ID 3630 3631 require.Nil(state.UpsertJob(999, alloc.Job)) 3632 require.Nil(state.UpsertDeployment(1000, deployment)) 3633 require.Nil(state.UpsertAllocs(1001, []*structs.Allocation{alloc})) 3634 3635 healthy := now.Add(time.Second) 3636 update := &structs.Allocation{ 3637 ID: alloc.ID, 3638 ClientStatus: structs.AllocClientStatusRunning, 3639 JobID: alloc.JobID, 3640 TaskGroup: alloc.TaskGroup, 3641 DeploymentStatus: &structs.AllocDeploymentStatus{ 3642 Healthy: helper.BoolToPtr(true), 3643 Timestamp: healthy, 3644 }, 3645 } 3646 require.Nil(state.UpdateAllocsFromClient(1001, []*structs.Allocation{update})) 3647 3648 // Check that the deployment state was updated because the healthy 3649 // deployment 3650 dout, err := state.DeploymentByID(nil, deployment.ID) 3651 require.Nil(err) 3652 require.NotNil(dout) 3653 require.Len(dout.TaskGroups, 1) 3654 dstate := dout.TaskGroups[alloc.TaskGroup] 3655 require.NotNil(dstate) 3656 require.Equal(1, dstate.PlacedAllocs) 3657 require.True(healthy.Add(pdeadline).Equal(dstate.RequireProgressBy)) 3658 } 3659 3660 // This tests that the deployment state is merged correctly 3661 func TestStateStore_UpdateAllocsFromClient_DeploymentStateMerges(t *testing.T) { 3662 require := require.New(t) 3663 state := testStateStore(t) 3664 3665 alloc := mock.Alloc() 3666 now := time.Now() 3667 alloc.CreateTime = now.UnixNano() 3668 pdeadline := 5 * time.Minute 3669 deployment := mock.Deployment() 3670 deployment.TaskGroups[alloc.TaskGroup].ProgressDeadline = pdeadline 3671 alloc.DeploymentID = deployment.ID 3672 alloc.DeploymentStatus = &structs.AllocDeploymentStatus{ 3673 Canary: true, 3674 } 3675 3676 require.Nil(state.UpsertJob(999, alloc.Job)) 3677 require.Nil(state.UpsertDeployment(1000, deployment)) 3678 require.Nil(state.UpsertAllocs(1001, []*structs.Allocation{alloc})) 3679 3680 update := &structs.Allocation{ 3681 ID: alloc.ID, 3682 ClientStatus: structs.AllocClientStatusRunning, 3683 JobID: alloc.JobID, 3684 TaskGroup: alloc.TaskGroup, 3685 DeploymentStatus: &structs.AllocDeploymentStatus{ 3686 Healthy: helper.BoolToPtr(true), 3687 Canary: false, 3688 }, 3689 } 3690 require.Nil(state.UpdateAllocsFromClient(1001, []*structs.Allocation{update})) 3691 3692 // Check that the merging of the deployment status was correct 3693 out, err := state.AllocByID(nil, alloc.ID) 3694 require.Nil(err) 3695 require.NotNil(out) 3696 require.True(out.DeploymentStatus.Canary) 3697 require.NotNil(out.DeploymentStatus.Healthy) 3698 require.True(*out.DeploymentStatus.Healthy) 3699 } 3700 3701 func TestStateStore_UpsertAlloc_Alloc(t *testing.T) { 3702 state := testStateStore(t) 3703 alloc := mock.Alloc() 3704 3705 if err := state.UpsertJob(999, alloc.Job); err != nil { 3706 t.Fatalf("err: %v", err) 3707 } 3708 3709 // Create watchsets so we can test that update fires the watch 3710 watches := make([]memdb.WatchSet, 4) 3711 for i := 0; i < 4; i++ { 3712 watches[i] = memdb.NewWatchSet() 3713 } 3714 if _, err := state.AllocByID(watches[0], alloc.ID); err != nil { 3715 t.Fatalf("bad: %v", err) 3716 } 3717 if _, err := state.AllocsByEval(watches[1], alloc.EvalID); err != nil { 3718 t.Fatalf("bad: %v", err) 3719 } 3720 if _, err := state.AllocsByJob(watches[2], alloc.Namespace, alloc.JobID, false); err != nil { 3721 t.Fatalf("bad: %v", err) 3722 } 3723 if _, err := state.AllocsByNode(watches[3], alloc.NodeID); err != nil { 3724 t.Fatalf("bad: %v", err) 3725 } 3726 3727 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3728 if err != nil { 3729 t.Fatalf("err: %v", err) 3730 } 3731 3732 for i, ws := range watches { 3733 if !watchFired(ws) { 3734 t.Fatalf("bad %d", i) 3735 } 3736 } 3737 3738 ws := memdb.NewWatchSet() 3739 out, err := state.AllocByID(ws, alloc.ID) 3740 if err != nil { 3741 t.Fatalf("err: %v", err) 3742 } 3743 3744 if !reflect.DeepEqual(alloc, out) { 3745 t.Fatalf("bad: %#v %#v", alloc, out) 3746 } 3747 3748 index, err := state.Index("allocs") 3749 if err != nil { 3750 t.Fatalf("err: %v", err) 3751 } 3752 if index != 1000 { 3753 t.Fatalf("bad: %d", index) 3754 } 3755 3756 summary, err := state.JobSummaryByID(ws, alloc.Namespace, alloc.JobID) 3757 if err != nil { 3758 t.Fatalf("err: %v", err) 3759 } 3760 3761 tgSummary, ok := summary.Summary["web"] 3762 if !ok { 3763 t.Fatalf("no summary for task group web") 3764 } 3765 if tgSummary.Starting != 1 { 3766 t.Fatalf("expected queued: %v, actual: %v", 1, tgSummary.Starting) 3767 } 3768 3769 if watchFired(ws) { 3770 t.Fatalf("bad") 3771 } 3772 } 3773 3774 func TestStateStore_UpsertAlloc_Deployment(t *testing.T) { 3775 require := require.New(t) 3776 state := testStateStore(t) 3777 alloc := mock.Alloc() 3778 now := time.Now() 3779 alloc.CreateTime = now.UnixNano() 3780 alloc.ModifyTime = now.UnixNano() 3781 pdeadline := 5 * time.Minute 3782 deployment := mock.Deployment() 3783 deployment.TaskGroups[alloc.TaskGroup].ProgressDeadline = pdeadline 3784 alloc.DeploymentID = deployment.ID 3785 3786 require.Nil(state.UpsertJob(999, alloc.Job)) 3787 require.Nil(state.UpsertDeployment(1000, deployment)) 3788 3789 // Create a watch set so we can test that update fires the watch 3790 ws := memdb.NewWatchSet() 3791 require.Nil(state.AllocsByDeployment(ws, alloc.DeploymentID)) 3792 3793 err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}) 3794 require.Nil(err) 3795 3796 if !watchFired(ws) { 3797 t.Fatalf("watch not fired") 3798 } 3799 3800 ws = memdb.NewWatchSet() 3801 allocs, err := state.AllocsByDeployment(ws, alloc.DeploymentID) 3802 require.Nil(err) 3803 require.Len(allocs, 1) 3804 require.EqualValues(alloc, allocs[0]) 3805 3806 index, err := state.Index("allocs") 3807 require.Nil(err) 3808 require.EqualValues(1001, index) 3809 if watchFired(ws) { 3810 t.Fatalf("bad") 3811 } 3812 3813 // Check that the deployment state was updated 3814 dout, err := state.DeploymentByID(nil, deployment.ID) 3815 require.Nil(err) 3816 require.NotNil(dout) 3817 require.Len(dout.TaskGroups, 1) 3818 dstate := dout.TaskGroups[alloc.TaskGroup] 3819 require.NotNil(dstate) 3820 require.Equal(1, dstate.PlacedAllocs) 3821 require.True(now.Add(pdeadline).Equal(dstate.RequireProgressBy)) 3822 } 3823 3824 // Testing to ensure we keep issue 3825 // https://github.com/hashicorp/nomad/issues/2583 fixed 3826 func TestStateStore_UpsertAlloc_No_Job(t *testing.T) { 3827 state := testStateStore(t) 3828 alloc := mock.Alloc() 3829 alloc.Job = nil 3830 3831 err := state.UpsertAllocs(999, []*structs.Allocation{alloc}) 3832 if err == nil || !strings.Contains(err.Error(), "without a job") { 3833 t.Fatalf("expect err: %v", err) 3834 } 3835 } 3836 3837 func TestStateStore_UpsertAlloc_NoEphemeralDisk(t *testing.T) { 3838 state := testStateStore(t) 3839 alloc := mock.Alloc() 3840 alloc.Job.TaskGroups[0].EphemeralDisk = nil 3841 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 3842 3843 if err := state.UpsertJob(999, alloc.Job); err != nil { 3844 t.Fatalf("err: %v", err) 3845 } 3846 3847 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3848 if err != nil { 3849 t.Fatalf("err: %v", err) 3850 } 3851 3852 ws := memdb.NewWatchSet() 3853 out, err := state.AllocByID(ws, alloc.ID) 3854 if err != nil { 3855 t.Fatalf("err: %v", err) 3856 } 3857 3858 expected := alloc.Copy() 3859 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 3860 if !reflect.DeepEqual(expected, out) { 3861 t.Fatalf("bad: %#v %#v", expected, out) 3862 } 3863 } 3864 3865 func TestStateStore_UpsertAlloc_ChildJob(t *testing.T) { 3866 state := testStateStore(t) 3867 3868 parent := mock.Job() 3869 if err := state.UpsertJob(998, parent); err != nil { 3870 t.Fatalf("err: %v", err) 3871 } 3872 3873 child := mock.Job() 3874 child.ParentID = parent.ID 3875 3876 if err := state.UpsertJob(999, child); err != nil { 3877 t.Fatalf("err: %v", err) 3878 } 3879 3880 alloc := mock.Alloc() 3881 alloc.JobID = child.ID 3882 alloc.Job = child 3883 3884 // Create watchsets so we can test that delete fires the watch 3885 ws := memdb.NewWatchSet() 3886 if _, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID); err != nil { 3887 t.Fatalf("bad: %v", err) 3888 } 3889 3890 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3891 if err != nil { 3892 t.Fatalf("err: %v", err) 3893 } 3894 3895 if !watchFired(ws) { 3896 t.Fatalf("bad") 3897 } 3898 3899 ws = memdb.NewWatchSet() 3900 summary, err := state.JobSummaryByID(ws, parent.Namespace, parent.ID) 3901 if err != nil { 3902 t.Fatalf("err: %v", err) 3903 } 3904 if summary == nil { 3905 t.Fatalf("nil summary") 3906 } 3907 if summary.JobID != parent.ID { 3908 t.Fatalf("bad summary id: %v", parent.ID) 3909 } 3910 if summary.Children == nil { 3911 t.Fatalf("nil children summary") 3912 } 3913 if summary.Children.Pending != 0 || summary.Children.Running != 1 || summary.Children.Dead != 0 { 3914 t.Fatalf("bad children summary: %v", summary.Children) 3915 } 3916 3917 if watchFired(ws) { 3918 t.Fatalf("bad") 3919 } 3920 } 3921 3922 func TestStateStore_UpdateAlloc_Alloc(t *testing.T) { 3923 state := testStateStore(t) 3924 alloc := mock.Alloc() 3925 3926 if err := state.UpsertJob(999, alloc.Job); err != nil { 3927 t.Fatalf("err: %v", err) 3928 } 3929 3930 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 3931 if err != nil { 3932 t.Fatalf("err: %v", err) 3933 } 3934 3935 ws := memdb.NewWatchSet() 3936 summary, err := state.JobSummaryByID(ws, alloc.Namespace, alloc.JobID) 3937 if err != nil { 3938 t.Fatalf("err: %v", err) 3939 } 3940 tgSummary := summary.Summary["web"] 3941 if tgSummary.Starting != 1 { 3942 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 3943 } 3944 3945 alloc2 := mock.Alloc() 3946 alloc2.ID = alloc.ID 3947 alloc2.NodeID = alloc.NodeID + ".new" 3948 state.UpsertJobSummary(1001, mock.JobSummary(alloc2.JobID)) 3949 3950 // Create watchsets so we can test that update fires the watch 3951 watches := make([]memdb.WatchSet, 4) 3952 for i := 0; i < 4; i++ { 3953 watches[i] = memdb.NewWatchSet() 3954 } 3955 if _, err := state.AllocByID(watches[0], alloc2.ID); err != nil { 3956 t.Fatalf("bad: %v", err) 3957 } 3958 if _, err := state.AllocsByEval(watches[1], alloc2.EvalID); err != nil { 3959 t.Fatalf("bad: %v", err) 3960 } 3961 if _, err := state.AllocsByJob(watches[2], alloc2.Namespace, alloc2.JobID, false); err != nil { 3962 t.Fatalf("bad: %v", err) 3963 } 3964 if _, err := state.AllocsByNode(watches[3], alloc2.NodeID); err != nil { 3965 t.Fatalf("bad: %v", err) 3966 } 3967 3968 err = state.UpsertAllocs(1002, []*structs.Allocation{alloc2}) 3969 if err != nil { 3970 t.Fatalf("err: %v", err) 3971 } 3972 3973 for i, ws := range watches { 3974 if !watchFired(ws) { 3975 t.Fatalf("bad %d", i) 3976 } 3977 } 3978 3979 ws = memdb.NewWatchSet() 3980 out, err := state.AllocByID(ws, alloc.ID) 3981 if err != nil { 3982 t.Fatalf("err: %v", err) 3983 } 3984 3985 if !reflect.DeepEqual(alloc2, out) { 3986 t.Fatalf("bad: %#v %#v", alloc2, out) 3987 } 3988 3989 if out.CreateIndex != 1000 { 3990 t.Fatalf("bad: %#v", out) 3991 } 3992 if out.ModifyIndex != 1002 { 3993 t.Fatalf("bad: %#v", out) 3994 } 3995 3996 index, err := state.Index("allocs") 3997 if err != nil { 3998 t.Fatalf("err: %v", err) 3999 } 4000 if index != 1002 { 4001 t.Fatalf("bad: %d", index) 4002 } 4003 4004 // Ensure that summary hasb't changed 4005 summary, err = state.JobSummaryByID(ws, alloc.Namespace, alloc.JobID) 4006 if err != nil { 4007 t.Fatalf("err: %v", err) 4008 } 4009 tgSummary = summary.Summary["web"] 4010 if tgSummary.Starting != 1 { 4011 t.Fatalf("expected starting: %v, actual: %v", 1, tgSummary.Starting) 4012 } 4013 4014 if watchFired(ws) { 4015 t.Fatalf("bad") 4016 } 4017 } 4018 4019 // This test ensures that the state store will mark the clients status as lost 4020 // when set rather than preferring the existing status. 4021 func TestStateStore_UpdateAlloc_Lost(t *testing.T) { 4022 state := testStateStore(t) 4023 alloc := mock.Alloc() 4024 alloc.ClientStatus = "foo" 4025 4026 if err := state.UpsertJob(999, alloc.Job); err != nil { 4027 t.Fatalf("err: %v", err) 4028 } 4029 4030 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 4031 if err != nil { 4032 t.Fatalf("err: %v", err) 4033 } 4034 4035 alloc2 := new(structs.Allocation) 4036 *alloc2 = *alloc 4037 alloc2.ClientStatus = structs.AllocClientStatusLost 4038 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc2}); err != nil { 4039 t.Fatalf("err: %v", err) 4040 } 4041 4042 ws := memdb.NewWatchSet() 4043 out, err := state.AllocByID(ws, alloc2.ID) 4044 if err != nil { 4045 t.Fatalf("err: %v", err) 4046 } 4047 4048 if out.ClientStatus != structs.AllocClientStatusLost { 4049 t.Fatalf("bad: %#v", out) 4050 } 4051 } 4052 4053 // This test ensures an allocation can be updated when there is no job 4054 // associated with it. This will happen when a job is stopped by an user which 4055 // has non-terminal allocations on clients 4056 func TestStateStore_UpdateAlloc_NoJob(t *testing.T) { 4057 state := testStateStore(t) 4058 alloc := mock.Alloc() 4059 4060 // Upsert a job 4061 state.UpsertJobSummary(998, mock.JobSummary(alloc.JobID)) 4062 if err := state.UpsertJob(999, alloc.Job); err != nil { 4063 t.Fatalf("err: %v", err) 4064 } 4065 4066 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 4067 if err != nil { 4068 t.Fatalf("err: %v", err) 4069 } 4070 4071 if err := state.DeleteJob(1001, alloc.Namespace, alloc.JobID); err != nil { 4072 t.Fatalf("err: %v", err) 4073 } 4074 4075 // Update the desired state of the allocation to stop 4076 allocCopy := alloc.Copy() 4077 allocCopy.DesiredStatus = structs.AllocDesiredStatusStop 4078 if err := state.UpsertAllocs(1002, []*structs.Allocation{allocCopy}); err != nil { 4079 t.Fatalf("err: %v", err) 4080 } 4081 4082 // Update the client state of the allocation to complete 4083 allocCopy1 := allocCopy.Copy() 4084 allocCopy1.ClientStatus = structs.AllocClientStatusComplete 4085 if err := state.UpdateAllocsFromClient(1003, []*structs.Allocation{allocCopy1}); err != nil { 4086 t.Fatalf("err: %v", err) 4087 } 4088 4089 ws := memdb.NewWatchSet() 4090 out, _ := state.AllocByID(ws, alloc.ID) 4091 // Update the modify index of the alloc before comparing 4092 allocCopy1.ModifyIndex = 1003 4093 if !reflect.DeepEqual(out, allocCopy1) { 4094 t.Fatalf("expected: %#v \n actual: %#v", allocCopy1, out) 4095 } 4096 } 4097 4098 func TestStateStore_UpdateAllocDesiredTransition(t *testing.T) { 4099 t.Parallel() 4100 require := require.New(t) 4101 4102 state := testStateStore(t) 4103 alloc := mock.Alloc() 4104 4105 require.Nil(state.UpsertJob(999, alloc.Job)) 4106 require.Nil(state.UpsertAllocs(1000, []*structs.Allocation{alloc})) 4107 4108 t1 := &structs.DesiredTransition{ 4109 Migrate: helper.BoolToPtr(true), 4110 } 4111 t2 := &structs.DesiredTransition{ 4112 Migrate: helper.BoolToPtr(false), 4113 } 4114 eval := &structs.Evaluation{ 4115 ID: uuid.Generate(), 4116 Namespace: alloc.Namespace, 4117 Priority: alloc.Job.Priority, 4118 Type: alloc.Job.Type, 4119 TriggeredBy: structs.EvalTriggerNodeDrain, 4120 JobID: alloc.Job.ID, 4121 JobModifyIndex: alloc.Job.ModifyIndex, 4122 Status: structs.EvalStatusPending, 4123 } 4124 evals := []*structs.Evaluation{eval} 4125 4126 m := map[string]*structs.DesiredTransition{alloc.ID: t1} 4127 require.Nil(state.UpdateAllocsDesiredTransitions(1001, m, evals)) 4128 4129 ws := memdb.NewWatchSet() 4130 out, err := state.AllocByID(ws, alloc.ID) 4131 require.Nil(err) 4132 require.NotNil(out.DesiredTransition.Migrate) 4133 require.True(*out.DesiredTransition.Migrate) 4134 require.EqualValues(1000, out.CreateIndex) 4135 require.EqualValues(1001, out.ModifyIndex) 4136 4137 index, err := state.Index("allocs") 4138 require.Nil(err) 4139 require.EqualValues(1001, index) 4140 4141 // Check the eval is created 4142 eout, err := state.EvalByID(nil, eval.ID) 4143 require.Nil(err) 4144 require.NotNil(eout) 4145 4146 m = map[string]*structs.DesiredTransition{alloc.ID: t2} 4147 require.Nil(state.UpdateAllocsDesiredTransitions(1002, m, evals)) 4148 4149 ws = memdb.NewWatchSet() 4150 out, err = state.AllocByID(ws, alloc.ID) 4151 require.Nil(err) 4152 require.NotNil(out.DesiredTransition.Migrate) 4153 require.False(*out.DesiredTransition.Migrate) 4154 require.EqualValues(1000, out.CreateIndex) 4155 require.EqualValues(1002, out.ModifyIndex) 4156 4157 index, err = state.Index("allocs") 4158 require.Nil(err) 4159 require.EqualValues(1002, index) 4160 4161 // Try with a bogus alloc id 4162 m = map[string]*structs.DesiredTransition{uuid.Generate(): t2} 4163 require.Nil(state.UpdateAllocsDesiredTransitions(1003, m, evals)) 4164 } 4165 4166 func TestStateStore_JobSummary(t *testing.T) { 4167 state := testStateStore(t) 4168 4169 // Add a job 4170 job := mock.Job() 4171 state.UpsertJob(900, job) 4172 4173 // Get the job back 4174 ws := memdb.NewWatchSet() 4175 outJob, _ := state.JobByID(ws, job.Namespace, job.ID) 4176 if outJob.CreateIndex != 900 { 4177 t.Fatalf("bad create index: %v", outJob.CreateIndex) 4178 } 4179 summary, _ := state.JobSummaryByID(ws, job.Namespace, job.ID) 4180 if summary.CreateIndex != 900 { 4181 t.Fatalf("bad create index: %v", summary.CreateIndex) 4182 } 4183 4184 // Upsert an allocation 4185 alloc := mock.Alloc() 4186 alloc.JobID = job.ID 4187 alloc.Job = job 4188 state.UpsertAllocs(910, []*structs.Allocation{alloc}) 4189 4190 // Update the alloc from client 4191 alloc1 := alloc.Copy() 4192 alloc1.ClientStatus = structs.AllocClientStatusPending 4193 alloc1.DesiredStatus = "" 4194 state.UpdateAllocsFromClient(920, []*structs.Allocation{alloc}) 4195 4196 alloc3 := alloc.Copy() 4197 alloc3.ClientStatus = structs.AllocClientStatusRunning 4198 alloc3.DesiredStatus = "" 4199 state.UpdateAllocsFromClient(930, []*structs.Allocation{alloc3}) 4200 4201 // Upsert the alloc 4202 alloc4 := alloc.Copy() 4203 alloc4.ClientStatus = structs.AllocClientStatusPending 4204 alloc4.DesiredStatus = structs.AllocDesiredStatusRun 4205 state.UpsertAllocs(950, []*structs.Allocation{alloc4}) 4206 4207 // Again upsert the alloc 4208 alloc5 := alloc.Copy() 4209 alloc5.ClientStatus = structs.AllocClientStatusPending 4210 alloc5.DesiredStatus = structs.AllocDesiredStatusRun 4211 state.UpsertAllocs(970, []*structs.Allocation{alloc5}) 4212 4213 if !watchFired(ws) { 4214 t.Fatalf("bad") 4215 } 4216 4217 expectedSummary := structs.JobSummary{ 4218 JobID: job.ID, 4219 Namespace: job.Namespace, 4220 Summary: map[string]structs.TaskGroupSummary{ 4221 "web": { 4222 Running: 1, 4223 }, 4224 }, 4225 Children: new(structs.JobChildrenSummary), 4226 CreateIndex: 900, 4227 ModifyIndex: 930, 4228 } 4229 4230 summary, _ = state.JobSummaryByID(ws, job.Namespace, job.ID) 4231 if !reflect.DeepEqual(&expectedSummary, summary) { 4232 t.Fatalf("expected: %#v, actual: %v", expectedSummary, summary) 4233 } 4234 4235 // De-register the job. 4236 state.DeleteJob(980, job.Namespace, job.ID) 4237 4238 // Shouldn't have any effect on the summary 4239 alloc6 := alloc.Copy() 4240 alloc6.ClientStatus = structs.AllocClientStatusRunning 4241 alloc6.DesiredStatus = "" 4242 state.UpdateAllocsFromClient(990, []*structs.Allocation{alloc6}) 4243 4244 // We shouldn't have any summary at this point 4245 summary, _ = state.JobSummaryByID(ws, job.Namespace, job.ID) 4246 if summary != nil { 4247 t.Fatalf("expected nil, actual: %#v", summary) 4248 } 4249 4250 // Re-register the same job 4251 job1 := mock.Job() 4252 job1.ID = job.ID 4253 state.UpsertJob(1000, job1) 4254 outJob2, _ := state.JobByID(ws, job1.Namespace, job1.ID) 4255 if outJob2.CreateIndex != 1000 { 4256 t.Fatalf("bad create index: %v", outJob2.CreateIndex) 4257 } 4258 summary, _ = state.JobSummaryByID(ws, job1.Namespace, job1.ID) 4259 if summary.CreateIndex != 1000 { 4260 t.Fatalf("bad create index: %v", summary.CreateIndex) 4261 } 4262 4263 // Upsert an allocation 4264 alloc7 := alloc.Copy() 4265 alloc7.JobID = outJob.ID 4266 alloc7.Job = outJob 4267 alloc7.ClientStatus = structs.AllocClientStatusComplete 4268 alloc7.DesiredStatus = structs.AllocDesiredStatusRun 4269 state.UpdateAllocsFromClient(1020, []*structs.Allocation{alloc7}) 4270 4271 expectedSummary = structs.JobSummary{ 4272 JobID: job.ID, 4273 Namespace: job.Namespace, 4274 Summary: map[string]structs.TaskGroupSummary{ 4275 "web": {}, 4276 }, 4277 Children: new(structs.JobChildrenSummary), 4278 CreateIndex: 1000, 4279 ModifyIndex: 1000, 4280 } 4281 4282 summary, _ = state.JobSummaryByID(ws, job1.Namespace, job1.ID) 4283 if !reflect.DeepEqual(&expectedSummary, summary) { 4284 t.Fatalf("expected: %#v, actual: %#v", expectedSummary, summary) 4285 } 4286 } 4287 4288 func TestStateStore_ReconcileJobSummary(t *testing.T) { 4289 state := testStateStore(t) 4290 4291 // Create an alloc 4292 alloc := mock.Alloc() 4293 4294 // Add another task group to the job 4295 tg2 := alloc.Job.TaskGroups[0].Copy() 4296 tg2.Name = "db" 4297 alloc.Job.TaskGroups = append(alloc.Job.TaskGroups, tg2) 4298 state.UpsertJob(100, alloc.Job) 4299 4300 // Create one more alloc for the db task group 4301 alloc2 := mock.Alloc() 4302 alloc2.TaskGroup = "db" 4303 alloc2.JobID = alloc.JobID 4304 alloc2.Job = alloc.Job 4305 4306 // Upserts the alloc 4307 state.UpsertAllocs(110, []*structs.Allocation{alloc, alloc2}) 4308 4309 // Change the state of the first alloc to running 4310 alloc3 := alloc.Copy() 4311 alloc3.ClientStatus = structs.AllocClientStatusRunning 4312 state.UpdateAllocsFromClient(120, []*structs.Allocation{alloc3}) 4313 4314 //Add some more allocs to the second tg 4315 alloc4 := mock.Alloc() 4316 alloc4.JobID = alloc.JobID 4317 alloc4.Job = alloc.Job 4318 alloc4.TaskGroup = "db" 4319 alloc5 := alloc4.Copy() 4320 alloc5.ClientStatus = structs.AllocClientStatusRunning 4321 4322 alloc6 := mock.Alloc() 4323 alloc6.JobID = alloc.JobID 4324 alloc6.Job = alloc.Job 4325 alloc6.TaskGroup = "db" 4326 alloc7 := alloc6.Copy() 4327 alloc7.ClientStatus = structs.AllocClientStatusComplete 4328 4329 alloc8 := mock.Alloc() 4330 alloc8.JobID = alloc.JobID 4331 alloc8.Job = alloc.Job 4332 alloc8.TaskGroup = "db" 4333 alloc9 := alloc8.Copy() 4334 alloc9.ClientStatus = structs.AllocClientStatusFailed 4335 4336 alloc10 := mock.Alloc() 4337 alloc10.JobID = alloc.JobID 4338 alloc10.Job = alloc.Job 4339 alloc10.TaskGroup = "db" 4340 alloc11 := alloc10.Copy() 4341 alloc11.ClientStatus = structs.AllocClientStatusLost 4342 4343 state.UpsertAllocs(130, []*structs.Allocation{alloc4, alloc6, alloc8, alloc10}) 4344 4345 state.UpdateAllocsFromClient(150, []*structs.Allocation{alloc5, alloc7, alloc9, alloc11}) 4346 4347 // DeleteJobSummary is a helper method and doesn't modify the indexes table 4348 state.DeleteJobSummary(130, alloc.Namespace, alloc.Job.ID) 4349 4350 state.ReconcileJobSummaries(120) 4351 4352 ws := memdb.NewWatchSet() 4353 summary, _ := state.JobSummaryByID(ws, alloc.Namespace, alloc.Job.ID) 4354 expectedSummary := structs.JobSummary{ 4355 JobID: alloc.Job.ID, 4356 Namespace: alloc.Namespace, 4357 Summary: map[string]structs.TaskGroupSummary{ 4358 "web": { 4359 Running: 1, 4360 }, 4361 "db": { 4362 Starting: 1, 4363 Running: 1, 4364 Failed: 1, 4365 Complete: 1, 4366 Lost: 1, 4367 }, 4368 }, 4369 CreateIndex: 100, 4370 ModifyIndex: 120, 4371 } 4372 if !reflect.DeepEqual(&expectedSummary, summary) { 4373 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 4374 } 4375 } 4376 4377 func TestStateStore_UpdateAlloc_JobNotPresent(t *testing.T) { 4378 state := testStateStore(t) 4379 4380 alloc := mock.Alloc() 4381 state.UpsertJob(100, alloc.Job) 4382 state.UpsertAllocs(200, []*structs.Allocation{alloc}) 4383 4384 // Delete the job 4385 state.DeleteJob(300, alloc.Namespace, alloc.Job.ID) 4386 4387 // Update the alloc 4388 alloc1 := alloc.Copy() 4389 alloc1.ClientStatus = structs.AllocClientStatusRunning 4390 4391 // Updating allocation should not throw any error 4392 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 4393 t.Fatalf("expect err: %v", err) 4394 } 4395 4396 // Re-Register the job 4397 state.UpsertJob(500, alloc.Job) 4398 4399 // Update the alloc again 4400 alloc2 := alloc.Copy() 4401 alloc2.ClientStatus = structs.AllocClientStatusComplete 4402 if err := state.UpdateAllocsFromClient(400, []*structs.Allocation{alloc1}); err != nil { 4403 t.Fatalf("expect err: %v", err) 4404 } 4405 4406 // Job Summary of the newly registered job shouldn't account for the 4407 // allocation update for the older job 4408 expectedSummary := structs.JobSummary{ 4409 JobID: alloc1.JobID, 4410 Namespace: alloc1.Namespace, 4411 Summary: map[string]structs.TaskGroupSummary{ 4412 "web": {}, 4413 }, 4414 Children: new(structs.JobChildrenSummary), 4415 CreateIndex: 500, 4416 ModifyIndex: 500, 4417 } 4418 4419 ws := memdb.NewWatchSet() 4420 summary, _ := state.JobSummaryByID(ws, alloc.Namespace, alloc.Job.ID) 4421 if !reflect.DeepEqual(&expectedSummary, summary) { 4422 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 4423 } 4424 } 4425 4426 func TestStateStore_EvictAlloc_Alloc(t *testing.T) { 4427 state := testStateStore(t) 4428 alloc := mock.Alloc() 4429 4430 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 4431 err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}) 4432 if err != nil { 4433 t.Fatalf("err: %v", err) 4434 } 4435 4436 alloc2 := new(structs.Allocation) 4437 *alloc2 = *alloc 4438 alloc2.DesiredStatus = structs.AllocDesiredStatusEvict 4439 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc2}) 4440 if err != nil { 4441 t.Fatalf("err: %v", err) 4442 } 4443 4444 ws := memdb.NewWatchSet() 4445 out, err := state.AllocByID(ws, alloc.ID) 4446 if err != nil { 4447 t.Fatalf("err: %v", err) 4448 } 4449 4450 if out.DesiredStatus != structs.AllocDesiredStatusEvict { 4451 t.Fatalf("bad: %#v %#v", alloc, out) 4452 } 4453 4454 index, err := state.Index("allocs") 4455 if err != nil { 4456 t.Fatalf("err: %v", err) 4457 } 4458 if index != 1001 { 4459 t.Fatalf("bad: %d", index) 4460 } 4461 } 4462 4463 func TestStateStore_AllocsByNode(t *testing.T) { 4464 state := testStateStore(t) 4465 var allocs []*structs.Allocation 4466 4467 for i := 0; i < 10; i++ { 4468 alloc := mock.Alloc() 4469 alloc.NodeID = "foo" 4470 allocs = append(allocs, alloc) 4471 } 4472 4473 for idx, alloc := range allocs { 4474 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 4475 } 4476 4477 err := state.UpsertAllocs(1000, allocs) 4478 if err != nil { 4479 t.Fatalf("err: %v", err) 4480 } 4481 4482 ws := memdb.NewWatchSet() 4483 out, err := state.AllocsByNode(ws, "foo") 4484 if err != nil { 4485 t.Fatalf("err: %v", err) 4486 } 4487 4488 sort.Sort(AllocIDSort(allocs)) 4489 sort.Sort(AllocIDSort(out)) 4490 4491 if !reflect.DeepEqual(allocs, out) { 4492 t.Fatalf("bad: %#v %#v", allocs, out) 4493 } 4494 4495 if watchFired(ws) { 4496 t.Fatalf("bad") 4497 } 4498 } 4499 4500 func TestStateStore_AllocsByNodeTerminal(t *testing.T) { 4501 state := testStateStore(t) 4502 var allocs, term, nonterm []*structs.Allocation 4503 4504 for i := 0; i < 10; i++ { 4505 alloc := mock.Alloc() 4506 alloc.NodeID = "foo" 4507 if i%2 == 0 { 4508 alloc.DesiredStatus = structs.AllocDesiredStatusStop 4509 term = append(term, alloc) 4510 } else { 4511 nonterm = append(nonterm, alloc) 4512 } 4513 allocs = append(allocs, alloc) 4514 } 4515 4516 for idx, alloc := range allocs { 4517 state.UpsertJobSummary(uint64(900+idx), mock.JobSummary(alloc.JobID)) 4518 } 4519 4520 err := state.UpsertAllocs(1000, allocs) 4521 if err != nil { 4522 t.Fatalf("err: %v", err) 4523 } 4524 4525 // Verify the terminal allocs 4526 ws := memdb.NewWatchSet() 4527 out, err := state.AllocsByNodeTerminal(ws, "foo", true) 4528 if err != nil { 4529 t.Fatalf("err: %v", err) 4530 } 4531 4532 sort.Sort(AllocIDSort(term)) 4533 sort.Sort(AllocIDSort(out)) 4534 4535 if !reflect.DeepEqual(term, out) { 4536 t.Fatalf("bad: %#v %#v", term, out) 4537 } 4538 4539 // Verify the non-terminal allocs 4540 out, err = state.AllocsByNodeTerminal(ws, "foo", false) 4541 if err != nil { 4542 t.Fatalf("err: %v", err) 4543 } 4544 4545 sort.Sort(AllocIDSort(nonterm)) 4546 sort.Sort(AllocIDSort(out)) 4547 4548 if !reflect.DeepEqual(nonterm, out) { 4549 t.Fatalf("bad: %#v %#v", nonterm, out) 4550 } 4551 4552 if watchFired(ws) { 4553 t.Fatalf("bad") 4554 } 4555 } 4556 4557 func TestStateStore_AllocsByJob(t *testing.T) { 4558 state := testStateStore(t) 4559 var allocs []*structs.Allocation 4560 4561 for i := 0; i < 10; i++ { 4562 alloc := mock.Alloc() 4563 alloc.JobID = "foo" 4564 allocs = append(allocs, alloc) 4565 } 4566 4567 for i, alloc := range allocs { 4568 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 4569 } 4570 4571 err := state.UpsertAllocs(1000, allocs) 4572 if err != nil { 4573 t.Fatalf("err: %v", err) 4574 } 4575 4576 ws := memdb.NewWatchSet() 4577 out, err := state.AllocsByJob(ws, mock.Alloc().Namespace, "foo", false) 4578 if err != nil { 4579 t.Fatalf("err: %v", err) 4580 } 4581 4582 sort.Sort(AllocIDSort(allocs)) 4583 sort.Sort(AllocIDSort(out)) 4584 4585 if !reflect.DeepEqual(allocs, out) { 4586 t.Fatalf("bad: %#v %#v", allocs, out) 4587 } 4588 4589 if watchFired(ws) { 4590 t.Fatalf("bad") 4591 } 4592 } 4593 4594 func TestStateStore_AllocsForRegisteredJob(t *testing.T) { 4595 state := testStateStore(t) 4596 var allocs []*structs.Allocation 4597 var allocs1 []*structs.Allocation 4598 4599 job := mock.Job() 4600 job.ID = "foo" 4601 state.UpsertJob(100, job) 4602 for i := 0; i < 3; i++ { 4603 alloc := mock.Alloc() 4604 alloc.Job = job 4605 alloc.JobID = job.ID 4606 allocs = append(allocs, alloc) 4607 } 4608 if err := state.UpsertAllocs(200, allocs); err != nil { 4609 t.Fatalf("err: %v", err) 4610 } 4611 4612 if err := state.DeleteJob(250, job.Namespace, job.ID); err != nil { 4613 t.Fatalf("err: %v", err) 4614 } 4615 4616 job1 := mock.Job() 4617 job1.ID = "foo" 4618 job1.CreateIndex = 50 4619 state.UpsertJob(300, job1) 4620 for i := 0; i < 4; i++ { 4621 alloc := mock.Alloc() 4622 alloc.Job = job1 4623 alloc.JobID = job1.ID 4624 allocs1 = append(allocs1, alloc) 4625 } 4626 4627 if err := state.UpsertAllocs(1000, allocs1); err != nil { 4628 t.Fatalf("err: %v", err) 4629 } 4630 4631 ws := memdb.NewWatchSet() 4632 out, err := state.AllocsByJob(ws, job1.Namespace, job1.ID, true) 4633 if err != nil { 4634 t.Fatalf("err: %v", err) 4635 } 4636 4637 expected := len(allocs) + len(allocs1) 4638 if len(out) != expected { 4639 t.Fatalf("expected: %v, actual: %v", expected, len(out)) 4640 } 4641 4642 out1, err := state.AllocsByJob(ws, job1.Namespace, job1.ID, false) 4643 if err != nil { 4644 t.Fatalf("bad: %v", err) 4645 } 4646 4647 expected = len(allocs1) 4648 if len(out1) != expected { 4649 t.Fatalf("expected: %v, actual: %v", expected, len(out1)) 4650 } 4651 4652 if watchFired(ws) { 4653 t.Fatalf("bad") 4654 } 4655 } 4656 4657 func TestStateStore_AllocsByIDPrefix(t *testing.T) { 4658 state := testStateStore(t) 4659 var allocs []*structs.Allocation 4660 4661 ids := []string{ 4662 "aaaaaaaa-7bfb-395d-eb95-0685af2176b2", 4663 "aaaaaaab-7bfb-395d-eb95-0685af2176b2", 4664 "aaaaaabb-7bfb-395d-eb95-0685af2176b2", 4665 "aaaaabbb-7bfb-395d-eb95-0685af2176b2", 4666 "aaaabbbb-7bfb-395d-eb95-0685af2176b2", 4667 "aaabbbbb-7bfb-395d-eb95-0685af2176b2", 4668 "aabbbbbb-7bfb-395d-eb95-0685af2176b2", 4669 "abbbbbbb-7bfb-395d-eb95-0685af2176b2", 4670 "bbbbbbbb-7bfb-395d-eb95-0685af2176b2", 4671 } 4672 for i := 0; i < 9; i++ { 4673 alloc := mock.Alloc() 4674 alloc.ID = ids[i] 4675 allocs = append(allocs, alloc) 4676 } 4677 4678 for i, alloc := range allocs { 4679 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 4680 } 4681 4682 err := state.UpsertAllocs(1000, allocs) 4683 if err != nil { 4684 t.Fatalf("err: %v", err) 4685 } 4686 4687 ws := memdb.NewWatchSet() 4688 iter, err := state.AllocsByIDPrefix(ws, structs.DefaultNamespace, "aaaa") 4689 if err != nil { 4690 t.Fatalf("err: %v", err) 4691 } 4692 4693 gatherAllocs := func(iter memdb.ResultIterator) []*structs.Allocation { 4694 var allocs []*structs.Allocation 4695 for { 4696 raw := iter.Next() 4697 if raw == nil { 4698 break 4699 } 4700 allocs = append(allocs, raw.(*structs.Allocation)) 4701 } 4702 return allocs 4703 } 4704 4705 out := gatherAllocs(iter) 4706 if len(out) != 5 { 4707 t.Fatalf("bad: expected five allocations, got: %#v", out) 4708 } 4709 4710 sort.Sort(AllocIDSort(allocs)) 4711 4712 for index, alloc := range out { 4713 if ids[index] != alloc.ID { 4714 t.Fatalf("bad: got unexpected id: %s", alloc.ID) 4715 } 4716 } 4717 4718 iter, err = state.AllocsByIDPrefix(ws, structs.DefaultNamespace, "b-a7bfb") 4719 if err != nil { 4720 t.Fatalf("err: %v", err) 4721 } 4722 4723 out = gatherAllocs(iter) 4724 if len(out) != 0 { 4725 t.Fatalf("bad: unexpected zero allocations, got: %#v", out) 4726 } 4727 4728 if watchFired(ws) { 4729 t.Fatalf("bad") 4730 } 4731 } 4732 4733 func TestStateStore_Allocs(t *testing.T) { 4734 state := testStateStore(t) 4735 var allocs []*structs.Allocation 4736 4737 for i := 0; i < 10; i++ { 4738 alloc := mock.Alloc() 4739 allocs = append(allocs, alloc) 4740 } 4741 for i, alloc := range allocs { 4742 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 4743 } 4744 4745 err := state.UpsertAllocs(1000, allocs) 4746 if err != nil { 4747 t.Fatalf("err: %v", err) 4748 } 4749 4750 ws := memdb.NewWatchSet() 4751 iter, err := state.Allocs(ws) 4752 if err != nil { 4753 t.Fatalf("err: %v", err) 4754 } 4755 4756 var out []*structs.Allocation 4757 for { 4758 raw := iter.Next() 4759 if raw == nil { 4760 break 4761 } 4762 out = append(out, raw.(*structs.Allocation)) 4763 } 4764 4765 sort.Sort(AllocIDSort(allocs)) 4766 sort.Sort(AllocIDSort(out)) 4767 4768 if !reflect.DeepEqual(allocs, out) { 4769 t.Fatalf("bad: %#v %#v", allocs, out) 4770 } 4771 4772 if watchFired(ws) { 4773 t.Fatalf("bad") 4774 } 4775 } 4776 4777 func TestStateStore_Allocs_PrevAlloc(t *testing.T) { 4778 state := testStateStore(t) 4779 var allocs []*structs.Allocation 4780 4781 require := require.New(t) 4782 for i := 0; i < 5; i++ { 4783 alloc := mock.Alloc() 4784 allocs = append(allocs, alloc) 4785 } 4786 for i, alloc := range allocs { 4787 state.UpsertJobSummary(uint64(900+i), mock.JobSummary(alloc.JobID)) 4788 } 4789 // Set some previous alloc ids 4790 allocs[1].PreviousAllocation = allocs[0].ID 4791 allocs[2].PreviousAllocation = allocs[1].ID 4792 4793 err := state.UpsertAllocs(1000, allocs) 4794 require.Nil(err) 4795 4796 ws := memdb.NewWatchSet() 4797 iter, err := state.Allocs(ws) 4798 require.Nil(err) 4799 4800 var out []*structs.Allocation 4801 for { 4802 raw := iter.Next() 4803 if raw == nil { 4804 break 4805 } 4806 out = append(out, raw.(*structs.Allocation)) 4807 } 4808 4809 // Set expected NextAllocation fields 4810 allocs[0].NextAllocation = allocs[1].ID 4811 allocs[1].NextAllocation = allocs[2].ID 4812 4813 sort.Sort(AllocIDSort(allocs)) 4814 sort.Sort(AllocIDSort(out)) 4815 4816 require.Equal(allocs, out) 4817 require.False(watchFired(ws)) 4818 4819 // Insert another alloc, verify index of previous alloc also got updated 4820 alloc := mock.Alloc() 4821 alloc.PreviousAllocation = allocs[0].ID 4822 err = state.UpsertAllocs(1001, []*structs.Allocation{alloc}) 4823 require.Nil(err) 4824 alloc0, err := state.AllocByID(nil, allocs[0].ID) 4825 require.Nil(err) 4826 require.Equal(alloc0.ModifyIndex, uint64(1001)) 4827 } 4828 4829 func TestStateStore_RestoreAlloc(t *testing.T) { 4830 state := testStateStore(t) 4831 alloc := mock.Alloc() 4832 4833 restore, err := state.Restore() 4834 if err != nil { 4835 t.Fatalf("err: %v", err) 4836 } 4837 4838 err = restore.AllocRestore(alloc) 4839 if err != nil { 4840 t.Fatalf("err: %v", err) 4841 } 4842 4843 restore.Commit() 4844 4845 ws := memdb.NewWatchSet() 4846 out, err := state.AllocByID(ws, alloc.ID) 4847 if err != nil { 4848 t.Fatalf("err: %v", err) 4849 } 4850 4851 if !reflect.DeepEqual(out, alloc) { 4852 t.Fatalf("Bad: %#v %#v", out, alloc) 4853 } 4854 4855 if watchFired(ws) { 4856 t.Fatalf("bad") 4857 } 4858 } 4859 4860 func TestStateStore_RestoreAlloc_NoEphemeralDisk(t *testing.T) { 4861 state := testStateStore(t) 4862 alloc := mock.Alloc() 4863 alloc.Job.TaskGroups[0].EphemeralDisk = nil 4864 alloc.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 120 4865 4866 restore, err := state.Restore() 4867 if err != nil { 4868 t.Fatalf("err: %v", err) 4869 } 4870 4871 err = restore.AllocRestore(alloc) 4872 if err != nil { 4873 t.Fatalf("err: %v", err) 4874 } 4875 4876 restore.Commit() 4877 4878 ws := memdb.NewWatchSet() 4879 out, err := state.AllocByID(ws, alloc.ID) 4880 if err != nil { 4881 t.Fatalf("err: %v", err) 4882 } 4883 4884 expected := alloc.Copy() 4885 expected.Job.TaskGroups[0].EphemeralDisk = &structs.EphemeralDisk{SizeMB: 120} 4886 expected.Job.TaskGroups[0].Tasks[0].Resources.DiskMB = 0 4887 4888 if !reflect.DeepEqual(out, expected) { 4889 t.Fatalf("Bad: %#v %#v", out, expected) 4890 } 4891 4892 if watchFired(ws) { 4893 t.Fatalf("bad") 4894 } 4895 } 4896 4897 func TestStateStore_SetJobStatus_ForceStatus(t *testing.T) { 4898 state := testStateStore(t) 4899 txn := state.db.Txn(true) 4900 4901 // Create and insert a mock job. 4902 job := mock.Job() 4903 job.Status = "" 4904 job.ModifyIndex = 0 4905 if err := txn.Insert("jobs", job); err != nil { 4906 t.Fatalf("job insert failed: %v", err) 4907 } 4908 4909 exp := "foobar" 4910 index := uint64(1000) 4911 if err := state.setJobStatus(index, txn, job, false, exp); err != nil { 4912 t.Fatalf("setJobStatus() failed: %v", err) 4913 } 4914 4915 i, err := txn.First("jobs", "id", job.Namespace, job.ID) 4916 if err != nil { 4917 t.Fatalf("job lookup failed: %v", err) 4918 } 4919 updated := i.(*structs.Job) 4920 4921 if updated.Status != exp { 4922 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, exp) 4923 } 4924 4925 if updated.ModifyIndex != index { 4926 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 4927 } 4928 } 4929 4930 func TestStateStore_SetJobStatus_NoOp(t *testing.T) { 4931 state := testStateStore(t) 4932 txn := state.db.Txn(true) 4933 4934 // Create and insert a mock job that should be pending. 4935 job := mock.Job() 4936 job.Status = structs.JobStatusPending 4937 job.ModifyIndex = 10 4938 if err := txn.Insert("jobs", job); err != nil { 4939 t.Fatalf("job insert failed: %v", err) 4940 } 4941 4942 index := uint64(1000) 4943 if err := state.setJobStatus(index, txn, job, false, ""); err != nil { 4944 t.Fatalf("setJobStatus() failed: %v", err) 4945 } 4946 4947 i, err := txn.First("jobs", "id", job.Namespace, job.ID) 4948 if err != nil { 4949 t.Fatalf("job lookup failed: %v", err) 4950 } 4951 updated := i.(*structs.Job) 4952 4953 if updated.ModifyIndex == index { 4954 t.Fatalf("setJobStatus() should have been a no-op") 4955 } 4956 } 4957 4958 func TestStateStore_SetJobStatus(t *testing.T) { 4959 state := testStateStore(t) 4960 txn := state.db.Txn(true) 4961 4962 // Create and insert a mock job that should be pending but has an incorrect 4963 // status. 4964 job := mock.Job() 4965 job.Status = "foobar" 4966 job.ModifyIndex = 10 4967 if err := txn.Insert("jobs", job); err != nil { 4968 t.Fatalf("job insert failed: %v", err) 4969 } 4970 4971 index := uint64(1000) 4972 if err := state.setJobStatus(index, txn, job, false, ""); err != nil { 4973 t.Fatalf("setJobStatus() failed: %v", err) 4974 } 4975 4976 i, err := txn.First("jobs", "id", job.Namespace, job.ID) 4977 if err != nil { 4978 t.Fatalf("job lookup failed: %v", err) 4979 } 4980 updated := i.(*structs.Job) 4981 4982 if updated.Status != structs.JobStatusPending { 4983 t.Fatalf("setJobStatus() set %v; expected %v", updated.Status, structs.JobStatusPending) 4984 } 4985 4986 if updated.ModifyIndex != index { 4987 t.Fatalf("setJobStatus() set %d; expected %d", updated.ModifyIndex, index) 4988 } 4989 } 4990 4991 func TestStateStore_GetJobStatus_NoEvalsOrAllocs(t *testing.T) { 4992 job := mock.Job() 4993 state := testStateStore(t) 4994 txn := state.db.Txn(false) 4995 status, err := state.getJobStatus(txn, job, false) 4996 if err != nil { 4997 t.Fatalf("getJobStatus() failed: %v", err) 4998 } 4999 5000 if status != structs.JobStatusPending { 5001 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 5002 } 5003 } 5004 5005 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_Periodic(t *testing.T) { 5006 job := mock.PeriodicJob() 5007 state := testStateStore(t) 5008 txn := state.db.Txn(false) 5009 status, err := state.getJobStatus(txn, job, false) 5010 if err != nil { 5011 t.Fatalf("getJobStatus() failed: %v", err) 5012 } 5013 5014 if status != structs.JobStatusRunning { 5015 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 5016 } 5017 } 5018 5019 func TestStateStore_GetJobStatus_NoEvalsOrAllocs_EvalDelete(t *testing.T) { 5020 job := mock.Job() 5021 state := testStateStore(t) 5022 txn := state.db.Txn(false) 5023 status, err := state.getJobStatus(txn, job, true) 5024 if err != nil { 5025 t.Fatalf("getJobStatus() failed: %v", err) 5026 } 5027 5028 if status != structs.JobStatusDead { 5029 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 5030 } 5031 } 5032 5033 func TestStateStore_GetJobStatus_DeadEvalsAndAllocs(t *testing.T) { 5034 state := testStateStore(t) 5035 job := mock.Job() 5036 5037 // Create a mock alloc that is dead. 5038 alloc := mock.Alloc() 5039 alloc.JobID = job.ID 5040 alloc.DesiredStatus = structs.AllocDesiredStatusStop 5041 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 5042 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 5043 t.Fatalf("err: %v", err) 5044 } 5045 5046 // Create a mock eval that is complete 5047 eval := mock.Eval() 5048 eval.JobID = job.ID 5049 eval.Status = structs.EvalStatusComplete 5050 if err := state.UpsertEvals(1001, []*structs.Evaluation{eval}); err != nil { 5051 t.Fatalf("err: %v", err) 5052 } 5053 5054 txn := state.db.Txn(false) 5055 status, err := state.getJobStatus(txn, job, false) 5056 if err != nil { 5057 t.Fatalf("getJobStatus() failed: %v", err) 5058 } 5059 5060 if status != structs.JobStatusDead { 5061 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 5062 } 5063 } 5064 5065 func TestStateStore_GetJobStatus_RunningAlloc(t *testing.T) { 5066 state := testStateStore(t) 5067 job := mock.Job() 5068 5069 // Create a mock alloc that is running. 5070 alloc := mock.Alloc() 5071 alloc.JobID = job.ID 5072 alloc.DesiredStatus = structs.AllocDesiredStatusRun 5073 state.UpsertJobSummary(999, mock.JobSummary(alloc.JobID)) 5074 if err := state.UpsertAllocs(1000, []*structs.Allocation{alloc}); err != nil { 5075 t.Fatalf("err: %v", err) 5076 } 5077 5078 txn := state.db.Txn(false) 5079 status, err := state.getJobStatus(txn, job, true) 5080 if err != nil { 5081 t.Fatalf("getJobStatus() failed: %v", err) 5082 } 5083 5084 if status != structs.JobStatusRunning { 5085 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 5086 } 5087 } 5088 5089 func TestStateStore_GetJobStatus_PeriodicJob(t *testing.T) { 5090 state := testStateStore(t) 5091 job := mock.PeriodicJob() 5092 5093 txn := state.db.Txn(false) 5094 status, err := state.getJobStatus(txn, job, false) 5095 if err != nil { 5096 t.Fatalf("getJobStatus() failed: %v", err) 5097 } 5098 5099 if status != structs.JobStatusRunning { 5100 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 5101 } 5102 5103 // Mark it as stopped 5104 job.Stop = true 5105 status, err = state.getJobStatus(txn, job, false) 5106 if err != nil { 5107 t.Fatalf("getJobStatus() failed: %v", err) 5108 } 5109 5110 if status != structs.JobStatusDead { 5111 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 5112 } 5113 } 5114 5115 func TestStateStore_GetJobStatus_ParameterizedJob(t *testing.T) { 5116 state := testStateStore(t) 5117 job := mock.Job() 5118 job.ParameterizedJob = &structs.ParameterizedJobConfig{} 5119 5120 txn := state.db.Txn(false) 5121 status, err := state.getJobStatus(txn, job, false) 5122 if err != nil { 5123 t.Fatalf("getJobStatus() failed: %v", err) 5124 } 5125 5126 if status != structs.JobStatusRunning { 5127 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusRunning) 5128 } 5129 5130 // Mark it as stopped 5131 job.Stop = true 5132 status, err = state.getJobStatus(txn, job, false) 5133 if err != nil { 5134 t.Fatalf("getJobStatus() failed: %v", err) 5135 } 5136 5137 if status != structs.JobStatusDead { 5138 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusDead) 5139 } 5140 } 5141 5142 func TestStateStore_SetJobStatus_PendingEval(t *testing.T) { 5143 state := testStateStore(t) 5144 job := mock.Job() 5145 5146 // Create a mock eval that is pending. 5147 eval := mock.Eval() 5148 eval.JobID = job.ID 5149 eval.Status = structs.EvalStatusPending 5150 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 5151 t.Fatalf("err: %v", err) 5152 } 5153 5154 txn := state.db.Txn(false) 5155 status, err := state.getJobStatus(txn, job, true) 5156 if err != nil { 5157 t.Fatalf("getJobStatus() failed: %v", err) 5158 } 5159 5160 if status != structs.JobStatusPending { 5161 t.Fatalf("getJobStatus() returned %v; expected %v", status, structs.JobStatusPending) 5162 } 5163 } 5164 5165 // TestStateStore_SetJobStatus_SystemJob asserts that system jobs are still 5166 // considered running until explicitly stopped. 5167 func TestStateStore_SetJobStatus_SystemJob(t *testing.T) { 5168 state := testStateStore(t) 5169 job := mock.SystemJob() 5170 5171 // Create a mock eval that is pending. 5172 eval := mock.Eval() 5173 eval.JobID = job.ID 5174 eval.Type = job.Type 5175 eval.Status = structs.EvalStatusComplete 5176 if err := state.UpsertEvals(1000, []*structs.Evaluation{eval}); err != nil { 5177 t.Fatalf("err: %v", err) 5178 } 5179 5180 txn := state.db.Txn(false) 5181 status, err := state.getJobStatus(txn, job, true) 5182 if err != nil { 5183 t.Fatalf("getJobStatus() failed: %v", err) 5184 } 5185 5186 if expected := structs.JobStatusRunning; status != expected { 5187 t.Fatalf("getJobStatus() returned %v; expected %v", status, expected) 5188 } 5189 5190 // Stop the job 5191 job.Stop = true 5192 status, err = state.getJobStatus(txn, job, true) 5193 if err != nil { 5194 t.Fatalf("getJobStatus() failed: %v", err) 5195 } 5196 5197 if expected := structs.JobStatusDead; status != expected { 5198 t.Fatalf("getJobStatus() returned %v; expected %v", status, expected) 5199 } 5200 } 5201 5202 func TestStateJobSummary_UpdateJobCount(t *testing.T) { 5203 state := testStateStore(t) 5204 alloc := mock.Alloc() 5205 job := alloc.Job 5206 job.TaskGroups[0].Count = 3 5207 5208 // Create watchsets so we can test that upsert fires the watch 5209 ws := memdb.NewWatchSet() 5210 if _, err := state.JobSummaryByID(ws, job.Namespace, job.ID); err != nil { 5211 t.Fatalf("bad: %v", err) 5212 } 5213 5214 if err := state.UpsertJob(1000, job); err != nil { 5215 t.Fatalf("err: %v", err) 5216 } 5217 5218 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc}); err != nil { 5219 t.Fatalf("err: %v", err) 5220 } 5221 5222 if !watchFired(ws) { 5223 t.Fatalf("bad") 5224 } 5225 5226 ws = memdb.NewWatchSet() 5227 summary, _ := state.JobSummaryByID(ws, job.Namespace, job.ID) 5228 expectedSummary := structs.JobSummary{ 5229 JobID: job.ID, 5230 Namespace: job.Namespace, 5231 Summary: map[string]structs.TaskGroupSummary{ 5232 "web": { 5233 Starting: 1, 5234 }, 5235 }, 5236 Children: new(structs.JobChildrenSummary), 5237 CreateIndex: 1000, 5238 ModifyIndex: 1001, 5239 } 5240 if !reflect.DeepEqual(summary, &expectedSummary) { 5241 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 5242 } 5243 5244 // Create watchsets so we can test that upsert fires the watch 5245 ws2 := memdb.NewWatchSet() 5246 if _, err := state.JobSummaryByID(ws2, job.Namespace, job.ID); err != nil { 5247 t.Fatalf("bad: %v", err) 5248 } 5249 5250 alloc2 := mock.Alloc() 5251 alloc2.Job = job 5252 alloc2.JobID = job.ID 5253 5254 alloc3 := mock.Alloc() 5255 alloc3.Job = job 5256 alloc3.JobID = job.ID 5257 5258 if err := state.UpsertAllocs(1002, []*structs.Allocation{alloc2, alloc3}); err != nil { 5259 t.Fatalf("err: %v", err) 5260 } 5261 5262 if !watchFired(ws2) { 5263 t.Fatalf("bad") 5264 } 5265 5266 outA, _ := state.AllocByID(ws, alloc3.ID) 5267 5268 summary, _ = state.JobSummaryByID(ws, job.Namespace, job.ID) 5269 expectedSummary = structs.JobSummary{ 5270 JobID: job.ID, 5271 Namespace: job.Namespace, 5272 Summary: map[string]structs.TaskGroupSummary{ 5273 "web": { 5274 Starting: 3, 5275 }, 5276 }, 5277 Children: new(structs.JobChildrenSummary), 5278 CreateIndex: job.CreateIndex, 5279 ModifyIndex: outA.ModifyIndex, 5280 } 5281 if !reflect.DeepEqual(summary, &expectedSummary) { 5282 t.Fatalf("expected summary: %v, actual: %v", expectedSummary, summary) 5283 } 5284 5285 // Create watchsets so we can test that upsert fires the watch 5286 ws3 := memdb.NewWatchSet() 5287 if _, err := state.JobSummaryByID(ws3, job.Namespace, job.ID); err != nil { 5288 t.Fatalf("bad: %v", err) 5289 } 5290 5291 alloc4 := mock.Alloc() 5292 alloc4.ID = alloc2.ID 5293 alloc4.Job = alloc2.Job 5294 alloc4.JobID = alloc2.JobID 5295 alloc4.ClientStatus = structs.AllocClientStatusComplete 5296 5297 alloc5 := mock.Alloc() 5298 alloc5.ID = alloc3.ID 5299 alloc5.Job = alloc3.Job 5300 alloc5.JobID = alloc3.JobID 5301 alloc5.ClientStatus = structs.AllocClientStatusComplete 5302 5303 if err := state.UpdateAllocsFromClient(1004, []*structs.Allocation{alloc4, alloc5}); err != nil { 5304 t.Fatalf("err: %v", err) 5305 } 5306 5307 if !watchFired(ws2) { 5308 t.Fatalf("bad") 5309 } 5310 5311 outA, _ = state.AllocByID(ws, alloc5.ID) 5312 summary, _ = state.JobSummaryByID(ws, job.Namespace, job.ID) 5313 expectedSummary = structs.JobSummary{ 5314 JobID: job.ID, 5315 Namespace: job.Namespace, 5316 Summary: map[string]structs.TaskGroupSummary{ 5317 "web": { 5318 Complete: 2, 5319 Starting: 1, 5320 }, 5321 }, 5322 Children: new(structs.JobChildrenSummary), 5323 CreateIndex: job.CreateIndex, 5324 ModifyIndex: outA.ModifyIndex, 5325 } 5326 if !reflect.DeepEqual(summary, &expectedSummary) { 5327 t.Fatalf("expected: %v, actual: %v", expectedSummary, summary) 5328 } 5329 } 5330 5331 func TestJobSummary_UpdateClientStatus(t *testing.T) { 5332 state := testStateStore(t) 5333 alloc := mock.Alloc() 5334 job := alloc.Job 5335 job.TaskGroups[0].Count = 3 5336 5337 alloc2 := mock.Alloc() 5338 alloc2.Job = job 5339 alloc2.JobID = job.ID 5340 5341 alloc3 := mock.Alloc() 5342 alloc3.Job = job 5343 alloc3.JobID = job.ID 5344 5345 err := state.UpsertJob(1000, job) 5346 if err != nil { 5347 t.Fatalf("err: %v", err) 5348 } 5349 5350 if err := state.UpsertAllocs(1001, []*structs.Allocation{alloc, alloc2, alloc3}); err != nil { 5351 t.Fatalf("err: %v", err) 5352 } 5353 5354 ws := memdb.NewWatchSet() 5355 summary, _ := state.JobSummaryByID(ws, job.Namespace, job.ID) 5356 if summary.Summary["web"].Starting != 3 { 5357 t.Fatalf("bad job summary: %v", summary) 5358 } 5359 5360 alloc4 := mock.Alloc() 5361 alloc4.ID = alloc2.ID 5362 alloc4.Job = alloc2.Job 5363 alloc4.JobID = alloc2.JobID 5364 alloc4.ClientStatus = structs.AllocClientStatusComplete 5365 5366 alloc5 := mock.Alloc() 5367 alloc5.ID = alloc3.ID 5368 alloc5.Job = alloc3.Job 5369 alloc5.JobID = alloc3.JobID 5370 alloc5.ClientStatus = structs.AllocClientStatusFailed 5371 5372 alloc6 := mock.Alloc() 5373 alloc6.ID = alloc.ID 5374 alloc6.Job = alloc.Job 5375 alloc6.JobID = alloc.JobID 5376 alloc6.ClientStatus = structs.AllocClientStatusRunning 5377 5378 if err := state.UpdateAllocsFromClient(1002, []*structs.Allocation{alloc4, alloc5, alloc6}); err != nil { 5379 t.Fatalf("err: %v", err) 5380 } 5381 5382 if !watchFired(ws) { 5383 t.Fatalf("bad") 5384 } 5385 5386 summary, _ = state.JobSummaryByID(ws, job.Namespace, job.ID) 5387 if summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 5388 t.Fatalf("bad job summary: %v", summary) 5389 } 5390 5391 alloc7 := mock.Alloc() 5392 alloc7.Job = alloc.Job 5393 alloc7.JobID = alloc.JobID 5394 5395 if err := state.UpsertAllocs(1003, []*structs.Allocation{alloc7}); err != nil { 5396 t.Fatalf("err: %v", err) 5397 } 5398 summary, _ = state.JobSummaryByID(ws, job.Namespace, job.ID) 5399 if summary.Summary["web"].Starting != 1 || summary.Summary["web"].Running != 1 || summary.Summary["web"].Failed != 1 || summary.Summary["web"].Complete != 1 { 5400 t.Fatalf("bad job summary: %v", summary) 5401 } 5402 } 5403 5404 // Test that nonexistent deployment can't be updated 5405 func TestStateStore_UpsertDeploymentStatusUpdate_Nonexistent(t *testing.T) { 5406 state := testStateStore(t) 5407 5408 // Update the nonexistent deployment 5409 req := &structs.DeploymentStatusUpdateRequest{ 5410 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 5411 DeploymentID: uuid.Generate(), 5412 Status: structs.DeploymentStatusRunning, 5413 }, 5414 } 5415 err := state.UpdateDeploymentStatus(2, req) 5416 if err == nil || !strings.Contains(err.Error(), "does not exist") { 5417 t.Fatalf("expected error updating the status because the deployment doesn't exist") 5418 } 5419 } 5420 5421 // Test that terminal deployment can't be updated 5422 func TestStateStore_UpsertDeploymentStatusUpdate_Terminal(t *testing.T) { 5423 state := testStateStore(t) 5424 5425 // Insert a terminal deployment 5426 d := mock.Deployment() 5427 d.Status = structs.DeploymentStatusFailed 5428 5429 if err := state.UpsertDeployment(1, d); err != nil { 5430 t.Fatalf("bad: %v", err) 5431 } 5432 5433 // Update the deployment 5434 req := &structs.DeploymentStatusUpdateRequest{ 5435 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 5436 DeploymentID: d.ID, 5437 Status: structs.DeploymentStatusRunning, 5438 }, 5439 } 5440 err := state.UpdateDeploymentStatus(2, req) 5441 if err == nil || !strings.Contains(err.Error(), "has terminal status") { 5442 t.Fatalf("expected error updating the status because the deployment is terminal") 5443 } 5444 } 5445 5446 // Test that a non terminal deployment is updated and that a job and eval are 5447 // created. 5448 func TestStateStore_UpsertDeploymentStatusUpdate_NonTerminal(t *testing.T) { 5449 state := testStateStore(t) 5450 5451 // Insert a deployment 5452 d := mock.Deployment() 5453 if err := state.UpsertDeployment(1, d); err != nil { 5454 t.Fatalf("bad: %v", err) 5455 } 5456 5457 // Create an eval and a job 5458 e := mock.Eval() 5459 j := mock.Job() 5460 5461 // Update the deployment 5462 status, desc := structs.DeploymentStatusFailed, "foo" 5463 req := &structs.DeploymentStatusUpdateRequest{ 5464 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 5465 DeploymentID: d.ID, 5466 Status: status, 5467 StatusDescription: desc, 5468 }, 5469 Job: j, 5470 Eval: e, 5471 } 5472 err := state.UpdateDeploymentStatus(2, req) 5473 if err != nil { 5474 t.Fatalf("bad: %v", err) 5475 } 5476 5477 // Check that the status was updated properly 5478 ws := memdb.NewWatchSet() 5479 dout, err := state.DeploymentByID(ws, d.ID) 5480 if err != nil { 5481 t.Fatalf("bad: %v", err) 5482 } 5483 if dout.Status != status || dout.StatusDescription != desc { 5484 t.Fatalf("bad: %#v", dout) 5485 } 5486 5487 // Check that the evaluation was created 5488 eout, _ := state.EvalByID(ws, e.ID) 5489 if err != nil { 5490 t.Fatalf("bad: %v", err) 5491 } 5492 if eout == nil { 5493 t.Fatalf("bad: %#v", eout) 5494 } 5495 5496 // Check that the job was created 5497 jout, _ := state.JobByID(ws, j.Namespace, j.ID) 5498 if err != nil { 5499 t.Fatalf("bad: %v", err) 5500 } 5501 if jout == nil { 5502 t.Fatalf("bad: %#v", jout) 5503 } 5504 } 5505 5506 // Test that when a deployment is updated to successful the job is updated to 5507 // stable 5508 func TestStateStore_UpsertDeploymentStatusUpdate_Successful(t *testing.T) { 5509 state := testStateStore(t) 5510 5511 // Insert a job 5512 job := mock.Job() 5513 if err := state.UpsertJob(1, job); err != nil { 5514 t.Fatalf("bad: %v", err) 5515 } 5516 5517 // Insert a deployment 5518 d := structs.NewDeployment(job) 5519 if err := state.UpsertDeployment(2, d); err != nil { 5520 t.Fatalf("bad: %v", err) 5521 } 5522 5523 // Update the deployment 5524 req := &structs.DeploymentStatusUpdateRequest{ 5525 DeploymentUpdate: &structs.DeploymentStatusUpdate{ 5526 DeploymentID: d.ID, 5527 Status: structs.DeploymentStatusSuccessful, 5528 StatusDescription: structs.DeploymentStatusDescriptionSuccessful, 5529 }, 5530 } 5531 err := state.UpdateDeploymentStatus(3, req) 5532 if err != nil { 5533 t.Fatalf("bad: %v", err) 5534 } 5535 5536 // Check that the status was updated properly 5537 ws := memdb.NewWatchSet() 5538 dout, err := state.DeploymentByID(ws, d.ID) 5539 if err != nil { 5540 t.Fatalf("bad: %v", err) 5541 } 5542 if dout.Status != structs.DeploymentStatusSuccessful || 5543 dout.StatusDescription != structs.DeploymentStatusDescriptionSuccessful { 5544 t.Fatalf("bad: %#v", dout) 5545 } 5546 5547 // Check that the job was created 5548 jout, _ := state.JobByID(ws, job.Namespace, job.ID) 5549 if err != nil { 5550 t.Fatalf("bad: %v", err) 5551 } 5552 if jout == nil { 5553 t.Fatalf("bad: %#v", jout) 5554 } 5555 if !jout.Stable { 5556 t.Fatalf("job not marked stable %#v", jout) 5557 } 5558 if jout.Version != d.JobVersion { 5559 t.Fatalf("job version changed; got %d; want %d", jout.Version, d.JobVersion) 5560 } 5561 } 5562 5563 func TestStateStore_UpdateJobStability(t *testing.T) { 5564 state := testStateStore(t) 5565 5566 // Insert a job twice to get two versions 5567 job := mock.Job() 5568 if err := state.UpsertJob(1, job); err != nil { 5569 t.Fatalf("bad: %v", err) 5570 } 5571 5572 if err := state.UpsertJob(2, job); err != nil { 5573 t.Fatalf("bad: %v", err) 5574 } 5575 5576 // Update the stability to true 5577 err := state.UpdateJobStability(3, job.Namespace, job.ID, 0, true) 5578 if err != nil { 5579 t.Fatalf("bad: %v", err) 5580 } 5581 5582 // Check that the job was updated properly 5583 ws := memdb.NewWatchSet() 5584 jout, _ := state.JobByIDAndVersion(ws, job.Namespace, job.ID, 0) 5585 if err != nil { 5586 t.Fatalf("bad: %v", err) 5587 } 5588 if jout == nil { 5589 t.Fatalf("bad: %#v", jout) 5590 } 5591 if !jout.Stable { 5592 t.Fatalf("job not marked stable %#v", jout) 5593 } 5594 5595 // Update the stability to false 5596 err = state.UpdateJobStability(3, job.Namespace, job.ID, 0, false) 5597 if err != nil { 5598 t.Fatalf("bad: %v", err) 5599 } 5600 5601 // Check that the job was updated properly 5602 jout, _ = state.JobByIDAndVersion(ws, job.Namespace, job.ID, 0) 5603 if err != nil { 5604 t.Fatalf("bad: %v", err) 5605 } 5606 if jout == nil { 5607 t.Fatalf("bad: %#v", jout) 5608 } 5609 if jout.Stable { 5610 t.Fatalf("job marked stable %#v", jout) 5611 } 5612 } 5613 5614 // Test that nonexistent deployment can't be promoted 5615 func TestStateStore_UpsertDeploymentPromotion_Nonexistent(t *testing.T) { 5616 state := testStateStore(t) 5617 5618 // Promote the nonexistent deployment 5619 req := &structs.ApplyDeploymentPromoteRequest{ 5620 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5621 DeploymentID: uuid.Generate(), 5622 All: true, 5623 }, 5624 } 5625 err := state.UpdateDeploymentPromotion(2, req) 5626 if err == nil || !strings.Contains(err.Error(), "does not exist") { 5627 t.Fatalf("expected error promoting because the deployment doesn't exist") 5628 } 5629 } 5630 5631 // Test that terminal deployment can't be updated 5632 func TestStateStore_UpsertDeploymentPromotion_Terminal(t *testing.T) { 5633 state := testStateStore(t) 5634 5635 // Insert a terminal deployment 5636 d := mock.Deployment() 5637 d.Status = structs.DeploymentStatusFailed 5638 5639 if err := state.UpsertDeployment(1, d); err != nil { 5640 t.Fatalf("bad: %v", err) 5641 } 5642 5643 // Promote the deployment 5644 req := &structs.ApplyDeploymentPromoteRequest{ 5645 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5646 DeploymentID: d.ID, 5647 All: true, 5648 }, 5649 } 5650 err := state.UpdateDeploymentPromotion(2, req) 5651 if err == nil || !strings.Contains(err.Error(), "has terminal status") { 5652 t.Fatalf("expected error updating the status because the deployment is terminal: %v", err) 5653 } 5654 } 5655 5656 // Test promoting unhealthy canaries in a deployment. 5657 func TestStateStore_UpsertDeploymentPromotion_Unhealthy(t *testing.T) { 5658 state := testStateStore(t) 5659 require := require.New(t) 5660 5661 // Create a job 5662 j := mock.Job() 5663 require.Nil(state.UpsertJob(1, j)) 5664 5665 // Create a deployment 5666 d := mock.Deployment() 5667 d.JobID = j.ID 5668 d.TaskGroups["web"].DesiredCanaries = 2 5669 require.Nil(state.UpsertDeployment(2, d)) 5670 5671 // Create a set of allocations 5672 c1 := mock.Alloc() 5673 c1.JobID = j.ID 5674 c1.DeploymentID = d.ID 5675 d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID) 5676 c2 := mock.Alloc() 5677 c2.JobID = j.ID 5678 c2.DeploymentID = d.ID 5679 d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID) 5680 5681 // Create a healthy but terminal alloc 5682 c3 := mock.Alloc() 5683 c3.JobID = j.ID 5684 c3.DeploymentID = d.ID 5685 c3.DesiredStatus = structs.AllocDesiredStatusStop 5686 c3.DeploymentStatus = &structs.AllocDeploymentStatus{Healthy: helper.BoolToPtr(true)} 5687 d.TaskGroups[c3.TaskGroup].PlacedCanaries = append(d.TaskGroups[c3.TaskGroup].PlacedCanaries, c3.ID) 5688 5689 require.Nil(state.UpsertAllocs(3, []*structs.Allocation{c1, c2, c3})) 5690 5691 // Promote the canaries 5692 req := &structs.ApplyDeploymentPromoteRequest{ 5693 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5694 DeploymentID: d.ID, 5695 All: true, 5696 }, 5697 } 5698 err := state.UpdateDeploymentPromotion(4, req) 5699 require.NotNil(err) 5700 require.Contains(err.Error(), `Task group "web" has 0/2 healthy allocations`) 5701 } 5702 5703 // Test promoting a deployment with no canaries 5704 func TestStateStore_UpsertDeploymentPromotion_NoCanaries(t *testing.T) { 5705 state := testStateStore(t) 5706 require := require.New(t) 5707 5708 // Create a job 5709 j := mock.Job() 5710 require.Nil(state.UpsertJob(1, j)) 5711 5712 // Create a deployment 5713 d := mock.Deployment() 5714 d.TaskGroups["web"].DesiredCanaries = 2 5715 d.JobID = j.ID 5716 require.Nil(state.UpsertDeployment(2, d)) 5717 5718 // Promote the canaries 5719 req := &structs.ApplyDeploymentPromoteRequest{ 5720 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5721 DeploymentID: d.ID, 5722 All: true, 5723 }, 5724 } 5725 err := state.UpdateDeploymentPromotion(4, req) 5726 require.NotNil(err) 5727 require.Contains(err.Error(), `Task group "web" has 0/2 healthy allocations`) 5728 } 5729 5730 // Test promoting all canaries in a deployment. 5731 func TestStateStore_UpsertDeploymentPromotion_All(t *testing.T) { 5732 state := testStateStore(t) 5733 5734 // Create a job with two task groups 5735 j := mock.Job() 5736 tg1 := j.TaskGroups[0] 5737 tg2 := tg1.Copy() 5738 tg2.Name = "foo" 5739 j.TaskGroups = append(j.TaskGroups, tg2) 5740 if err := state.UpsertJob(1, j); err != nil { 5741 t.Fatalf("bad: %v", err) 5742 } 5743 5744 // Create a deployment 5745 d := mock.Deployment() 5746 d.StatusDescription = structs.DeploymentStatusDescriptionRunningNeedsPromotion 5747 d.JobID = j.ID 5748 d.TaskGroups = map[string]*structs.DeploymentState{ 5749 "web": { 5750 DesiredTotal: 10, 5751 DesiredCanaries: 1, 5752 }, 5753 "foo": { 5754 DesiredTotal: 10, 5755 DesiredCanaries: 1, 5756 }, 5757 } 5758 if err := state.UpsertDeployment(2, d); err != nil { 5759 t.Fatalf("bad: %v", err) 5760 } 5761 5762 // Create a set of allocations 5763 c1 := mock.Alloc() 5764 c1.JobID = j.ID 5765 c1.DeploymentID = d.ID 5766 d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID) 5767 c1.DeploymentStatus = &structs.AllocDeploymentStatus{ 5768 Healthy: helper.BoolToPtr(true), 5769 } 5770 c2 := mock.Alloc() 5771 c2.JobID = j.ID 5772 c2.DeploymentID = d.ID 5773 d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID) 5774 c2.TaskGroup = tg2.Name 5775 c2.DeploymentStatus = &structs.AllocDeploymentStatus{ 5776 Healthy: helper.BoolToPtr(true), 5777 } 5778 5779 if err := state.UpsertAllocs(3, []*structs.Allocation{c1, c2}); err != nil { 5780 t.Fatalf("err: %v", err) 5781 } 5782 5783 // Create an eval 5784 e := mock.Eval() 5785 5786 // Promote the canaries 5787 req := &structs.ApplyDeploymentPromoteRequest{ 5788 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5789 DeploymentID: d.ID, 5790 All: true, 5791 }, 5792 Eval: e, 5793 } 5794 err := state.UpdateDeploymentPromotion(4, req) 5795 if err != nil { 5796 t.Fatalf("bad: %v", err) 5797 } 5798 5799 // Check that the status per task group was updated properly 5800 ws := memdb.NewWatchSet() 5801 dout, err := state.DeploymentByID(ws, d.ID) 5802 if err != nil { 5803 t.Fatalf("bad: %v", err) 5804 } 5805 if dout.StatusDescription != structs.DeploymentStatusDescriptionRunning { 5806 t.Fatalf("status description not updated: got %v; want %v", dout.StatusDescription, structs.DeploymentStatusDescriptionRunning) 5807 } 5808 if len(dout.TaskGroups) != 2 { 5809 t.Fatalf("bad: %#v", dout.TaskGroups) 5810 } 5811 for tg, state := range dout.TaskGroups { 5812 if !state.Promoted { 5813 t.Fatalf("bad: group %q not promoted %#v", tg, state) 5814 } 5815 } 5816 5817 // Check that the evaluation was created 5818 eout, _ := state.EvalByID(ws, e.ID) 5819 if err != nil { 5820 t.Fatalf("bad: %v", err) 5821 } 5822 if eout == nil { 5823 t.Fatalf("bad: %#v", eout) 5824 } 5825 } 5826 5827 // Test promoting a subset of canaries in a deployment. 5828 func TestStateStore_UpsertDeploymentPromotion_Subset(t *testing.T) { 5829 state := testStateStore(t) 5830 require := require.New(t) 5831 5832 // Create a job with two task groups 5833 j := mock.Job() 5834 tg1 := j.TaskGroups[0] 5835 tg2 := tg1.Copy() 5836 tg2.Name = "foo" 5837 j.TaskGroups = append(j.TaskGroups, tg2) 5838 require.Nil(state.UpsertJob(1, j)) 5839 5840 // Create a deployment 5841 d := mock.Deployment() 5842 d.JobID = j.ID 5843 d.TaskGroups = map[string]*structs.DeploymentState{ 5844 "web": { 5845 DesiredTotal: 10, 5846 DesiredCanaries: 1, 5847 }, 5848 "foo": { 5849 DesiredTotal: 10, 5850 DesiredCanaries: 1, 5851 }, 5852 } 5853 require.Nil(state.UpsertDeployment(2, d)) 5854 5855 // Create a set of allocations for both groups, including an unhealthy one 5856 c1 := mock.Alloc() 5857 c1.JobID = j.ID 5858 c1.DeploymentID = d.ID 5859 d.TaskGroups[c1.TaskGroup].PlacedCanaries = append(d.TaskGroups[c1.TaskGroup].PlacedCanaries, c1.ID) 5860 c1.DeploymentStatus = &structs.AllocDeploymentStatus{ 5861 Healthy: helper.BoolToPtr(true), 5862 Canary: true, 5863 } 5864 5865 // Should still be a canary 5866 c2 := mock.Alloc() 5867 c2.JobID = j.ID 5868 c2.DeploymentID = d.ID 5869 d.TaskGroups[c2.TaskGroup].PlacedCanaries = append(d.TaskGroups[c2.TaskGroup].PlacedCanaries, c2.ID) 5870 c2.TaskGroup = tg2.Name 5871 c2.DeploymentStatus = &structs.AllocDeploymentStatus{ 5872 Healthy: helper.BoolToPtr(true), 5873 Canary: true, 5874 } 5875 5876 c3 := mock.Alloc() 5877 c3.JobID = j.ID 5878 c3.DeploymentID = d.ID 5879 d.TaskGroups[c3.TaskGroup].PlacedCanaries = append(d.TaskGroups[c3.TaskGroup].PlacedCanaries, c3.ID) 5880 c3.DeploymentStatus = &structs.AllocDeploymentStatus{ 5881 Healthy: helper.BoolToPtr(false), 5882 Canary: true, 5883 } 5884 5885 require.Nil(state.UpsertAllocs(3, []*structs.Allocation{c1, c2, c3})) 5886 5887 // Create an eval 5888 e := mock.Eval() 5889 5890 // Promote the canaries 5891 req := &structs.ApplyDeploymentPromoteRequest{ 5892 DeploymentPromoteRequest: structs.DeploymentPromoteRequest{ 5893 DeploymentID: d.ID, 5894 Groups: []string{"web"}, 5895 }, 5896 Eval: e, 5897 } 5898 require.Nil(state.UpdateDeploymentPromotion(4, req)) 5899 5900 // Check that the status per task group was updated properly 5901 ws := memdb.NewWatchSet() 5902 dout, err := state.DeploymentByID(ws, d.ID) 5903 require.Nil(err) 5904 require.Len(dout.TaskGroups, 2) 5905 require.Contains(dout.TaskGroups, "web") 5906 require.True(dout.TaskGroups["web"].Promoted) 5907 5908 // Check that the evaluation was created 5909 eout, err := state.EvalByID(ws, e.ID) 5910 require.Nil(err) 5911 require.NotNil(eout) 5912 5913 // Check the canary field was set properly 5914 aout1, err1 := state.AllocByID(ws, c1.ID) 5915 aout2, err2 := state.AllocByID(ws, c2.ID) 5916 aout3, err3 := state.AllocByID(ws, c3.ID) 5917 require.Nil(err1) 5918 require.Nil(err2) 5919 require.Nil(err3) 5920 require.NotNil(aout1) 5921 require.NotNil(aout2) 5922 require.NotNil(aout3) 5923 require.False(aout1.DeploymentStatus.Canary) 5924 require.True(aout2.DeploymentStatus.Canary) 5925 require.True(aout3.DeploymentStatus.Canary) 5926 } 5927 5928 // Test that allocation health can't be set against a nonexistent deployment 5929 func TestStateStore_UpsertDeploymentAllocHealth_Nonexistent(t *testing.T) { 5930 state := testStateStore(t) 5931 5932 // Set health against the nonexistent deployment 5933 req := &structs.ApplyDeploymentAllocHealthRequest{ 5934 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5935 DeploymentID: uuid.Generate(), 5936 HealthyAllocationIDs: []string{uuid.Generate()}, 5937 }, 5938 } 5939 err := state.UpdateDeploymentAllocHealth(2, req) 5940 if err == nil || !strings.Contains(err.Error(), "does not exist") { 5941 t.Fatalf("expected error because the deployment doesn't exist: %v", err) 5942 } 5943 } 5944 5945 // Test that allocation health can't be set against a terminal deployment 5946 func TestStateStore_UpsertDeploymentAllocHealth_Terminal(t *testing.T) { 5947 state := testStateStore(t) 5948 5949 // Insert a terminal deployment 5950 d := mock.Deployment() 5951 d.Status = structs.DeploymentStatusFailed 5952 5953 if err := state.UpsertDeployment(1, d); err != nil { 5954 t.Fatalf("bad: %v", err) 5955 } 5956 5957 // Set health against the terminal deployment 5958 req := &structs.ApplyDeploymentAllocHealthRequest{ 5959 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5960 DeploymentID: d.ID, 5961 HealthyAllocationIDs: []string{uuid.Generate()}, 5962 }, 5963 } 5964 err := state.UpdateDeploymentAllocHealth(2, req) 5965 if err == nil || !strings.Contains(err.Error(), "has terminal status") { 5966 t.Fatalf("expected error because the deployment is terminal: %v", err) 5967 } 5968 } 5969 5970 // Test that allocation health can't be set against a nonexistent alloc 5971 func TestStateStore_UpsertDeploymentAllocHealth_BadAlloc_Nonexistent(t *testing.T) { 5972 state := testStateStore(t) 5973 5974 // Insert a deployment 5975 d := mock.Deployment() 5976 if err := state.UpsertDeployment(1, d); err != nil { 5977 t.Fatalf("bad: %v", err) 5978 } 5979 5980 // Set health against the terminal deployment 5981 req := &structs.ApplyDeploymentAllocHealthRequest{ 5982 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 5983 DeploymentID: d.ID, 5984 HealthyAllocationIDs: []string{uuid.Generate()}, 5985 }, 5986 } 5987 err := state.UpdateDeploymentAllocHealth(2, req) 5988 if err == nil || !strings.Contains(err.Error(), "unknown alloc") { 5989 t.Fatalf("expected error because the alloc doesn't exist: %v", err) 5990 } 5991 } 5992 5993 // Test that allocation health can't be set for an alloc with mismatched 5994 // deployment ids 5995 func TestStateStore_UpsertDeploymentAllocHealth_BadAlloc_MismatchDeployment(t *testing.T) { 5996 state := testStateStore(t) 5997 5998 // Insert two deployment 5999 d1 := mock.Deployment() 6000 d2 := mock.Deployment() 6001 if err := state.UpsertDeployment(1, d1); err != nil { 6002 t.Fatalf("bad: %v", err) 6003 } 6004 if err := state.UpsertDeployment(2, d2); err != nil { 6005 t.Fatalf("bad: %v", err) 6006 } 6007 6008 // Insert an alloc for a random deployment 6009 a := mock.Alloc() 6010 a.DeploymentID = d1.ID 6011 if err := state.UpsertAllocs(3, []*structs.Allocation{a}); err != nil { 6012 t.Fatalf("bad: %v", err) 6013 } 6014 6015 // Set health against the terminal deployment 6016 req := &structs.ApplyDeploymentAllocHealthRequest{ 6017 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 6018 DeploymentID: d2.ID, 6019 HealthyAllocationIDs: []string{a.ID}, 6020 }, 6021 } 6022 err := state.UpdateDeploymentAllocHealth(4, req) 6023 if err == nil || !strings.Contains(err.Error(), "not part of deployment") { 6024 t.Fatalf("expected error because the alloc isn't part of the deployment: %v", err) 6025 } 6026 } 6027 6028 // Test that allocation health is properly set 6029 func TestStateStore_UpsertDeploymentAllocHealth(t *testing.T) { 6030 state := testStateStore(t) 6031 6032 // Insert a deployment 6033 d := mock.Deployment() 6034 d.TaskGroups["web"].ProgressDeadline = 5 * time.Minute 6035 if err := state.UpsertDeployment(1, d); err != nil { 6036 t.Fatalf("bad: %v", err) 6037 } 6038 6039 // Insert two allocations 6040 a1 := mock.Alloc() 6041 a1.DeploymentID = d.ID 6042 a2 := mock.Alloc() 6043 a2.DeploymentID = d.ID 6044 if err := state.UpsertAllocs(2, []*structs.Allocation{a1, a2}); err != nil { 6045 t.Fatalf("bad: %v", err) 6046 } 6047 6048 // Create a job to roll back to 6049 j := mock.Job() 6050 6051 // Create an eval that should be upserted 6052 e := mock.Eval() 6053 6054 // Create a status update for the deployment 6055 status, desc := structs.DeploymentStatusFailed, "foo" 6056 u := &structs.DeploymentStatusUpdate{ 6057 DeploymentID: d.ID, 6058 Status: status, 6059 StatusDescription: desc, 6060 } 6061 6062 // Capture the time for the update 6063 ts := time.Now() 6064 6065 // Set health against the deployment 6066 req := &structs.ApplyDeploymentAllocHealthRequest{ 6067 DeploymentAllocHealthRequest: structs.DeploymentAllocHealthRequest{ 6068 DeploymentID: d.ID, 6069 HealthyAllocationIDs: []string{a1.ID}, 6070 UnhealthyAllocationIDs: []string{a2.ID}, 6071 }, 6072 Job: j, 6073 Eval: e, 6074 DeploymentUpdate: u, 6075 Timestamp: ts, 6076 } 6077 err := state.UpdateDeploymentAllocHealth(3, req) 6078 if err != nil { 6079 t.Fatalf("bad: %v", err) 6080 } 6081 6082 // Check that the status was updated properly 6083 ws := memdb.NewWatchSet() 6084 dout, err := state.DeploymentByID(ws, d.ID) 6085 if err != nil { 6086 t.Fatalf("bad: %v", err) 6087 } 6088 if dout.Status != status || dout.StatusDescription != desc { 6089 t.Fatalf("bad: %#v", dout) 6090 } 6091 6092 // Check that the evaluation was created 6093 eout, _ := state.EvalByID(ws, e.ID) 6094 if err != nil { 6095 t.Fatalf("bad: %v", err) 6096 } 6097 if eout == nil { 6098 t.Fatalf("bad: %#v", eout) 6099 } 6100 6101 // Check that the job was created 6102 jout, _ := state.JobByID(ws, j.Namespace, j.ID) 6103 if err != nil { 6104 t.Fatalf("bad: %v", err) 6105 } 6106 if jout == nil { 6107 t.Fatalf("bad: %#v", jout) 6108 } 6109 6110 // Check the status of the allocs 6111 out1, err := state.AllocByID(ws, a1.ID) 6112 if err != nil { 6113 t.Fatalf("err: %v", err) 6114 } 6115 out2, err := state.AllocByID(ws, a2.ID) 6116 if err != nil { 6117 t.Fatalf("err: %v", err) 6118 } 6119 6120 if !out1.DeploymentStatus.IsHealthy() { 6121 t.Fatalf("bad: alloc %q not healthy", out1.ID) 6122 } 6123 if !out2.DeploymentStatus.IsUnhealthy() { 6124 t.Fatalf("bad: alloc %q not unhealthy", out2.ID) 6125 } 6126 6127 if !out1.DeploymentStatus.Timestamp.Equal(ts) { 6128 t.Fatalf("bad: alloc %q had timestamp %v; want %v", out1.ID, out1.DeploymentStatus.Timestamp, ts) 6129 } 6130 if !out2.DeploymentStatus.Timestamp.Equal(ts) { 6131 t.Fatalf("bad: alloc %q had timestamp %v; want %v", out2.ID, out2.DeploymentStatus.Timestamp, ts) 6132 } 6133 } 6134 6135 func TestStateStore_UpsertVaultAccessors(t *testing.T) { 6136 state := testStateStore(t) 6137 a := mock.VaultAccessor() 6138 a2 := mock.VaultAccessor() 6139 6140 ws := memdb.NewWatchSet() 6141 if _, err := state.VaultAccessor(ws, a.Accessor); err != nil { 6142 t.Fatalf("err: %v", err) 6143 } 6144 6145 if _, err := state.VaultAccessor(ws, a2.Accessor); err != nil { 6146 t.Fatalf("err: %v", err) 6147 } 6148 6149 err := state.UpsertVaultAccessor(1000, []*structs.VaultAccessor{a, a2}) 6150 if err != nil { 6151 t.Fatalf("err: %v", err) 6152 } 6153 6154 if !watchFired(ws) { 6155 t.Fatalf("bad") 6156 } 6157 6158 ws = memdb.NewWatchSet() 6159 out, err := state.VaultAccessor(ws, a.Accessor) 6160 if err != nil { 6161 t.Fatalf("err: %v", err) 6162 } 6163 6164 if !reflect.DeepEqual(a, out) { 6165 t.Fatalf("bad: %#v %#v", a, out) 6166 } 6167 6168 out, err = state.VaultAccessor(ws, a2.Accessor) 6169 if err != nil { 6170 t.Fatalf("err: %v", err) 6171 } 6172 6173 if !reflect.DeepEqual(a2, out) { 6174 t.Fatalf("bad: %#v %#v", a2, out) 6175 } 6176 6177 iter, err := state.VaultAccessors(ws) 6178 if err != nil { 6179 t.Fatalf("err: %v", err) 6180 } 6181 6182 count := 0 6183 for { 6184 raw := iter.Next() 6185 if raw == nil { 6186 break 6187 } 6188 6189 count++ 6190 accessor := raw.(*structs.VaultAccessor) 6191 6192 if !reflect.DeepEqual(accessor, a) && !reflect.DeepEqual(accessor, a2) { 6193 t.Fatalf("bad: %#v", accessor) 6194 } 6195 } 6196 6197 if count != 2 { 6198 t.Fatalf("bad: %d", count) 6199 } 6200 6201 index, err := state.Index("vault_accessors") 6202 if err != nil { 6203 t.Fatalf("err: %v", err) 6204 } 6205 if index != 1000 { 6206 t.Fatalf("bad: %d", index) 6207 } 6208 6209 if watchFired(ws) { 6210 t.Fatalf("bad") 6211 } 6212 } 6213 6214 func TestStateStore_DeleteVaultAccessors(t *testing.T) { 6215 state := testStateStore(t) 6216 a1 := mock.VaultAccessor() 6217 a2 := mock.VaultAccessor() 6218 accessors := []*structs.VaultAccessor{a1, a2} 6219 6220 err := state.UpsertVaultAccessor(1000, accessors) 6221 if err != nil { 6222 t.Fatalf("err: %v", err) 6223 } 6224 6225 ws := memdb.NewWatchSet() 6226 if _, err := state.VaultAccessor(ws, a1.Accessor); err != nil { 6227 t.Fatalf("err: %v", err) 6228 } 6229 6230 err = state.DeleteVaultAccessors(1001, accessors) 6231 if err != nil { 6232 t.Fatalf("err: %v", err) 6233 } 6234 6235 if !watchFired(ws) { 6236 t.Fatalf("bad") 6237 } 6238 6239 ws = memdb.NewWatchSet() 6240 out, err := state.VaultAccessor(ws, a1.Accessor) 6241 if err != nil { 6242 t.Fatalf("err: %v", err) 6243 } 6244 if out != nil { 6245 t.Fatalf("bad: %#v %#v", a1, out) 6246 } 6247 out, err = state.VaultAccessor(ws, a2.Accessor) 6248 if err != nil { 6249 t.Fatalf("err: %v", err) 6250 } 6251 if out != nil { 6252 t.Fatalf("bad: %#v %#v", a2, out) 6253 } 6254 6255 index, err := state.Index("vault_accessors") 6256 if err != nil { 6257 t.Fatalf("err: %v", err) 6258 } 6259 if index != 1001 { 6260 t.Fatalf("bad: %d", index) 6261 } 6262 6263 if watchFired(ws) { 6264 t.Fatalf("bad") 6265 } 6266 } 6267 6268 func TestStateStore_VaultAccessorsByAlloc(t *testing.T) { 6269 state := testStateStore(t) 6270 alloc := mock.Alloc() 6271 var accessors []*structs.VaultAccessor 6272 var expected []*structs.VaultAccessor 6273 6274 for i := 0; i < 5; i++ { 6275 accessor := mock.VaultAccessor() 6276 accessor.AllocID = alloc.ID 6277 expected = append(expected, accessor) 6278 accessors = append(accessors, accessor) 6279 } 6280 6281 for i := 0; i < 10; i++ { 6282 accessor := mock.VaultAccessor() 6283 accessors = append(accessors, accessor) 6284 } 6285 6286 err := state.UpsertVaultAccessor(1000, accessors) 6287 if err != nil { 6288 t.Fatalf("err: %v", err) 6289 } 6290 6291 ws := memdb.NewWatchSet() 6292 out, err := state.VaultAccessorsByAlloc(ws, alloc.ID) 6293 if err != nil { 6294 t.Fatalf("err: %v", err) 6295 } 6296 6297 if len(expected) != len(out) { 6298 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 6299 } 6300 6301 index, err := state.Index("vault_accessors") 6302 if err != nil { 6303 t.Fatalf("err: %v", err) 6304 } 6305 if index != 1000 { 6306 t.Fatalf("bad: %d", index) 6307 } 6308 6309 if watchFired(ws) { 6310 t.Fatalf("bad") 6311 } 6312 } 6313 6314 func TestStateStore_VaultAccessorsByNode(t *testing.T) { 6315 state := testStateStore(t) 6316 node := mock.Node() 6317 var accessors []*structs.VaultAccessor 6318 var expected []*structs.VaultAccessor 6319 6320 for i := 0; i < 5; i++ { 6321 accessor := mock.VaultAccessor() 6322 accessor.NodeID = node.ID 6323 expected = append(expected, accessor) 6324 accessors = append(accessors, accessor) 6325 } 6326 6327 for i := 0; i < 10; i++ { 6328 accessor := mock.VaultAccessor() 6329 accessors = append(accessors, accessor) 6330 } 6331 6332 err := state.UpsertVaultAccessor(1000, accessors) 6333 if err != nil { 6334 t.Fatalf("err: %v", err) 6335 } 6336 6337 ws := memdb.NewWatchSet() 6338 out, err := state.VaultAccessorsByNode(ws, node.ID) 6339 if err != nil { 6340 t.Fatalf("err: %v", err) 6341 } 6342 6343 if len(expected) != len(out) { 6344 t.Fatalf("bad: %#v %#v", len(expected), len(out)) 6345 } 6346 6347 index, err := state.Index("vault_accessors") 6348 if err != nil { 6349 t.Fatalf("err: %v", err) 6350 } 6351 if index != 1000 { 6352 t.Fatalf("bad: %d", index) 6353 } 6354 6355 if watchFired(ws) { 6356 t.Fatalf("bad") 6357 } 6358 } 6359 6360 func TestStateStore_RestoreVaultAccessor(t *testing.T) { 6361 state := testStateStore(t) 6362 a := mock.VaultAccessor() 6363 6364 restore, err := state.Restore() 6365 if err != nil { 6366 t.Fatalf("err: %v", err) 6367 } 6368 6369 err = restore.VaultAccessorRestore(a) 6370 if err != nil { 6371 t.Fatalf("err: %v", err) 6372 } 6373 restore.Commit() 6374 6375 ws := memdb.NewWatchSet() 6376 out, err := state.VaultAccessor(ws, a.Accessor) 6377 if err != nil { 6378 t.Fatalf("err: %v", err) 6379 } 6380 6381 if !reflect.DeepEqual(out, a) { 6382 t.Fatalf("Bad: %#v %#v", out, a) 6383 } 6384 6385 if watchFired(ws) { 6386 t.Fatalf("bad") 6387 } 6388 } 6389 6390 func TestStateStore_UpsertACLPolicy(t *testing.T) { 6391 state := testStateStore(t) 6392 policy := mock.ACLPolicy() 6393 policy2 := mock.ACLPolicy() 6394 6395 ws := memdb.NewWatchSet() 6396 if _, err := state.ACLPolicyByName(ws, policy.Name); err != nil { 6397 t.Fatalf("err: %v", err) 6398 } 6399 if _, err := state.ACLPolicyByName(ws, policy2.Name); err != nil { 6400 t.Fatalf("err: %v", err) 6401 } 6402 6403 if err := state.UpsertACLPolicies(1000, 6404 []*structs.ACLPolicy{policy, policy2}); err != nil { 6405 t.Fatalf("err: %v", err) 6406 } 6407 if !watchFired(ws) { 6408 t.Fatalf("bad") 6409 } 6410 6411 ws = memdb.NewWatchSet() 6412 out, err := state.ACLPolicyByName(ws, policy.Name) 6413 assert.Equal(t, nil, err) 6414 assert.Equal(t, policy, out) 6415 6416 out, err = state.ACLPolicyByName(ws, policy2.Name) 6417 assert.Equal(t, nil, err) 6418 assert.Equal(t, policy2, out) 6419 6420 iter, err := state.ACLPolicies(ws) 6421 if err != nil { 6422 t.Fatalf("err: %v", err) 6423 } 6424 6425 // Ensure we see both policies 6426 count := 0 6427 for { 6428 raw := iter.Next() 6429 if raw == nil { 6430 break 6431 } 6432 count++ 6433 } 6434 if count != 2 { 6435 t.Fatalf("bad: %d", count) 6436 } 6437 6438 index, err := state.Index("acl_policy") 6439 if err != nil { 6440 t.Fatalf("err: %v", err) 6441 } 6442 if index != 1000 { 6443 t.Fatalf("bad: %d", index) 6444 } 6445 6446 if watchFired(ws) { 6447 t.Fatalf("bad") 6448 } 6449 } 6450 6451 func TestStateStore_DeleteACLPolicy(t *testing.T) { 6452 state := testStateStore(t) 6453 policy := mock.ACLPolicy() 6454 policy2 := mock.ACLPolicy() 6455 6456 // Create the policy 6457 if err := state.UpsertACLPolicies(1000, 6458 []*structs.ACLPolicy{policy, policy2}); err != nil { 6459 t.Fatalf("err: %v", err) 6460 } 6461 6462 // Create a watcher 6463 ws := memdb.NewWatchSet() 6464 if _, err := state.ACLPolicyByName(ws, policy.Name); err != nil { 6465 t.Fatalf("err: %v", err) 6466 } 6467 6468 // Delete the policy 6469 if err := state.DeleteACLPolicies(1001, 6470 []string{policy.Name, policy2.Name}); err != nil { 6471 t.Fatalf("err: %v", err) 6472 } 6473 6474 // Ensure watching triggered 6475 if !watchFired(ws) { 6476 t.Fatalf("bad") 6477 } 6478 6479 // Ensure we don't get the object back 6480 ws = memdb.NewWatchSet() 6481 out, err := state.ACLPolicyByName(ws, policy.Name) 6482 assert.Equal(t, nil, err) 6483 if out != nil { 6484 t.Fatalf("bad: %#v", out) 6485 } 6486 6487 iter, err := state.ACLPolicies(ws) 6488 if err != nil { 6489 t.Fatalf("err: %v", err) 6490 } 6491 6492 // Ensure we see both policies 6493 count := 0 6494 for { 6495 raw := iter.Next() 6496 if raw == nil { 6497 break 6498 } 6499 count++ 6500 } 6501 if count != 0 { 6502 t.Fatalf("bad: %d", count) 6503 } 6504 6505 index, err := state.Index("acl_policy") 6506 if err != nil { 6507 t.Fatalf("err: %v", err) 6508 } 6509 if index != 1001 { 6510 t.Fatalf("bad: %d", index) 6511 } 6512 6513 if watchFired(ws) { 6514 t.Fatalf("bad") 6515 } 6516 } 6517 6518 func TestStateStore_ACLPolicyByNamePrefix(t *testing.T) { 6519 state := testStateStore(t) 6520 names := []string{ 6521 "foo", 6522 "bar", 6523 "foobar", 6524 "foozip", 6525 "zip", 6526 } 6527 6528 // Create the policies 6529 var baseIndex uint64 = 1000 6530 for _, name := range names { 6531 p := mock.ACLPolicy() 6532 p.Name = name 6533 if err := state.UpsertACLPolicies(baseIndex, []*structs.ACLPolicy{p}); err != nil { 6534 t.Fatalf("err: %v", err) 6535 } 6536 baseIndex++ 6537 } 6538 6539 // Scan by prefix 6540 iter, err := state.ACLPolicyByNamePrefix(nil, "foo") 6541 if err != nil { 6542 t.Fatalf("err: %v", err) 6543 } 6544 6545 // Ensure we see both policies 6546 count := 0 6547 out := []string{} 6548 for { 6549 raw := iter.Next() 6550 if raw == nil { 6551 break 6552 } 6553 count++ 6554 out = append(out, raw.(*structs.ACLPolicy).Name) 6555 } 6556 if count != 3 { 6557 t.Fatalf("bad: %d %v", count, out) 6558 } 6559 sort.Strings(out) 6560 6561 expect := []string{"foo", "foobar", "foozip"} 6562 assert.Equal(t, expect, out) 6563 } 6564 6565 func TestStateStore_BootstrapACLTokens(t *testing.T) { 6566 state := testStateStore(t) 6567 tk1 := mock.ACLToken() 6568 tk2 := mock.ACLToken() 6569 6570 ok, resetIdx, err := state.CanBootstrapACLToken() 6571 assert.Nil(t, err) 6572 assert.Equal(t, true, ok) 6573 assert.EqualValues(t, 0, resetIdx) 6574 6575 if err := state.BootstrapACLTokens(1000, 0, tk1); err != nil { 6576 t.Fatalf("err: %v", err) 6577 } 6578 6579 out, err := state.ACLTokenByAccessorID(nil, tk1.AccessorID) 6580 assert.Equal(t, nil, err) 6581 assert.Equal(t, tk1, out) 6582 6583 ok, resetIdx, err = state.CanBootstrapACLToken() 6584 assert.Nil(t, err) 6585 assert.Equal(t, false, ok) 6586 assert.EqualValues(t, 1000, resetIdx) 6587 6588 if err := state.BootstrapACLTokens(1001, 0, tk2); err == nil { 6589 t.Fatalf("expected error") 6590 } 6591 6592 iter, err := state.ACLTokens(nil) 6593 if err != nil { 6594 t.Fatalf("err: %v", err) 6595 } 6596 6597 // Ensure we see both policies 6598 count := 0 6599 for { 6600 raw := iter.Next() 6601 if raw == nil { 6602 break 6603 } 6604 count++ 6605 } 6606 if count != 1 { 6607 t.Fatalf("bad: %d", count) 6608 } 6609 6610 index, err := state.Index("acl_token") 6611 if err != nil { 6612 t.Fatalf("err: %v", err) 6613 } 6614 if index != 1000 { 6615 t.Fatalf("bad: %d", index) 6616 } 6617 index, err = state.Index("acl_token_bootstrap") 6618 if err != nil { 6619 t.Fatalf("err: %v", err) 6620 } 6621 if index != 1000 { 6622 t.Fatalf("bad: %d", index) 6623 } 6624 6625 // Should allow bootstrap with reset index 6626 if err := state.BootstrapACLTokens(1001, 1000, tk2); err != nil { 6627 t.Fatalf("err %v", err) 6628 } 6629 6630 // Check we've modified the index 6631 index, err = state.Index("acl_token") 6632 if err != nil { 6633 t.Fatalf("err: %v", err) 6634 } 6635 if index != 1001 { 6636 t.Fatalf("bad: %d", index) 6637 } 6638 index, err = state.Index("acl_token_bootstrap") 6639 if err != nil { 6640 t.Fatalf("err: %v", err) 6641 } 6642 if index != 1001 { 6643 t.Fatalf("bad: %d", index) 6644 } 6645 } 6646 6647 func TestStateStore_UpsertACLTokens(t *testing.T) { 6648 state := testStateStore(t) 6649 tk1 := mock.ACLToken() 6650 tk2 := mock.ACLToken() 6651 6652 ws := memdb.NewWatchSet() 6653 if _, err := state.ACLTokenByAccessorID(ws, tk1.AccessorID); err != nil { 6654 t.Fatalf("err: %v", err) 6655 } 6656 if _, err := state.ACLTokenByAccessorID(ws, tk2.AccessorID); err != nil { 6657 t.Fatalf("err: %v", err) 6658 } 6659 6660 if err := state.UpsertACLTokens(1000, 6661 []*structs.ACLToken{tk1, tk2}); err != nil { 6662 t.Fatalf("err: %v", err) 6663 } 6664 if !watchFired(ws) { 6665 t.Fatalf("bad") 6666 } 6667 6668 ws = memdb.NewWatchSet() 6669 out, err := state.ACLTokenByAccessorID(ws, tk1.AccessorID) 6670 assert.Equal(t, nil, err) 6671 assert.Equal(t, tk1, out) 6672 6673 out, err = state.ACLTokenByAccessorID(ws, tk2.AccessorID) 6674 assert.Equal(t, nil, err) 6675 assert.Equal(t, tk2, out) 6676 6677 out, err = state.ACLTokenBySecretID(ws, tk1.SecretID) 6678 assert.Equal(t, nil, err) 6679 assert.Equal(t, tk1, out) 6680 6681 out, err = state.ACLTokenBySecretID(ws, tk2.SecretID) 6682 assert.Equal(t, nil, err) 6683 assert.Equal(t, tk2, out) 6684 6685 iter, err := state.ACLTokens(ws) 6686 if err != nil { 6687 t.Fatalf("err: %v", err) 6688 } 6689 6690 // Ensure we see both policies 6691 count := 0 6692 for { 6693 raw := iter.Next() 6694 if raw == nil { 6695 break 6696 } 6697 count++ 6698 } 6699 if count != 2 { 6700 t.Fatalf("bad: %d", count) 6701 } 6702 6703 index, err := state.Index("acl_token") 6704 if err != nil { 6705 t.Fatalf("err: %v", err) 6706 } 6707 if index != 1000 { 6708 t.Fatalf("bad: %d", index) 6709 } 6710 6711 if watchFired(ws) { 6712 t.Fatalf("bad") 6713 } 6714 } 6715 6716 func TestStateStore_DeleteACLTokens(t *testing.T) { 6717 state := testStateStore(t) 6718 tk1 := mock.ACLToken() 6719 tk2 := mock.ACLToken() 6720 6721 // Create the tokens 6722 if err := state.UpsertACLTokens(1000, 6723 []*structs.ACLToken{tk1, tk2}); err != nil { 6724 t.Fatalf("err: %v", err) 6725 } 6726 6727 // Create a watcher 6728 ws := memdb.NewWatchSet() 6729 if _, err := state.ACLTokenByAccessorID(ws, tk1.AccessorID); err != nil { 6730 t.Fatalf("err: %v", err) 6731 } 6732 6733 // Delete the token 6734 if err := state.DeleteACLTokens(1001, 6735 []string{tk1.AccessorID, tk2.AccessorID}); err != nil { 6736 t.Fatalf("err: %v", err) 6737 } 6738 6739 // Ensure watching triggered 6740 if !watchFired(ws) { 6741 t.Fatalf("bad") 6742 } 6743 6744 // Ensure we don't get the object back 6745 ws = memdb.NewWatchSet() 6746 out, err := state.ACLTokenByAccessorID(ws, tk1.AccessorID) 6747 assert.Equal(t, nil, err) 6748 if out != nil { 6749 t.Fatalf("bad: %#v", out) 6750 } 6751 6752 iter, err := state.ACLTokens(ws) 6753 if err != nil { 6754 t.Fatalf("err: %v", err) 6755 } 6756 6757 // Ensure we see both policies 6758 count := 0 6759 for { 6760 raw := iter.Next() 6761 if raw == nil { 6762 break 6763 } 6764 count++ 6765 } 6766 if count != 0 { 6767 t.Fatalf("bad: %d", count) 6768 } 6769 6770 index, err := state.Index("acl_token") 6771 if err != nil { 6772 t.Fatalf("err: %v", err) 6773 } 6774 if index != 1001 { 6775 t.Fatalf("bad: %d", index) 6776 } 6777 6778 if watchFired(ws) { 6779 t.Fatalf("bad") 6780 } 6781 } 6782 6783 func TestStateStore_ACLTokenByAccessorIDPrefix(t *testing.T) { 6784 state := testStateStore(t) 6785 prefixes := []string{ 6786 "aaaa", 6787 "aabb", 6788 "bbbb", 6789 "bbcc", 6790 "ffff", 6791 } 6792 6793 // Create the tokens 6794 var baseIndex uint64 = 1000 6795 for _, prefix := range prefixes { 6796 tk := mock.ACLToken() 6797 tk.AccessorID = prefix + tk.AccessorID[4:] 6798 if err := state.UpsertACLTokens(baseIndex, []*structs.ACLToken{tk}); err != nil { 6799 t.Fatalf("err: %v", err) 6800 } 6801 baseIndex++ 6802 } 6803 6804 // Scan by prefix 6805 iter, err := state.ACLTokenByAccessorIDPrefix(nil, "aa") 6806 if err != nil { 6807 t.Fatalf("err: %v", err) 6808 } 6809 6810 // Ensure we see both tokens 6811 count := 0 6812 out := []string{} 6813 for { 6814 raw := iter.Next() 6815 if raw == nil { 6816 break 6817 } 6818 count++ 6819 out = append(out, raw.(*structs.ACLToken).AccessorID[:4]) 6820 } 6821 if count != 2 { 6822 t.Fatalf("bad: %d %v", count, out) 6823 } 6824 sort.Strings(out) 6825 6826 expect := []string{"aaaa", "aabb"} 6827 assert.Equal(t, expect, out) 6828 } 6829 6830 func TestStateStore_RestoreACLPolicy(t *testing.T) { 6831 state := testStateStore(t) 6832 policy := mock.ACLPolicy() 6833 6834 restore, err := state.Restore() 6835 if err != nil { 6836 t.Fatalf("err: %v", err) 6837 } 6838 6839 err = restore.ACLPolicyRestore(policy) 6840 if err != nil { 6841 t.Fatalf("err: %v", err) 6842 } 6843 restore.Commit() 6844 6845 ws := memdb.NewWatchSet() 6846 out, err := state.ACLPolicyByName(ws, policy.Name) 6847 if err != nil { 6848 t.Fatalf("err: %v", err) 6849 } 6850 assert.Equal(t, policy, out) 6851 } 6852 6853 func TestStateStore_ACLTokensByGlobal(t *testing.T) { 6854 state := testStateStore(t) 6855 tk1 := mock.ACLToken() 6856 tk2 := mock.ACLToken() 6857 tk3 := mock.ACLToken() 6858 tk4 := mock.ACLToken() 6859 tk3.Global = true 6860 6861 if err := state.UpsertACLTokens(1000, 6862 []*structs.ACLToken{tk1, tk2, tk3, tk4}); err != nil { 6863 t.Fatalf("err: %v", err) 6864 } 6865 6866 iter, err := state.ACLTokensByGlobal(nil, true) 6867 if err != nil { 6868 t.Fatalf("err: %v", err) 6869 } 6870 6871 // Ensure we see the one global policies 6872 count := 0 6873 for { 6874 raw := iter.Next() 6875 if raw == nil { 6876 break 6877 } 6878 count++ 6879 } 6880 if count != 1 { 6881 t.Fatalf("bad: %d", count) 6882 } 6883 } 6884 6885 func TestStateStore_RestoreACLToken(t *testing.T) { 6886 state := testStateStore(t) 6887 token := mock.ACLToken() 6888 6889 restore, err := state.Restore() 6890 if err != nil { 6891 t.Fatalf("err: %v", err) 6892 } 6893 6894 err = restore.ACLTokenRestore(token) 6895 if err != nil { 6896 t.Fatalf("err: %v", err) 6897 } 6898 restore.Commit() 6899 6900 ws := memdb.NewWatchSet() 6901 out, err := state.ACLTokenByAccessorID(ws, token.AccessorID) 6902 if err != nil { 6903 t.Fatalf("err: %v", err) 6904 } 6905 assert.Equal(t, token, out) 6906 } 6907 6908 func TestStateStore_Abandon(t *testing.T) { 6909 s := testStateStore(t) 6910 abandonCh := s.AbandonCh() 6911 s.Abandon() 6912 select { 6913 case <-abandonCh: 6914 default: 6915 t.Fatalf("bad") 6916 } 6917 } 6918 6919 // watchFired is a helper for unit tests that returns if the given watch set 6920 // fired (it doesn't care which watch actually fired). This uses a fixed 6921 // timeout since we already expect the event happened before calling this and 6922 // just need to distinguish a fire from a timeout. We do need a little time to 6923 // allow the watch to set up any goroutines, though. 6924 func watchFired(ws memdb.WatchSet) bool { 6925 timedOut := ws.Watch(time.After(50 * time.Millisecond)) 6926 return !timedOut 6927 } 6928 6929 // NodeIDSort is used to sort nodes by ID 6930 type NodeIDSort []*structs.Node 6931 6932 func (n NodeIDSort) Len() int { 6933 return len(n) 6934 } 6935 6936 func (n NodeIDSort) Less(i, j int) bool { 6937 return n[i].ID < n[j].ID 6938 } 6939 6940 func (n NodeIDSort) Swap(i, j int) { 6941 n[i], n[j] = n[j], n[i] 6942 } 6943 6944 // JobIDis used to sort jobs by id 6945 type JobIDSort []*structs.Job 6946 6947 func (n JobIDSort) Len() int { 6948 return len(n) 6949 } 6950 6951 func (n JobIDSort) Less(i, j int) bool { 6952 return n[i].ID < n[j].ID 6953 } 6954 6955 func (n JobIDSort) Swap(i, j int) { 6956 n[i], n[j] = n[j], n[i] 6957 } 6958 6959 // EvalIDis used to sort evals by id 6960 type EvalIDSort []*structs.Evaluation 6961 6962 func (n EvalIDSort) Len() int { 6963 return len(n) 6964 } 6965 6966 func (n EvalIDSort) Less(i, j int) bool { 6967 return n[i].ID < n[j].ID 6968 } 6969 6970 func (n EvalIDSort) Swap(i, j int) { 6971 n[i], n[j] = n[j], n[i] 6972 } 6973 6974 // AllocIDsort used to sort allocations by id 6975 type AllocIDSort []*structs.Allocation 6976 6977 func (n AllocIDSort) Len() int { 6978 return len(n) 6979 } 6980 6981 func (n AllocIDSort) Less(i, j int) bool { 6982 return n[i].ID < n[j].ID 6983 } 6984 6985 func (n AllocIDSort) Swap(i, j int) { 6986 n[i], n[j] = n[j], n[i] 6987 }