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