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