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