github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/nomad/node_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/net-rpc-msgpackrpc" 11 "github.com/hashicorp/nomad/nomad/mock" 12 "github.com/hashicorp/nomad/nomad/structs" 13 "github.com/hashicorp/nomad/testutil" 14 vapi "github.com/hashicorp/vault/api" 15 ) 16 17 func TestClientEndpoint_Register(t *testing.T) { 18 s1 := testServer(t, nil) 19 defer s1.Shutdown() 20 codec := rpcClient(t, s1) 21 testutil.WaitForLeader(t, s1.RPC) 22 23 // Create the register request 24 node := mock.Node() 25 req := &structs.NodeRegisterRequest{ 26 Node: node, 27 WriteRequest: structs.WriteRequest{Region: "global"}, 28 } 29 30 // Fetch the response 31 var resp structs.GenericResponse 32 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil { 33 t.Fatalf("err: %v", err) 34 } 35 if resp.Index == 0 { 36 t.Fatalf("bad index: %d", resp.Index) 37 } 38 39 // Check for the node in the FSM 40 state := s1.fsm.State() 41 out, err := state.NodeByID(node.ID) 42 if err != nil { 43 t.Fatalf("err: %v", err) 44 } 45 if out == nil { 46 t.Fatalf("expected node") 47 } 48 if out.CreateIndex != resp.Index { 49 t.Fatalf("index mis-match") 50 } 51 if out.ComputedClass == "" { 52 t.Fatal("ComputedClass not set") 53 } 54 } 55 56 func TestClientEndpoint_Register_NoSecret(t *testing.T) { 57 s1 := testServer(t, nil) 58 defer s1.Shutdown() 59 codec := rpcClient(t, s1) 60 testutil.WaitForLeader(t, s1.RPC) 61 62 // Create the register request 63 node := mock.Node() 64 node.SecretID = "" 65 req := &structs.NodeRegisterRequest{ 66 Node: node, 67 WriteRequest: structs.WriteRequest{Region: "global"}, 68 } 69 70 // Fetch the response 71 var resp structs.GenericResponse 72 err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp) 73 if err == nil || !strings.Contains(err.Error(), "secret") { 74 t.Fatalf("Expecting error regarding missing secret id: %v", err) 75 } 76 77 // Update the node to be pre-0.5 78 node.Attributes["nomad.version"] = "0.4.1" 79 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil { 80 t.Fatalf("Not expecting err: %v", err) 81 } 82 if resp.Index == 0 { 83 t.Fatalf("bad index: %d", resp.Index) 84 } 85 86 // Check for the node in the FSM 87 state := s1.fsm.State() 88 out, err := state.NodeByID(node.ID) 89 if err != nil { 90 t.Fatalf("err: %v", err) 91 } 92 if out == nil { 93 t.Fatalf("expected node") 94 } 95 if out.CreateIndex != resp.Index { 96 t.Fatalf("index mis-match") 97 } 98 if out.ComputedClass == "" { 99 t.Fatal("ComputedClass not set") 100 } 101 } 102 103 func TestClientEndpoint_Register_SecretMismatch(t *testing.T) { 104 s1 := testServer(t, nil) 105 defer s1.Shutdown() 106 codec := rpcClient(t, s1) 107 testutil.WaitForLeader(t, s1.RPC) 108 109 // Create the register request 110 node := mock.Node() 111 req := &structs.NodeRegisterRequest{ 112 Node: node, 113 WriteRequest: structs.WriteRequest{Region: "global"}, 114 } 115 116 // Fetch the response 117 var resp structs.GenericResponse 118 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil { 119 t.Fatalf("err: %v", err) 120 } 121 122 // Update the nodes SecretID 123 node.SecretID = structs.GenerateUUID() 124 err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp) 125 if err == nil || !strings.Contains(err.Error(), "Not registering") { 126 t.Fatalf("Expecting error regarding mismatching secret id", err) 127 } 128 } 129 130 func TestClientEndpoint_Deregister(t *testing.T) { 131 s1 := testServer(t, nil) 132 defer s1.Shutdown() 133 codec := rpcClient(t, s1) 134 testutil.WaitForLeader(t, s1.RPC) 135 136 // Create the register request 137 node := mock.Node() 138 reg := &structs.NodeRegisterRequest{ 139 Node: node, 140 WriteRequest: structs.WriteRequest{Region: "global"}, 141 } 142 143 // Fetch the response 144 var resp structs.GenericResponse 145 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 146 t.Fatalf("err: %v", err) 147 } 148 149 // Deregister 150 dereg := &structs.NodeDeregisterRequest{ 151 NodeID: node.ID, 152 WriteRequest: structs.WriteRequest{Region: "global"}, 153 } 154 var resp2 structs.GenericResponse 155 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp2); err != nil { 156 t.Fatalf("err: %v", err) 157 } 158 if resp2.Index == 0 { 159 t.Fatalf("bad index: %d", resp2.Index) 160 } 161 162 // Check for the node in the FSM 163 state := s1.fsm.State() 164 out, err := state.NodeByID(node.ID) 165 if err != nil { 166 t.Fatalf("err: %v", err) 167 } 168 if out != nil { 169 t.Fatalf("unexpected node") 170 } 171 } 172 173 func TestClientEndpoint_Deregister_Vault(t *testing.T) { 174 s1 := testServer(t, nil) 175 defer s1.Shutdown() 176 codec := rpcClient(t, s1) 177 testutil.WaitForLeader(t, s1.RPC) 178 179 // Create the register request 180 node := mock.Node() 181 reg := &structs.NodeRegisterRequest{ 182 Node: node, 183 WriteRequest: structs.WriteRequest{Region: "global"}, 184 } 185 186 // Fetch the response 187 var resp structs.GenericResponse 188 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 189 t.Fatalf("err: %v", err) 190 } 191 192 // Swap the servers Vault Client 193 tvc := &TestVaultClient{} 194 s1.vault = tvc 195 196 // Put some Vault accessors in the state store for that node 197 state := s1.fsm.State() 198 va1 := mock.VaultAccessor() 199 va1.NodeID = node.ID 200 va2 := mock.VaultAccessor() 201 va2.NodeID = node.ID 202 state.UpsertVaultAccessor(100, []*structs.VaultAccessor{va1, va2}) 203 204 // Deregister 205 dereg := &structs.NodeDeregisterRequest{ 206 NodeID: node.ID, 207 WriteRequest: structs.WriteRequest{Region: "global"}, 208 } 209 var resp2 structs.GenericResponse 210 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp2); err != nil { 211 t.Fatalf("err: %v", err) 212 } 213 if resp2.Index == 0 { 214 t.Fatalf("bad index: %d", resp2.Index) 215 } 216 217 // Check for the node in the FSM 218 out, err := state.NodeByID(node.ID) 219 if err != nil { 220 t.Fatalf("err: %v", err) 221 } 222 if out != nil { 223 t.Fatalf("unexpected node") 224 } 225 226 // Check that the endpoint revoked the tokens 227 if l := len(tvc.RevokedTokens); l != 2 { 228 t.Fatalf("Deregister revoked %d tokens; want 2", l) 229 } 230 } 231 232 func TestClientEndpoint_UpdateStatus(t *testing.T) { 233 s1 := testServer(t, nil) 234 defer s1.Shutdown() 235 codec := rpcClient(t, s1) 236 testutil.WaitForLeader(t, s1.RPC) 237 238 // Create the register request 239 node := mock.Node() 240 reg := &structs.NodeRegisterRequest{ 241 Node: node, 242 WriteRequest: structs.WriteRequest{Region: "global"}, 243 } 244 245 // Fetch the response 246 var resp structs.NodeUpdateResponse 247 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 248 t.Fatalf("err: %v", err) 249 } 250 251 // Check for heartbeat interval 252 ttl := resp.HeartbeatTTL 253 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 254 t.Fatalf("bad: %#v", ttl) 255 } 256 257 // Update the status 258 dereg := &structs.NodeUpdateStatusRequest{ 259 NodeID: node.ID, 260 Status: structs.NodeStatusInit, 261 WriteRequest: structs.WriteRequest{Region: "global"}, 262 } 263 var resp2 structs.NodeUpdateResponse 264 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 265 t.Fatalf("err: %v", err) 266 } 267 if resp2.Index == 0 { 268 t.Fatalf("bad index: %d", resp2.Index) 269 } 270 271 // Check for heartbeat interval 272 ttl = resp2.HeartbeatTTL 273 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 274 t.Fatalf("bad: %#v", ttl) 275 } 276 277 // Check for the node in the FSM 278 state := s1.fsm.State() 279 out, err := state.NodeByID(node.ID) 280 if err != nil { 281 t.Fatalf("err: %v", err) 282 } 283 if out == nil { 284 t.Fatalf("expected node") 285 } 286 if out.ModifyIndex != resp2.Index { 287 t.Fatalf("index mis-match") 288 } 289 } 290 291 func TestClientEndpoint_UpdateStatus_Vault(t *testing.T) { 292 s1 := testServer(t, nil) 293 defer s1.Shutdown() 294 codec := rpcClient(t, s1) 295 testutil.WaitForLeader(t, s1.RPC) 296 297 // Create the register request 298 node := mock.Node() 299 reg := &structs.NodeRegisterRequest{ 300 Node: node, 301 WriteRequest: structs.WriteRequest{Region: "global"}, 302 } 303 304 // Fetch the response 305 var resp structs.NodeUpdateResponse 306 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 307 t.Fatalf("err: %v", err) 308 } 309 310 // Check for heartbeat interval 311 ttl := resp.HeartbeatTTL 312 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 313 t.Fatalf("bad: %#v", ttl) 314 } 315 316 // Swap the servers Vault Client 317 tvc := &TestVaultClient{} 318 s1.vault = tvc 319 320 // Put some Vault accessors in the state store for that node 321 state := s1.fsm.State() 322 va1 := mock.VaultAccessor() 323 va1.NodeID = node.ID 324 va2 := mock.VaultAccessor() 325 va2.NodeID = node.ID 326 state.UpsertVaultAccessor(100, []*structs.VaultAccessor{va1, va2}) 327 328 // Update the status to be down 329 dereg := &structs.NodeUpdateStatusRequest{ 330 NodeID: node.ID, 331 Status: structs.NodeStatusDown, 332 WriteRequest: structs.WriteRequest{Region: "global"}, 333 } 334 var resp2 structs.NodeUpdateResponse 335 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 336 t.Fatalf("err: %v", err) 337 } 338 if resp2.Index == 0 { 339 t.Fatalf("bad index: %d", resp2.Index) 340 } 341 342 // Check that the endpoint revoked the tokens 343 if l := len(tvc.RevokedTokens); l != 2 { 344 t.Fatalf("Deregister revoked %d tokens; want 2", l) 345 } 346 } 347 348 func TestClientEndpoint_Register_GetEvals(t *testing.T) { 349 s1 := testServer(t, nil) 350 defer s1.Shutdown() 351 codec := rpcClient(t, s1) 352 testutil.WaitForLeader(t, s1.RPC) 353 354 // Register a system job. 355 job := mock.SystemJob() 356 state := s1.fsm.State() 357 if err := state.UpsertJob(1, job); err != nil { 358 t.Fatalf("err: %v", err) 359 } 360 361 // Create the register request going directly to ready 362 node := mock.Node() 363 node.Status = structs.NodeStatusReady 364 reg := &structs.NodeRegisterRequest{ 365 Node: node, 366 WriteRequest: structs.WriteRequest{Region: "global"}, 367 } 368 369 // Fetch the response 370 var resp structs.NodeUpdateResponse 371 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 372 t.Fatalf("err: %v", err) 373 } 374 375 // Check for heartbeat interval 376 ttl := resp.HeartbeatTTL 377 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 378 t.Fatalf("bad: %#v", ttl) 379 } 380 381 // Check for an eval caused by the system job. 382 if len(resp.EvalIDs) != 1 { 383 t.Fatalf("expected one eval; got %#v", resp.EvalIDs) 384 } 385 386 evalID := resp.EvalIDs[0] 387 eval, err := state.EvalByID(evalID) 388 if err != nil { 389 t.Fatalf("could not get eval %v", evalID) 390 } 391 392 if eval.Type != "system" { 393 t.Fatalf("unexpected eval type; got %v; want %q", eval.Type, "system") 394 } 395 396 // Check for the node in the FSM 397 out, err := state.NodeByID(node.ID) 398 if err != nil { 399 t.Fatalf("err: %v", err) 400 } 401 if out == nil { 402 t.Fatalf("expected node") 403 } 404 if out.ModifyIndex != resp.Index { 405 t.Fatalf("index mis-match") 406 } 407 408 // Transistion it to down and then ready 409 node.Status = structs.NodeStatusDown 410 reg = &structs.NodeRegisterRequest{ 411 Node: node, 412 WriteRequest: structs.WriteRequest{Region: "global"}, 413 } 414 415 // Fetch the response 416 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 417 t.Fatalf("err: %v", err) 418 } 419 420 if len(resp.EvalIDs) != 1 { 421 t.Fatalf("expected one eval; got %#v", resp.EvalIDs) 422 } 423 424 node.Status = structs.NodeStatusReady 425 reg = &structs.NodeRegisterRequest{ 426 Node: node, 427 WriteRequest: structs.WriteRequest{Region: "global"}, 428 } 429 430 // Fetch the response 431 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 432 t.Fatalf("err: %v", err) 433 } 434 435 if len(resp.EvalIDs) != 1 { 436 t.Fatalf("expected one eval; got %#v", resp.EvalIDs) 437 } 438 } 439 440 func TestClientEndpoint_UpdateStatus_GetEvals(t *testing.T) { 441 s1 := testServer(t, nil) 442 defer s1.Shutdown() 443 codec := rpcClient(t, s1) 444 testutil.WaitForLeader(t, s1.RPC) 445 446 // Register a system job. 447 job := mock.SystemJob() 448 state := s1.fsm.State() 449 if err := state.UpsertJob(1, job); err != nil { 450 t.Fatalf("err: %v", err) 451 } 452 453 // Create the register request 454 node := mock.Node() 455 node.Status = structs.NodeStatusInit 456 reg := &structs.NodeRegisterRequest{ 457 Node: node, 458 WriteRequest: structs.WriteRequest{Region: "global"}, 459 } 460 461 // Fetch the response 462 var resp structs.NodeUpdateResponse 463 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 464 t.Fatalf("err: %v", err) 465 } 466 467 // Check for heartbeat interval 468 ttl := resp.HeartbeatTTL 469 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 470 t.Fatalf("bad: %#v", ttl) 471 } 472 473 // Update the status 474 update := &structs.NodeUpdateStatusRequest{ 475 NodeID: node.ID, 476 Status: structs.NodeStatusReady, 477 WriteRequest: structs.WriteRequest{Region: "global"}, 478 } 479 var resp2 structs.NodeUpdateResponse 480 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", update, &resp2); err != nil { 481 t.Fatalf("err: %v", err) 482 } 483 if resp2.Index == 0 { 484 t.Fatalf("bad index: %d", resp2.Index) 485 } 486 487 // Check for an eval caused by the system job. 488 if len(resp2.EvalIDs) != 1 { 489 t.Fatalf("expected one eval; got %#v", resp2.EvalIDs) 490 } 491 492 evalID := resp2.EvalIDs[0] 493 eval, err := state.EvalByID(evalID) 494 if err != nil { 495 t.Fatalf("could not get eval %v", evalID) 496 } 497 498 if eval.Type != "system" { 499 t.Fatalf("unexpected eval type; got %v; want %q", eval.Type, "system") 500 } 501 502 // Check for heartbeat interval 503 ttl = resp2.HeartbeatTTL 504 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 505 t.Fatalf("bad: %#v", ttl) 506 } 507 508 // Check for the node in the FSM 509 out, err := state.NodeByID(node.ID) 510 if err != nil { 511 t.Fatalf("err: %v", err) 512 } 513 if out == nil { 514 t.Fatalf("expected node") 515 } 516 if out.ModifyIndex != resp2.Index { 517 t.Fatalf("index mis-match") 518 } 519 } 520 521 func TestClientEndpoint_UpdateStatus_HeartbeatOnly(t *testing.T) { 522 s1 := testServer(t, nil) 523 defer s1.Shutdown() 524 525 s2 := testServer(t, func(c *Config) { 526 c.DevDisableBootstrap = true 527 }) 528 defer s2.Shutdown() 529 530 s3 := testServer(t, func(c *Config) { 531 c.DevDisableBootstrap = true 532 }) 533 defer s3.Shutdown() 534 servers := []*Server{s1, s2, s3} 535 testJoin(t, s1, s2, s3) 536 537 for _, s := range servers { 538 testutil.WaitForResult(func() (bool, error) { 539 peers, _ := s.raftPeers.Peers() 540 return len(peers) == 3, nil 541 }, func(err error) { 542 t.Fatalf("should have 3 peers") 543 }) 544 } 545 546 codec := rpcClient(t, s1) 547 testutil.WaitForLeader(t, s1.RPC) 548 549 // Create the register request 550 node := mock.Node() 551 reg := &structs.NodeRegisterRequest{ 552 Node: node, 553 WriteRequest: structs.WriteRequest{Region: "global"}, 554 } 555 556 // Fetch the response 557 var resp structs.NodeUpdateResponse 558 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 559 t.Fatalf("err: %v", err) 560 } 561 562 // Check for heartbeat interval 563 ttl := resp.HeartbeatTTL 564 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 565 t.Fatalf("bad: %#v", ttl) 566 } 567 568 // Check for heartbeat servers 569 serverAddrs := resp.Servers 570 if len(serverAddrs) == 0 { 571 t.Fatalf("bad: %#v", serverAddrs) 572 } 573 574 // Update the status, static state 575 dereg := &structs.NodeUpdateStatusRequest{ 576 NodeID: node.ID, 577 Status: node.Status, 578 WriteRequest: structs.WriteRequest{Region: "global"}, 579 } 580 var resp2 structs.NodeUpdateResponse 581 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 582 t.Fatalf("err: %v", err) 583 } 584 if resp2.Index != 0 { 585 t.Fatalf("bad index: %d", resp2.Index) 586 } 587 588 // Check for heartbeat interval 589 ttl = resp2.HeartbeatTTL 590 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 591 t.Fatalf("bad: %#v", ttl) 592 } 593 } 594 595 func TestClientEndpoint_UpdateDrain(t *testing.T) { 596 s1 := testServer(t, nil) 597 defer s1.Shutdown() 598 codec := rpcClient(t, s1) 599 testutil.WaitForLeader(t, s1.RPC) 600 601 // Create the register request 602 node := mock.Node() 603 reg := &structs.NodeRegisterRequest{ 604 Node: node, 605 WriteRequest: structs.WriteRequest{Region: "global"}, 606 } 607 608 // Fetch the response 609 var resp structs.NodeUpdateResponse 610 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 611 t.Fatalf("err: %v", err) 612 } 613 614 // Update the status 615 dereg := &structs.NodeUpdateDrainRequest{ 616 NodeID: node.ID, 617 Drain: true, 618 WriteRequest: structs.WriteRequest{Region: "global"}, 619 } 620 var resp2 structs.NodeDrainUpdateResponse 621 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp2); err != nil { 622 t.Fatalf("err: %v", err) 623 } 624 if resp2.Index == 0 { 625 t.Fatalf("bad index: %d", resp2.Index) 626 } 627 628 // Check for the node in the FSM 629 state := s1.fsm.State() 630 out, err := state.NodeByID(node.ID) 631 if err != nil { 632 t.Fatalf("err: %v", err) 633 } 634 if !out.Drain { 635 t.Fatalf("bad: %#v", out) 636 } 637 } 638 639 // This test ensures that Nomad marks client state of allocations which are in 640 // pending/running state to lost when a node is marked as down. 641 func TestClientEndpoint_Drain_Down(t *testing.T) { 642 s1 := testServer(t, nil) 643 defer s1.Shutdown() 644 codec := rpcClient(t, s1) 645 testutil.WaitForLeader(t, s1.RPC) 646 647 // Register a node 648 node := mock.Node() 649 reg := &structs.NodeRegisterRequest{ 650 Node: node, 651 WriteRequest: structs.WriteRequest{Region: "global"}, 652 } 653 // Fetch the response 654 var resp structs.NodeUpdateResponse 655 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 656 t.Fatalf("err: %v", err) 657 } 658 659 // Register a service job 660 var jobResp structs.JobRegisterResponse 661 job := mock.Job() 662 job.TaskGroups[0].Count = 1 663 jobReq := &structs.JobRegisterRequest{ 664 Job: job, 665 WriteRequest: structs.WriteRequest{Region: "global"}, 666 } 667 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", jobReq, &jobResp); err != nil { 668 t.Fatalf("err: %v", err) 669 } 670 671 // Register a system job 672 var jobResp1 structs.JobRegisterResponse 673 job1 := mock.Job() 674 job1.TaskGroups[0].Count = 1 675 job1.Type = structs.JobTypeSystem 676 jobReq1 := &structs.JobRegisterRequest{ 677 Job: job1, 678 WriteRequest: structs.WriteRequest{Region: "global"}, 679 } 680 if err := msgpackrpc.CallWithCodec(codec, "Job.Register", jobReq1, &jobResp1); err != nil { 681 t.Fatalf("err: %v", err) 682 } 683 684 // Wait for the scheduler to create an allocation 685 testutil.WaitForResult(func() (bool, error) { 686 allocs, err := s1.fsm.state.AllocsByJob(job.ID) 687 if err != nil { 688 return false, err 689 } 690 allocs1, err := s1.fsm.state.AllocsByJob(job1.ID) 691 if err != nil { 692 return false, err 693 } 694 return len(allocs) > 0 && len(allocs1) > 0, nil 695 }, func(err error) { 696 t.Fatalf("err: %v", err) 697 }) 698 699 // Drain the node 700 dereg := &structs.NodeUpdateDrainRequest{ 701 NodeID: node.ID, 702 Drain: true, 703 WriteRequest: structs.WriteRequest{Region: "global"}, 704 } 705 var resp2 structs.NodeDrainUpdateResponse 706 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp2); err != nil { 707 t.Fatalf("err: %v", err) 708 } 709 710 // Mark the node as down 711 node.Status = structs.NodeStatusDown 712 reg = &structs.NodeRegisterRequest{ 713 Node: node, 714 WriteRequest: structs.WriteRequest{Region: "global"}, 715 } 716 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 717 t.Fatalf("err: %v", err) 718 } 719 720 // Ensure that the allocation has transitioned to lost 721 testutil.WaitForResult(func() (bool, error) { 722 summary, err := s1.fsm.state.JobSummaryByID(job.ID) 723 if err != nil { 724 return false, err 725 } 726 expectedSummary := &structs.JobSummary{ 727 JobID: job.ID, 728 Summary: map[string]structs.TaskGroupSummary{ 729 "web": structs.TaskGroupSummary{ 730 Queued: 1, 731 Lost: 1, 732 }, 733 }, 734 CreateIndex: jobResp.JobModifyIndex, 735 ModifyIndex: summary.ModifyIndex, 736 } 737 if !reflect.DeepEqual(summary, expectedSummary) { 738 return false, fmt.Errorf("expected: %#v, actual: %#v", expectedSummary, summary) 739 } 740 741 summary1, err := s1.fsm.state.JobSummaryByID(job1.ID) 742 if err != nil { 743 return false, err 744 } 745 expectedSummary1 := &structs.JobSummary{ 746 JobID: job1.ID, 747 Summary: map[string]structs.TaskGroupSummary{ 748 "web": structs.TaskGroupSummary{ 749 Lost: 1, 750 }, 751 }, 752 CreateIndex: jobResp1.JobModifyIndex, 753 ModifyIndex: summary1.ModifyIndex, 754 } 755 if !reflect.DeepEqual(summary1, expectedSummary1) { 756 return false, fmt.Errorf("expected: %#v, actual: %#v", expectedSummary1, summary1) 757 } 758 return true, nil 759 }, func(err error) { 760 t.Fatalf("err: %v", err) 761 }) 762 } 763 764 func TestClientEndpoint_GetNode(t *testing.T) { 765 s1 := testServer(t, nil) 766 defer s1.Shutdown() 767 codec := rpcClient(t, s1) 768 testutil.WaitForLeader(t, s1.RPC) 769 770 // Create the register request 771 node := mock.Node() 772 reg := &structs.NodeRegisterRequest{ 773 Node: node, 774 WriteRequest: structs.WriteRequest{Region: "global"}, 775 } 776 777 // Fetch the response 778 var resp structs.GenericResponse 779 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 780 t.Fatalf("err: %v", err) 781 } 782 node.CreateIndex = resp.Index 783 node.ModifyIndex = resp.Index 784 785 // Lookup the node 786 get := &structs.NodeSpecificRequest{ 787 NodeID: node.ID, 788 QueryOptions: structs.QueryOptions{Region: "global"}, 789 } 790 var resp2 structs.SingleNodeResponse 791 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil { 792 t.Fatalf("err: %v", err) 793 } 794 if resp2.Index != resp.Index { 795 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 796 } 797 798 if resp2.Node.ComputedClass == "" { 799 t.Fatalf("bad ComputedClass: %#v", resp2.Node) 800 } 801 802 // Update the status updated at value 803 node.StatusUpdatedAt = resp2.Node.StatusUpdatedAt 804 node.SecretID = "" 805 if !reflect.DeepEqual(node, resp2.Node) { 806 t.Fatalf("bad: %#v \n %#v", node, resp2.Node) 807 } 808 809 // Lookup non-existing node 810 get.NodeID = "12345678-abcd-efab-cdef-123456789abc" 811 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil { 812 t.Fatalf("err: %v", err) 813 } 814 if resp2.Index != resp.Index { 815 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 816 } 817 if resp2.Node != nil { 818 t.Fatalf("unexpected node") 819 } 820 } 821 822 func TestClientEndpoint_GetNode_Blocking(t *testing.T) { 823 s1 := testServer(t, nil) 824 defer s1.Shutdown() 825 state := s1.fsm.State() 826 codec := rpcClient(t, s1) 827 testutil.WaitForLeader(t, s1.RPC) 828 829 // Create the node 830 node1 := mock.Node() 831 node2 := mock.Node() 832 833 // First create an unrelated node. 834 time.AfterFunc(100*time.Millisecond, func() { 835 if err := state.UpsertNode(100, node1); err != nil { 836 t.Fatalf("err: %v", err) 837 } 838 }) 839 840 // Upsert the node we are watching later 841 time.AfterFunc(200*time.Millisecond, func() { 842 if err := state.UpsertNode(200, node2); err != nil { 843 t.Fatalf("err: %v", err) 844 } 845 }) 846 847 // Lookup the node 848 req := &structs.NodeSpecificRequest{ 849 NodeID: node2.ID, 850 QueryOptions: structs.QueryOptions{ 851 Region: "global", 852 MinQueryIndex: 50, 853 }, 854 } 855 var resp structs.SingleNodeResponse 856 start := time.Now() 857 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp); err != nil { 858 t.Fatalf("err: %v", err) 859 } 860 861 if elapsed := time.Since(start); elapsed < 200*time.Millisecond { 862 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 863 } 864 if resp.Index != 200 { 865 t.Fatalf("Bad index: %d %d", resp.Index, 200) 866 } 867 if resp.Node == nil || resp.Node.ID != node2.ID { 868 t.Fatalf("bad: %#v", resp.Node) 869 } 870 871 // Node update triggers watches 872 time.AfterFunc(100*time.Millisecond, func() { 873 nodeUpdate := mock.Node() 874 nodeUpdate.ID = node2.ID 875 nodeUpdate.Status = structs.NodeStatusDown 876 if err := state.UpsertNode(300, nodeUpdate); err != nil { 877 t.Fatalf("err: %v", err) 878 } 879 }) 880 881 req.QueryOptions.MinQueryIndex = 250 882 var resp2 structs.SingleNodeResponse 883 start = time.Now() 884 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp2); err != nil { 885 t.Fatalf("err: %v", err) 886 } 887 888 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 889 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 890 } 891 if resp2.Index != 300 { 892 t.Fatalf("Bad index: %d %d", resp2.Index, 300) 893 } 894 if resp2.Node == nil || resp2.Node.Status != structs.NodeStatusDown { 895 t.Fatalf("bad: %#v", resp2.Node) 896 } 897 898 // Node delete triggers watches 899 time.AfterFunc(100*time.Millisecond, func() { 900 if err := state.DeleteNode(400, node2.ID); err != nil { 901 t.Fatalf("err: %v", err) 902 } 903 }) 904 905 req.QueryOptions.MinQueryIndex = 350 906 var resp3 structs.SingleNodeResponse 907 start = time.Now() 908 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp3); err != nil { 909 t.Fatalf("err: %v", err) 910 } 911 912 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 913 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 914 } 915 if resp3.Index != 400 { 916 t.Fatalf("Bad index: %d %d", resp2.Index, 400) 917 } 918 if resp3.Node != nil { 919 t.Fatalf("bad: %#v", resp3.Node) 920 } 921 } 922 923 func TestClientEndpoint_GetAllocs(t *testing.T) { 924 s1 := testServer(t, nil) 925 defer s1.Shutdown() 926 codec := rpcClient(t, s1) 927 testutil.WaitForLeader(t, s1.RPC) 928 929 // Create the register request 930 node := mock.Node() 931 reg := &structs.NodeRegisterRequest{ 932 Node: node, 933 WriteRequest: structs.WriteRequest{Region: "global"}, 934 } 935 936 // Fetch the response 937 var resp structs.GenericResponse 938 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 939 t.Fatalf("err: %v", err) 940 } 941 node.CreateIndex = resp.Index 942 node.ModifyIndex = resp.Index 943 944 // Inject fake evaluations 945 alloc := mock.Alloc() 946 alloc.NodeID = node.ID 947 state := s1.fsm.State() 948 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 949 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 950 if err != nil { 951 t.Fatalf("err: %v", err) 952 } 953 954 // Lookup the allocs 955 get := &structs.NodeSpecificRequest{ 956 NodeID: node.ID, 957 QueryOptions: structs.QueryOptions{Region: "global"}, 958 } 959 var resp2 structs.NodeAllocsResponse 960 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil { 961 t.Fatalf("err: %v", err) 962 } 963 if resp2.Index != 100 { 964 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 965 } 966 967 if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID { 968 t.Fatalf("bad: %#v", resp2.Allocs) 969 } 970 971 // Lookup non-existing node 972 get.NodeID = "foobarbaz" 973 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil { 974 t.Fatalf("err: %v", err) 975 } 976 if resp2.Index != 100 { 977 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 978 } 979 if len(resp2.Allocs) != 0 { 980 t.Fatalf("unexpected node") 981 } 982 } 983 984 func TestClientEndpoint_GetClientAllocs(t *testing.T) { 985 s1 := testServer(t, nil) 986 defer s1.Shutdown() 987 codec := rpcClient(t, s1) 988 testutil.WaitForLeader(t, s1.RPC) 989 990 // Create the register request 991 node := mock.Node() 992 reg := &structs.NodeRegisterRequest{ 993 Node: node, 994 WriteRequest: structs.WriteRequest{Region: "global"}, 995 } 996 997 // Fetch the response 998 var resp structs.GenericResponse 999 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1000 t.Fatalf("err: %v", err) 1001 } 1002 node.CreateIndex = resp.Index 1003 node.ModifyIndex = resp.Index 1004 1005 // Inject fake evaluations 1006 alloc := mock.Alloc() 1007 alloc.NodeID = node.ID 1008 state := s1.fsm.State() 1009 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1010 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1011 if err != nil { 1012 t.Fatalf("err: %v", err) 1013 } 1014 1015 // Lookup the allocs 1016 get := &structs.NodeSpecificRequest{ 1017 NodeID: node.ID, 1018 SecretID: node.SecretID, 1019 QueryOptions: structs.QueryOptions{Region: "global"}, 1020 } 1021 var resp2 structs.NodeClientAllocsResponse 1022 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp2); err != nil { 1023 t.Fatalf("err: %v", err) 1024 } 1025 if resp2.Index != 100 { 1026 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1027 } 1028 1029 if len(resp2.Allocs) != 1 || resp2.Allocs[alloc.ID] != 100 { 1030 t.Fatalf("bad: %#v", resp2.Allocs) 1031 } 1032 1033 // Lookup node with bad SecretID 1034 get.SecretID = "foobarbaz" 1035 var resp3 structs.NodeClientAllocsResponse 1036 err = msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp3) 1037 if err == nil || !strings.Contains(err.Error(), "does not match") { 1038 t.Fatalf("err: %v", err) 1039 } 1040 1041 // Lookup non-existing node 1042 get.NodeID = structs.GenerateUUID() 1043 var resp4 structs.NodeClientAllocsResponse 1044 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp4); err != nil { 1045 t.Fatalf("err: %v", err) 1046 } 1047 if resp4.Index != 100 { 1048 t.Fatalf("Bad index: %d %d", resp3.Index, 100) 1049 } 1050 if len(resp4.Allocs) != 0 { 1051 t.Fatalf("unexpected node %#v", resp3.Allocs) 1052 } 1053 } 1054 1055 func TestClientEndpoint_GetClientAllocs_Blocking(t *testing.T) { 1056 s1 := testServer(t, nil) 1057 defer s1.Shutdown() 1058 codec := rpcClient(t, s1) 1059 testutil.WaitForLeader(t, s1.RPC) 1060 1061 // Create the register request 1062 node := mock.Node() 1063 reg := &structs.NodeRegisterRequest{ 1064 Node: node, 1065 WriteRequest: structs.WriteRequest{Region: "global"}, 1066 } 1067 1068 // Fetch the response 1069 var resp structs.GenericResponse 1070 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1071 t.Fatalf("err: %v", err) 1072 } 1073 node.CreateIndex = resp.Index 1074 node.ModifyIndex = resp.Index 1075 1076 // Inject fake evaluations async 1077 alloc := mock.Alloc() 1078 alloc.NodeID = node.ID 1079 state := s1.fsm.State() 1080 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1081 start := time.Now() 1082 time.AfterFunc(100*time.Millisecond, func() { 1083 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1084 if err != nil { 1085 t.Fatalf("err: %v", err) 1086 } 1087 }) 1088 1089 // Lookup the allocs in a blocking query 1090 req := &structs.NodeSpecificRequest{ 1091 NodeID: node.ID, 1092 SecretID: node.SecretID, 1093 QueryOptions: structs.QueryOptions{ 1094 Region: "global", 1095 MinQueryIndex: 50, 1096 MaxQueryTime: time.Second, 1097 }, 1098 } 1099 var resp2 structs.NodeClientAllocsResponse 1100 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", req, &resp2); err != nil { 1101 t.Fatalf("err: %v", err) 1102 } 1103 1104 // Should block at least 100ms 1105 if time.Since(start) < 100*time.Millisecond { 1106 t.Fatalf("too fast") 1107 } 1108 1109 if resp2.Index != 100 { 1110 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1111 } 1112 1113 if len(resp2.Allocs) != 1 || resp2.Allocs[alloc.ID] != 100 { 1114 t.Fatalf("bad: %#v", resp2.Allocs) 1115 } 1116 1117 // Alloc updates fire watches 1118 time.AfterFunc(100*time.Millisecond, func() { 1119 allocUpdate := mock.Alloc() 1120 allocUpdate.NodeID = alloc.NodeID 1121 allocUpdate.ID = alloc.ID 1122 allocUpdate.ClientStatus = structs.AllocClientStatusRunning 1123 state.UpsertJobSummary(199, mock.JobSummary(allocUpdate.JobID)) 1124 err := state.UpsertAllocs(200, []*structs.Allocation{allocUpdate}) 1125 if err != nil { 1126 t.Fatalf("err: %v", err) 1127 } 1128 }) 1129 1130 req.QueryOptions.MinQueryIndex = 150 1131 var resp3 structs.NodeClientAllocsResponse 1132 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", req, &resp3); err != nil { 1133 t.Fatalf("err: %v", err) 1134 } 1135 1136 if time.Since(start) < 100*time.Millisecond { 1137 t.Fatalf("too fast") 1138 } 1139 if resp3.Index != 200 { 1140 t.Fatalf("Bad index: %d %d", resp3.Index, 200) 1141 } 1142 if len(resp3.Allocs) != 1 || resp3.Allocs[alloc.ID] != 200 { 1143 t.Fatalf("bad: %#v", resp3.Allocs) 1144 } 1145 } 1146 1147 func TestClientEndpoint_GetAllocs_Blocking(t *testing.T) { 1148 s1 := testServer(t, nil) 1149 defer s1.Shutdown() 1150 codec := rpcClient(t, s1) 1151 testutil.WaitForLeader(t, s1.RPC) 1152 1153 // Create the register request 1154 node := mock.Node() 1155 reg := &structs.NodeRegisterRequest{ 1156 Node: node, 1157 WriteRequest: structs.WriteRequest{Region: "global"}, 1158 } 1159 1160 // Fetch the response 1161 var resp structs.GenericResponse 1162 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1163 t.Fatalf("err: %v", err) 1164 } 1165 node.CreateIndex = resp.Index 1166 node.ModifyIndex = resp.Index 1167 1168 // Inject fake evaluations async 1169 alloc := mock.Alloc() 1170 alloc.NodeID = node.ID 1171 state := s1.fsm.State() 1172 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1173 start := time.Now() 1174 time.AfterFunc(100*time.Millisecond, func() { 1175 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1176 if err != nil { 1177 t.Fatalf("err: %v", err) 1178 } 1179 }) 1180 1181 // Lookup the allocs in a blocking query 1182 req := &structs.NodeSpecificRequest{ 1183 NodeID: node.ID, 1184 QueryOptions: structs.QueryOptions{ 1185 Region: "global", 1186 MinQueryIndex: 50, 1187 MaxQueryTime: time.Second, 1188 }, 1189 } 1190 var resp2 structs.NodeAllocsResponse 1191 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp2); err != nil { 1192 t.Fatalf("err: %v", err) 1193 } 1194 1195 // Should block at least 100ms 1196 if time.Since(start) < 100*time.Millisecond { 1197 t.Fatalf("too fast") 1198 } 1199 1200 if resp2.Index != 100 { 1201 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1202 } 1203 1204 if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID { 1205 t.Fatalf("bad: %#v", resp2.Allocs) 1206 } 1207 1208 // Alloc updates fire watches 1209 time.AfterFunc(100*time.Millisecond, func() { 1210 allocUpdate := mock.Alloc() 1211 allocUpdate.NodeID = alloc.NodeID 1212 allocUpdate.ID = alloc.ID 1213 allocUpdate.ClientStatus = structs.AllocClientStatusRunning 1214 state.UpsertJobSummary(199, mock.JobSummary(allocUpdate.JobID)) 1215 err := state.UpdateAllocsFromClient(200, []*structs.Allocation{allocUpdate}) 1216 if err != nil { 1217 t.Fatalf("err: %v", err) 1218 } 1219 }) 1220 1221 req.QueryOptions.MinQueryIndex = 150 1222 var resp3 structs.NodeAllocsResponse 1223 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp3); err != nil { 1224 t.Fatalf("err: %v", err) 1225 } 1226 1227 if time.Since(start) < 100*time.Millisecond { 1228 t.Fatalf("too fast") 1229 } 1230 if resp3.Index != 200 { 1231 t.Fatalf("Bad index: %d %d", resp3.Index, 200) 1232 } 1233 if len(resp3.Allocs) != 1 || resp3.Allocs[0].ClientStatus != structs.AllocClientStatusRunning { 1234 t.Fatalf("bad: %#v", resp3.Allocs[0]) 1235 } 1236 } 1237 1238 func TestClientEndpoint_UpdateAlloc(t *testing.T) { 1239 s1 := testServer(t, nil) 1240 defer s1.Shutdown() 1241 codec := rpcClient(t, s1) 1242 testutil.WaitForLeader(t, s1.RPC) 1243 1244 // Create the register request 1245 node := mock.Node() 1246 reg := &structs.NodeRegisterRequest{ 1247 Node: node, 1248 WriteRequest: structs.WriteRequest{Region: "global"}, 1249 } 1250 1251 // Fetch the response 1252 var resp structs.GenericResponse 1253 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1254 t.Fatalf("err: %v", err) 1255 } 1256 1257 // Inject fake evaluations 1258 alloc := mock.Alloc() 1259 alloc.NodeID = node.ID 1260 state := s1.fsm.State() 1261 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1262 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1263 if err != nil { 1264 t.Fatalf("err: %v", err) 1265 } 1266 1267 // Attempt update 1268 clientAlloc := new(structs.Allocation) 1269 *clientAlloc = *alloc 1270 clientAlloc.ClientStatus = structs.AllocClientStatusFailed 1271 1272 // Update the alloc 1273 update := &structs.AllocUpdateRequest{ 1274 Alloc: []*structs.Allocation{clientAlloc}, 1275 WriteRequest: structs.WriteRequest{Region: "global"}, 1276 } 1277 var resp2 structs.NodeAllocsResponse 1278 start := time.Now() 1279 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateAlloc", update, &resp2); err != nil { 1280 t.Fatalf("err: %v", err) 1281 } 1282 if resp2.Index == 0 { 1283 t.Fatalf("Bad index: %d", resp2.Index) 1284 } 1285 if diff := time.Since(start); diff < batchUpdateInterval { 1286 t.Fatalf("too fast: %v", diff) 1287 } 1288 1289 // Lookup the alloc 1290 out, err := state.AllocByID(alloc.ID) 1291 if err != nil { 1292 t.Fatalf("err: %v", err) 1293 } 1294 if out.ClientStatus != structs.AllocClientStatusFailed { 1295 t.Fatalf("Bad: %#v", out) 1296 } 1297 } 1298 1299 func TestClientEndpoint_BatchUpdate(t *testing.T) { 1300 s1 := testServer(t, nil) 1301 defer s1.Shutdown() 1302 codec := rpcClient(t, s1) 1303 testutil.WaitForLeader(t, s1.RPC) 1304 1305 // Create the register request 1306 node := mock.Node() 1307 reg := &structs.NodeRegisterRequest{ 1308 Node: node, 1309 WriteRequest: structs.WriteRequest{Region: "global"}, 1310 } 1311 1312 // Fetch the response 1313 var resp structs.GenericResponse 1314 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1315 t.Fatalf("err: %v", err) 1316 } 1317 1318 // Inject fake evaluations 1319 alloc := mock.Alloc() 1320 alloc.NodeID = node.ID 1321 state := s1.fsm.State() 1322 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1323 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1324 if err != nil { 1325 t.Fatalf("err: %v", err) 1326 } 1327 1328 // Attempt update 1329 clientAlloc := new(structs.Allocation) 1330 *clientAlloc = *alloc 1331 clientAlloc.ClientStatus = structs.AllocClientStatusFailed 1332 1333 // Call to do the batch update 1334 bf := NewBatchFuture() 1335 endpoint := s1.endpoints.Node 1336 endpoint.batchUpdate(bf, []*structs.Allocation{clientAlloc}) 1337 if err := bf.Wait(); err != nil { 1338 t.Fatalf("err: %v", err) 1339 } 1340 if bf.Index() == 0 { 1341 t.Fatalf("Bad index: %d", bf.Index()) 1342 } 1343 1344 // Lookup the alloc 1345 out, err := state.AllocByID(alloc.ID) 1346 if err != nil { 1347 t.Fatalf("err: %v", err) 1348 } 1349 if out.ClientStatus != structs.AllocClientStatusFailed { 1350 t.Fatalf("Bad: %#v", out) 1351 } 1352 } 1353 1354 func TestClientEndpoint_UpdateAlloc_Vault(t *testing.T) { 1355 s1 := testServer(t, nil) 1356 defer s1.Shutdown() 1357 codec := rpcClient(t, s1) 1358 testutil.WaitForLeader(t, s1.RPC) 1359 1360 // Create the register request 1361 node := mock.Node() 1362 reg := &structs.NodeRegisterRequest{ 1363 Node: node, 1364 WriteRequest: structs.WriteRequest{Region: "global"}, 1365 } 1366 1367 // Fetch the response 1368 var resp structs.GenericResponse 1369 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1370 t.Fatalf("err: %v", err) 1371 } 1372 1373 // Swap the servers Vault Client 1374 tvc := &TestVaultClient{} 1375 s1.vault = tvc 1376 1377 // Inject fake allocation and vault accessor 1378 alloc := mock.Alloc() 1379 alloc.NodeID = node.ID 1380 state := s1.fsm.State() 1381 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1382 if err := state.UpsertAllocs(100, []*structs.Allocation{alloc}); err != nil { 1383 t.Fatalf("err: %v", err) 1384 } 1385 1386 va := mock.VaultAccessor() 1387 va.NodeID = node.ID 1388 va.AllocID = alloc.ID 1389 if err := state.UpsertVaultAccessor(101, []*structs.VaultAccessor{va}); err != nil { 1390 t.Fatalf("err: %v", err) 1391 } 1392 1393 // Attempt update 1394 clientAlloc := new(structs.Allocation) 1395 *clientAlloc = *alloc 1396 clientAlloc.ClientStatus = structs.AllocClientStatusFailed 1397 1398 // Update the alloc 1399 update := &structs.AllocUpdateRequest{ 1400 Alloc: []*structs.Allocation{clientAlloc}, 1401 WriteRequest: structs.WriteRequest{Region: "global"}, 1402 } 1403 var resp2 structs.NodeAllocsResponse 1404 start := time.Now() 1405 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateAlloc", update, &resp2); err != nil { 1406 t.Fatalf("err: %v", err) 1407 } 1408 if resp2.Index == 0 { 1409 t.Fatalf("Bad index: %d", resp2.Index) 1410 } 1411 if diff := time.Since(start); diff < batchUpdateInterval { 1412 t.Fatalf("too fast: %v", diff) 1413 } 1414 1415 // Lookup the alloc 1416 out, err := state.AllocByID(alloc.ID) 1417 if err != nil { 1418 t.Fatalf("err: %v", err) 1419 } 1420 if out.ClientStatus != structs.AllocClientStatusFailed { 1421 t.Fatalf("Bad: %#v", out) 1422 } 1423 1424 if l := len(tvc.RevokedTokens); l != 1 { 1425 t.Fatalf("Deregister revoked %d tokens; want 1", l) 1426 } 1427 } 1428 1429 func TestClientEndpoint_CreateNodeEvals(t *testing.T) { 1430 s1 := testServer(t, nil) 1431 defer s1.Shutdown() 1432 testutil.WaitForLeader(t, s1.RPC) 1433 1434 // Inject fake evaluations 1435 alloc := mock.Alloc() 1436 state := s1.fsm.State() 1437 state.UpsertJobSummary(1, mock.JobSummary(alloc.JobID)) 1438 if err := state.UpsertAllocs(2, []*structs.Allocation{alloc}); err != nil { 1439 t.Fatalf("err: %v", err) 1440 } 1441 1442 // Inject a fake system job. 1443 job := mock.SystemJob() 1444 if err := state.UpsertJob(3, job); err != nil { 1445 t.Fatalf("err: %v", err) 1446 } 1447 1448 // Create some evaluations 1449 ids, index, err := s1.endpoints.Node.createNodeEvals(alloc.NodeID, 1) 1450 if err != nil { 1451 t.Fatalf("err: %v", err) 1452 } 1453 if index == 0 { 1454 t.Fatalf("bad: %d", index) 1455 } 1456 if len(ids) != 2 { 1457 t.Fatalf("bad: %s", ids) 1458 } 1459 1460 // Lookup the evaluations 1461 evalByType := make(map[string]*structs.Evaluation, 2) 1462 for _, id := range ids { 1463 eval, err := state.EvalByID(id) 1464 if err != nil { 1465 t.Fatalf("err: %v", err) 1466 } 1467 if eval == nil { 1468 t.Fatalf("expected eval") 1469 } 1470 1471 if old, ok := evalByType[eval.Type]; ok { 1472 t.Fatalf("multiple evals of the same type: %v and %v", old, eval) 1473 } 1474 1475 evalByType[eval.Type] = eval 1476 } 1477 1478 if len(evalByType) != 2 { 1479 t.Fatalf("Expected a service and system job; got %#v", evalByType) 1480 } 1481 1482 // Ensure the evals are correct. 1483 for schedType, eval := range evalByType { 1484 expPriority := alloc.Job.Priority 1485 expJobID := alloc.JobID 1486 if schedType == "system" { 1487 expPriority = job.Priority 1488 expJobID = job.ID 1489 } 1490 1491 if eval.CreateIndex != index { 1492 t.Fatalf("CreateIndex mis-match on type %v: %#v", schedType, eval) 1493 } 1494 if eval.TriggeredBy != structs.EvalTriggerNodeUpdate { 1495 t.Fatalf("TriggeredBy incorrect on type %v: %#v", schedType, eval) 1496 } 1497 if eval.NodeID != alloc.NodeID { 1498 t.Fatalf("NodeID incorrect on type %v: %#v", schedType, eval) 1499 } 1500 if eval.NodeModifyIndex != 1 { 1501 t.Fatalf("NodeModifyIndex incorrect on type %v: %#v", schedType, eval) 1502 } 1503 if eval.Status != structs.EvalStatusPending { 1504 t.Fatalf("Status incorrect on type %v: %#v", schedType, eval) 1505 } 1506 if eval.Priority != expPriority { 1507 t.Fatalf("Priority incorrect on type %v: %#v", schedType, eval) 1508 } 1509 if eval.JobID != expJobID { 1510 t.Fatalf("JobID incorrect on type %v: %#v", schedType, eval) 1511 } 1512 } 1513 } 1514 1515 func TestClientEndpoint_Evaluate(t *testing.T) { 1516 s1 := testServer(t, func(c *Config) { 1517 c.NumSchedulers = 0 // Prevent automatic dequeue 1518 }) 1519 defer s1.Shutdown() 1520 codec := rpcClient(t, s1) 1521 testutil.WaitForLeader(t, s1.RPC) 1522 1523 // Inject fake evaluations 1524 alloc := mock.Alloc() 1525 node := mock.Node() 1526 node.ID = alloc.NodeID 1527 state := s1.fsm.State() 1528 err := state.UpsertNode(1, node) 1529 if err != nil { 1530 t.Fatalf("err: %v", err) 1531 } 1532 state.UpsertJobSummary(2, mock.JobSummary(alloc.JobID)) 1533 err = state.UpsertAllocs(3, []*structs.Allocation{alloc}) 1534 if err != nil { 1535 t.Fatalf("err: %v", err) 1536 } 1537 1538 // Re-evaluate 1539 req := &structs.NodeEvaluateRequest{ 1540 NodeID: alloc.NodeID, 1541 WriteRequest: structs.WriteRequest{Region: "global"}, 1542 } 1543 1544 // Fetch the response 1545 var resp structs.NodeUpdateResponse 1546 if err := msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp); err != nil { 1547 t.Fatalf("err: %v", err) 1548 } 1549 if resp.Index == 0 { 1550 t.Fatalf("bad index: %d", resp.Index) 1551 } 1552 1553 // Create some evaluations 1554 ids := resp.EvalIDs 1555 if len(ids) != 1 { 1556 t.Fatalf("bad: %s", ids) 1557 } 1558 1559 // Lookup the evaluation 1560 eval, err := state.EvalByID(ids[0]) 1561 if err != nil { 1562 t.Fatalf("err: %v", err) 1563 } 1564 if eval == nil { 1565 t.Fatalf("expected eval") 1566 } 1567 if eval.CreateIndex != resp.Index { 1568 t.Fatalf("index mis-match") 1569 } 1570 1571 if eval.Priority != alloc.Job.Priority { 1572 t.Fatalf("bad: %#v", eval) 1573 } 1574 if eval.Type != alloc.Job.Type { 1575 t.Fatalf("bad: %#v", eval) 1576 } 1577 if eval.TriggeredBy != structs.EvalTriggerNodeUpdate { 1578 t.Fatalf("bad: %#v", eval) 1579 } 1580 if eval.JobID != alloc.JobID { 1581 t.Fatalf("bad: %#v", eval) 1582 } 1583 if eval.NodeID != alloc.NodeID { 1584 t.Fatalf("bad: %#v", eval) 1585 } 1586 if eval.NodeModifyIndex != 1 { 1587 t.Fatalf("bad: %#v", eval) 1588 } 1589 if eval.Status != structs.EvalStatusPending { 1590 t.Fatalf("bad: %#v", eval) 1591 } 1592 } 1593 1594 func TestClientEndpoint_ListNodes(t *testing.T) { 1595 s1 := testServer(t, nil) 1596 defer s1.Shutdown() 1597 codec := rpcClient(t, s1) 1598 testutil.WaitForLeader(t, s1.RPC) 1599 1600 // Create the register request 1601 node := mock.Node() 1602 reg := &structs.NodeRegisterRequest{ 1603 Node: node, 1604 WriteRequest: structs.WriteRequest{Region: "global"}, 1605 } 1606 1607 // Fetch the response 1608 var resp structs.GenericResponse 1609 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1610 t.Fatalf("err: %v", err) 1611 } 1612 node.CreateIndex = resp.Index 1613 node.ModifyIndex = resp.Index 1614 1615 // Lookup the node 1616 get := &structs.NodeListRequest{ 1617 QueryOptions: structs.QueryOptions{Region: "global"}, 1618 } 1619 var resp2 structs.NodeListResponse 1620 if err := msgpackrpc.CallWithCodec(codec, "Node.List", get, &resp2); err != nil { 1621 t.Fatalf("err: %v", err) 1622 } 1623 if resp2.Index != resp.Index { 1624 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 1625 } 1626 1627 if len(resp2.Nodes) != 1 { 1628 t.Fatalf("bad: %#v", resp2.Nodes) 1629 } 1630 if resp2.Nodes[0].ID != node.ID { 1631 t.Fatalf("bad: %#v", resp2.Nodes[0]) 1632 } 1633 1634 // Lookup the node with prefix 1635 get = &structs.NodeListRequest{ 1636 QueryOptions: structs.QueryOptions{Region: "global", Prefix: node.ID[:4]}, 1637 } 1638 var resp3 structs.NodeListResponse 1639 if err := msgpackrpc.CallWithCodec(codec, "Node.List", get, &resp3); err != nil { 1640 t.Fatalf("err: %v", err) 1641 } 1642 if resp3.Index != resp.Index { 1643 t.Fatalf("Bad index: %d %d", resp3.Index, resp2.Index) 1644 } 1645 1646 if len(resp3.Nodes) != 1 { 1647 t.Fatalf("bad: %#v", resp3.Nodes) 1648 } 1649 if resp3.Nodes[0].ID != node.ID { 1650 t.Fatalf("bad: %#v", resp3.Nodes[0]) 1651 } 1652 } 1653 1654 func TestClientEndpoint_ListNodes_Blocking(t *testing.T) { 1655 s1 := testServer(t, nil) 1656 defer s1.Shutdown() 1657 state := s1.fsm.State() 1658 codec := rpcClient(t, s1) 1659 testutil.WaitForLeader(t, s1.RPC) 1660 1661 // Create the node 1662 node := mock.Node() 1663 1664 // Node upsert triggers watches 1665 time.AfterFunc(100*time.Millisecond, func() { 1666 if err := state.UpsertNode(2, node); err != nil { 1667 t.Fatalf("err: %v", err) 1668 } 1669 }) 1670 1671 req := &structs.NodeListRequest{ 1672 QueryOptions: structs.QueryOptions{ 1673 Region: "global", 1674 MinQueryIndex: 1, 1675 }, 1676 } 1677 start := time.Now() 1678 var resp structs.NodeListResponse 1679 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp); err != nil { 1680 t.Fatalf("err: %v", err) 1681 } 1682 1683 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 1684 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 1685 } 1686 if resp.Index != 2 { 1687 t.Fatalf("Bad index: %d %d", resp.Index, 2) 1688 } 1689 if len(resp.Nodes) != 1 || resp.Nodes[0].ID != node.ID { 1690 t.Fatalf("bad: %#v", resp.Nodes) 1691 } 1692 1693 // Node drain updates trigger watches. 1694 time.AfterFunc(100*time.Millisecond, func() { 1695 if err := state.UpdateNodeDrain(3, node.ID, true); err != nil { 1696 t.Fatalf("err: %v", err) 1697 } 1698 }) 1699 1700 req.MinQueryIndex = 2 1701 var resp2 structs.NodeListResponse 1702 start = time.Now() 1703 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp2); err != nil { 1704 t.Fatalf("err: %v", err) 1705 } 1706 1707 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 1708 t.Fatalf("should block (returned in %s) %#v", elapsed, resp2) 1709 } 1710 if resp2.Index != 3 { 1711 t.Fatalf("Bad index: %d %d", resp2.Index, 3) 1712 } 1713 if len(resp2.Nodes) != 1 || !resp2.Nodes[0].Drain { 1714 t.Fatalf("bad: %#v", resp2.Nodes) 1715 } 1716 1717 // Node status update triggers watches 1718 time.AfterFunc(100*time.Millisecond, func() { 1719 if err := state.UpdateNodeStatus(4, node.ID, structs.NodeStatusDown); err != nil { 1720 t.Fatalf("err: %v", err) 1721 } 1722 }) 1723 1724 req.MinQueryIndex = 3 1725 var resp3 structs.NodeListResponse 1726 start = time.Now() 1727 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp3); err != nil { 1728 t.Fatalf("err: %v", err) 1729 } 1730 1731 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 1732 t.Fatalf("should block (returned in %s) %#v", elapsed, resp3) 1733 } 1734 if resp3.Index != 4 { 1735 t.Fatalf("Bad index: %d %d", resp3.Index, 4) 1736 } 1737 if len(resp3.Nodes) != 1 || resp3.Nodes[0].Status != structs.NodeStatusDown { 1738 t.Fatalf("bad: %#v", resp3.Nodes) 1739 } 1740 1741 // Node delete triggers watches. 1742 time.AfterFunc(100*time.Millisecond, func() { 1743 if err := state.DeleteNode(5, node.ID); err != nil { 1744 t.Fatalf("err: %v", err) 1745 } 1746 }) 1747 1748 req.MinQueryIndex = 4 1749 var resp4 structs.NodeListResponse 1750 start = time.Now() 1751 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp4); err != nil { 1752 t.Fatalf("err: %v", err) 1753 } 1754 1755 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 1756 t.Fatalf("should block (returned in %s) %#v", elapsed, resp4) 1757 } 1758 if resp4.Index != 5 { 1759 t.Fatalf("Bad index: %d %d", resp4.Index, 5) 1760 } 1761 if len(resp4.Nodes) != 0 { 1762 t.Fatalf("bad: %#v", resp4.Nodes) 1763 } 1764 } 1765 1766 func TestBatchFuture(t *testing.T) { 1767 bf := NewBatchFuture() 1768 1769 // Async respond to the future 1770 expect := fmt.Errorf("testing") 1771 go func() { 1772 time.Sleep(10 * time.Millisecond) 1773 bf.Respond(1000, expect) 1774 }() 1775 1776 // Block for the result 1777 start := time.Now() 1778 err := bf.Wait() 1779 diff := time.Since(start) 1780 if diff < 5*time.Millisecond { 1781 t.Fatalf("too fast") 1782 } 1783 1784 // Check the results 1785 if err != expect { 1786 t.Fatalf("bad: %s", err) 1787 } 1788 if bf.Index() != 1000 { 1789 t.Fatalf("bad: %d", bf.Index()) 1790 } 1791 } 1792 1793 func TestClientEndpoint_DeriveVaultToken_Bad(t *testing.T) { 1794 s1 := testServer(t, nil) 1795 defer s1.Shutdown() 1796 state := s1.fsm.State() 1797 codec := rpcClient(t, s1) 1798 testutil.WaitForLeader(t, s1.RPC) 1799 1800 // Create the node 1801 node := mock.Node() 1802 if err := state.UpsertNode(2, node); err != nil { 1803 t.Fatalf("err: %v", err) 1804 } 1805 1806 // Create an alloc 1807 alloc := mock.Alloc() 1808 task := alloc.Job.TaskGroups[0].Tasks[0] 1809 tasks := []string{task.Name} 1810 if err := state.UpsertAllocs(3, []*structs.Allocation{alloc}); err != nil { 1811 t.Fatalf("err: %v", err) 1812 } 1813 1814 req := &structs.DeriveVaultTokenRequest{ 1815 NodeID: node.ID, 1816 SecretID: structs.GenerateUUID(), 1817 AllocID: alloc.ID, 1818 Tasks: tasks, 1819 QueryOptions: structs.QueryOptions{ 1820 Region: "global", 1821 }, 1822 } 1823 1824 var resp structs.DeriveVaultTokenResponse 1825 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 1826 t.Fatalf("bad: %v", err) 1827 } 1828 1829 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "SecretID mismatch") { 1830 t.Fatalf("Expected SecretID mismatch: %v", resp.Error) 1831 } 1832 1833 // Put the correct SecretID 1834 req.SecretID = node.SecretID 1835 1836 // Now we should get an error about the allocation not running on the node 1837 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 1838 t.Fatalf("bad: %v", err) 1839 } 1840 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "not running on Node") { 1841 t.Fatalf("Expected not running on node error: %v", resp.Error) 1842 } 1843 1844 // Update to be running on the node 1845 alloc.NodeID = node.ID 1846 if err := state.UpsertAllocs(4, []*structs.Allocation{alloc}); err != nil { 1847 t.Fatalf("err: %v", err) 1848 } 1849 1850 // Now we should get an error about the job not needing any Vault secrets 1851 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 1852 t.Fatalf("bad: %v", err) 1853 } 1854 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "does not require") { 1855 t.Fatalf("Expected no policies error: %v", resp.Error) 1856 } 1857 1858 // Update to be terminal 1859 alloc.DesiredStatus = structs.AllocDesiredStatusStop 1860 if err := state.UpsertAllocs(5, []*structs.Allocation{alloc}); err != nil { 1861 t.Fatalf("err: %v", err) 1862 } 1863 1864 // Now we should get an error about the job not needing any Vault secrets 1865 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 1866 t.Fatalf("bad: %v", err) 1867 } 1868 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "terminal") { 1869 t.Fatalf("Expected terminal allocation error: %v", resp.Error) 1870 } 1871 } 1872 1873 func TestClientEndpoint_DeriveVaultToken(t *testing.T) { 1874 s1 := testServer(t, nil) 1875 defer s1.Shutdown() 1876 state := s1.fsm.State() 1877 codec := rpcClient(t, s1) 1878 testutil.WaitForLeader(t, s1.RPC) 1879 1880 // Enable vault and allow authenticated 1881 tr := true 1882 s1.config.VaultConfig.Enabled = &tr 1883 s1.config.VaultConfig.AllowUnauthenticated = &tr 1884 1885 // Replace the Vault Client on the server 1886 tvc := &TestVaultClient{} 1887 s1.vault = tvc 1888 1889 // Create the node 1890 node := mock.Node() 1891 if err := state.UpsertNode(2, node); err != nil { 1892 t.Fatalf("err: %v", err) 1893 } 1894 1895 // Create an alloc an allocation that has vault policies required 1896 alloc := mock.Alloc() 1897 alloc.NodeID = node.ID 1898 task := alloc.Job.TaskGroups[0].Tasks[0] 1899 tasks := []string{task.Name} 1900 task.Vault = &structs.Vault{Policies: []string{"a", "b"}} 1901 if err := state.UpsertAllocs(3, []*structs.Allocation{alloc}); err != nil { 1902 t.Fatalf("err: %v", err) 1903 } 1904 1905 // Return a secret for the task 1906 token := structs.GenerateUUID() 1907 accessor := structs.GenerateUUID() 1908 ttl := 10 1909 secret := &vapi.Secret{ 1910 WrapInfo: &vapi.SecretWrapInfo{ 1911 Token: token, 1912 WrappedAccessor: accessor, 1913 TTL: ttl, 1914 }, 1915 } 1916 tvc.SetCreateTokenSecret(alloc.ID, task.Name, secret) 1917 1918 req := &structs.DeriveVaultTokenRequest{ 1919 NodeID: node.ID, 1920 SecretID: node.SecretID, 1921 AllocID: alloc.ID, 1922 Tasks: tasks, 1923 QueryOptions: structs.QueryOptions{ 1924 Region: "global", 1925 }, 1926 } 1927 1928 var resp structs.DeriveVaultTokenResponse 1929 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 1930 t.Fatalf("bad: %v", err) 1931 } 1932 if resp.Error != nil { 1933 t.Fatalf("bad: %v", resp.Error) 1934 } 1935 1936 // Check the state store and ensure that we created a VaultAccessor 1937 va, err := state.VaultAccessor(accessor) 1938 if err != nil { 1939 t.Fatalf("bad: %v", err) 1940 } 1941 if va == nil { 1942 t.Fatalf("bad: %v", va) 1943 } 1944 1945 if va.CreateIndex == 0 { 1946 t.Fatalf("bad: %v", va) 1947 } 1948 1949 va.CreateIndex = 0 1950 expected := &structs.VaultAccessor{ 1951 AllocID: alloc.ID, 1952 Task: task.Name, 1953 NodeID: alloc.NodeID, 1954 Accessor: accessor, 1955 CreationTTL: ttl, 1956 } 1957 1958 if !reflect.DeepEqual(expected, va) { 1959 t.Fatalf("Got %#v; want %#v", va, expected) 1960 } 1961 } 1962 1963 func TestClientEndpoint_DeriveVaultToken_VaultError(t *testing.T) { 1964 s1 := testServer(t, nil) 1965 defer s1.Shutdown() 1966 state := s1.fsm.State() 1967 codec := rpcClient(t, s1) 1968 testutil.WaitForLeader(t, s1.RPC) 1969 1970 // Enable vault and allow authenticated 1971 tr := true 1972 s1.config.VaultConfig.Enabled = &tr 1973 s1.config.VaultConfig.AllowUnauthenticated = &tr 1974 1975 // Replace the Vault Client on the server 1976 tvc := &TestVaultClient{} 1977 s1.vault = tvc 1978 1979 // Create the node 1980 node := mock.Node() 1981 if err := state.UpsertNode(2, node); err != nil { 1982 t.Fatalf("err: %v", err) 1983 } 1984 1985 // Create an alloc an allocation that has vault policies required 1986 alloc := mock.Alloc() 1987 alloc.NodeID = node.ID 1988 task := alloc.Job.TaskGroups[0].Tasks[0] 1989 tasks := []string{task.Name} 1990 task.Vault = &structs.Vault{Policies: []string{"a", "b"}} 1991 if err := state.UpsertAllocs(3, []*structs.Allocation{alloc}); err != nil { 1992 t.Fatalf("err: %v", err) 1993 } 1994 1995 // Return an error when creating the token 1996 tvc.SetCreateTokenError(alloc.ID, task.Name, 1997 structs.NewRecoverableError(fmt.Errorf("recover"), true)) 1998 1999 req := &structs.DeriveVaultTokenRequest{ 2000 NodeID: node.ID, 2001 SecretID: node.SecretID, 2002 AllocID: alloc.ID, 2003 Tasks: tasks, 2004 QueryOptions: structs.QueryOptions{ 2005 Region: "global", 2006 }, 2007 } 2008 2009 var resp structs.DeriveVaultTokenResponse 2010 err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp) 2011 if err != nil { 2012 t.Fatalf("bad: %v", err) 2013 } 2014 if resp.Error == nil || !resp.Error.Recoverable { 2015 t.Fatalf("bad: %+v", resp.Error) 2016 } 2017 }