github.com/zoomfoo/nomad@v0.8.5-0.20180907175415-f28fd3a1a056/nomad/node_endpoint_test.go (about) 1 package nomad 2 3 import ( 4 "fmt" 5 "net" 6 "reflect" 7 "strings" 8 "testing" 9 "time" 10 11 memdb "github.com/hashicorp/go-memdb" 12 "github.com/hashicorp/net-rpc-msgpackrpc" 13 "github.com/hashicorp/nomad/acl" 14 "github.com/hashicorp/nomad/helper/uuid" 15 "github.com/hashicorp/nomad/nomad/mock" 16 "github.com/hashicorp/nomad/nomad/state" 17 "github.com/hashicorp/nomad/nomad/structs" 18 "github.com/hashicorp/nomad/testutil" 19 vapi "github.com/hashicorp/vault/api" 20 "github.com/stretchr/testify/assert" 21 "github.com/stretchr/testify/require" 22 ) 23 24 func TestClientEndpoint_Register(t *testing.T) { 25 t.Parallel() 26 require := require.New(t) 27 s1 := TestServer(t, nil) 28 defer s1.Shutdown() 29 codec := rpcClient(t, s1) 30 testutil.WaitForLeader(t, s1.RPC) 31 32 // Check that we have no client connections 33 require.Empty(s1.connectedNodes()) 34 35 // Create the register request 36 node := mock.Node() 37 req := &structs.NodeRegisterRequest{ 38 Node: node, 39 WriteRequest: structs.WriteRequest{Region: "global"}, 40 } 41 42 // Fetch the response 43 var resp structs.GenericResponse 44 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil { 45 t.Fatalf("err: %v", err) 46 } 47 if resp.Index == 0 { 48 t.Fatalf("bad index: %d", resp.Index) 49 } 50 51 // Check that we have the client connections 52 nodes := s1.connectedNodes() 53 require.Len(nodes, 1) 54 require.Contains(nodes, node.ID) 55 56 // Check for the node in the FSM 57 state := s1.fsm.State() 58 ws := memdb.NewWatchSet() 59 out, err := state.NodeByID(ws, node.ID) 60 if err != nil { 61 t.Fatalf("err: %v", err) 62 } 63 if out == nil { 64 t.Fatalf("expected node") 65 } 66 if out.CreateIndex != resp.Index { 67 t.Fatalf("index mis-match") 68 } 69 if out.ComputedClass == "" { 70 t.Fatal("ComputedClass not set") 71 } 72 73 // Close the connection and check that we remove the client connections 74 require.Nil(codec.Close()) 75 testutil.WaitForResult(func() (bool, error) { 76 nodes := s1.connectedNodes() 77 return len(nodes) == 0, nil 78 }, func(err error) { 79 t.Fatalf("should have no clients") 80 }) 81 } 82 83 // This test asserts that we only track node connections if they are not from 84 // forwarded RPCs. This is essential otherwise we will think a Yamux session to 85 // a Nomad server is actually the session to the node. 86 func TestClientEndpoint_Register_NodeConn_Forwarded(t *testing.T) { 87 t.Parallel() 88 require := require.New(t) 89 s1 := TestServer(t, func(c *Config) { 90 c.BootstrapExpect = 2 91 }) 92 93 defer s1.Shutdown() 94 s2 := TestServer(t, func(c *Config) { 95 c.DevDisableBootstrap = true 96 }) 97 defer s2.Shutdown() 98 TestJoin(t, s1, s2) 99 testutil.WaitForLeader(t, s1.RPC) 100 testutil.WaitForLeader(t, s2.RPC) 101 102 // Determine the non-leader server 103 var leader, nonLeader *Server 104 if s1.IsLeader() { 105 leader = s1 106 nonLeader = s2 107 } else { 108 leader = s2 109 nonLeader = s1 110 } 111 112 // Send the requests to the non-leader 113 codec := rpcClient(t, nonLeader) 114 115 // Check that we have no client connections 116 require.Empty(nonLeader.connectedNodes()) 117 require.Empty(leader.connectedNodes()) 118 119 // Create the register request 120 node := mock.Node() 121 req := &structs.NodeRegisterRequest{ 122 Node: node, 123 WriteRequest: structs.WriteRequest{Region: "global"}, 124 } 125 126 // Fetch the response 127 var resp structs.GenericResponse 128 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp); err != nil { 129 t.Fatalf("err: %v", err) 130 } 131 if resp.Index == 0 { 132 t.Fatalf("bad index: %d", resp.Index) 133 } 134 135 // Check that we have the client connections on the non leader 136 nodes := nonLeader.connectedNodes() 137 require.Len(nodes, 1) 138 require.Contains(nodes, node.ID) 139 140 // Check that we have no client connections on the leader 141 nodes = leader.connectedNodes() 142 require.Empty(nodes) 143 144 // Check for the node in the FSM 145 state := leader.State() 146 testutil.WaitForResult(func() (bool, error) { 147 out, err := state.NodeByID(nil, node.ID) 148 if err != nil { 149 return false, err 150 } 151 if out == nil { 152 return false, fmt.Errorf("expected node") 153 } 154 if out.CreateIndex != resp.Index { 155 return false, fmt.Errorf("index mis-match") 156 } 157 if out.ComputedClass == "" { 158 return false, fmt.Errorf("ComputedClass not set") 159 } 160 161 return true, nil 162 }, func(err error) { 163 t.Fatalf("err: %v", err) 164 }) 165 166 // Close the connection and check that we remove the client connections 167 require.Nil(codec.Close()) 168 testutil.WaitForResult(func() (bool, error) { 169 nodes := nonLeader.connectedNodes() 170 return len(nodes) == 0, nil 171 }, func(err error) { 172 t.Fatalf("should have no clients") 173 }) 174 } 175 176 func TestClientEndpoint_Register_SecretMismatch(t *testing.T) { 177 t.Parallel() 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 req := &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", req, &resp); err != nil { 193 t.Fatalf("err: %v", err) 194 } 195 196 // Update the nodes SecretID 197 node.SecretID = uuid.Generate() 198 err := msgpackrpc.CallWithCodec(codec, "Node.Register", req, &resp) 199 if err == nil || !strings.Contains(err.Error(), "Not registering") { 200 t.Fatalf("Expecting error regarding mismatching secret id: %v", err) 201 } 202 } 203 204 func TestClientEndpoint_Deregister(t *testing.T) { 205 t.Parallel() 206 s1 := TestServer(t, nil) 207 defer s1.Shutdown() 208 codec := rpcClient(t, s1) 209 testutil.WaitForLeader(t, s1.RPC) 210 211 // Create the register request 212 node := mock.Node() 213 reg := &structs.NodeRegisterRequest{ 214 Node: node, 215 WriteRequest: structs.WriteRequest{Region: "global"}, 216 } 217 218 // Fetch the response 219 var resp structs.GenericResponse 220 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 221 t.Fatalf("err: %v", err) 222 } 223 224 // Deregister 225 dereg := &structs.NodeDeregisterRequest{ 226 NodeID: node.ID, 227 WriteRequest: structs.WriteRequest{Region: "global"}, 228 } 229 var resp2 structs.GenericResponse 230 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp2); err != nil { 231 t.Fatalf("err: %v", err) 232 } 233 if resp2.Index == 0 { 234 t.Fatalf("bad index: %d", resp2.Index) 235 } 236 237 // Check for the node in the FSM 238 state := s1.fsm.State() 239 ws := memdb.NewWatchSet() 240 out, err := state.NodeByID(ws, node.ID) 241 if err != nil { 242 t.Fatalf("err: %v", err) 243 } 244 if out != nil { 245 t.Fatalf("unexpected node") 246 } 247 } 248 249 func TestClientEndpoint_Deregister_ACL(t *testing.T) { 250 t.Parallel() 251 s1, root := TestACLServer(t, nil) 252 defer s1.Shutdown() 253 codec := rpcClient(t, s1) 254 testutil.WaitForLeader(t, s1.RPC) 255 256 // Create the node 257 node := mock.Node() 258 node1 := mock.Node() 259 state := s1.fsm.State() 260 if err := state.UpsertNode(1, node); err != nil { 261 t.Fatalf("err: %v", err) 262 } 263 if err := state.UpsertNode(2, node1); err != nil { 264 t.Fatalf("err: %v", err) 265 } 266 267 // Create the policy and tokens 268 validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid", mock.NodePolicy(acl.PolicyWrite)) 269 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", mock.NodePolicy(acl.PolicyRead)) 270 271 // Deregister without any token and expect it to fail 272 dereg := &structs.NodeDeregisterRequest{ 273 NodeID: node.ID, 274 WriteRequest: structs.WriteRequest{Region: "global"}, 275 } 276 var resp structs.GenericResponse 277 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp); err == nil { 278 t.Fatalf("node de-register succeeded") 279 } 280 281 // Deregister with a valid token 282 dereg.AuthToken = validToken.SecretID 283 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp); err != nil { 284 t.Fatalf("err: %v", err) 285 } 286 287 // Check for the node in the FSM 288 ws := memdb.NewWatchSet() 289 out, err := state.NodeByID(ws, node.ID) 290 if err != nil { 291 t.Fatalf("err: %v", err) 292 } 293 if out != nil { 294 t.Fatalf("unexpected node") 295 } 296 297 // Deregister with an invalid token. 298 dereg1 := &structs.NodeDeregisterRequest{ 299 NodeID: node1.ID, 300 WriteRequest: structs.WriteRequest{Region: "global"}, 301 } 302 dereg1.AuthToken = invalidToken.SecretID 303 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg1, &resp); err == nil { 304 t.Fatalf("rpc should not have succeeded") 305 } 306 307 // Try with a root token 308 dereg1.AuthToken = root.SecretID 309 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg1, &resp); err != nil { 310 t.Fatalf("err: %v", err) 311 } 312 } 313 314 func TestClientEndpoint_Deregister_Vault(t *testing.T) { 315 t.Parallel() 316 s1 := TestServer(t, nil) 317 defer s1.Shutdown() 318 codec := rpcClient(t, s1) 319 testutil.WaitForLeader(t, s1.RPC) 320 321 // Create the register request 322 node := mock.Node() 323 reg := &structs.NodeRegisterRequest{ 324 Node: node, 325 WriteRequest: structs.WriteRequest{Region: "global"}, 326 } 327 328 // Fetch the response 329 var resp structs.GenericResponse 330 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 331 t.Fatalf("err: %v", err) 332 } 333 334 // Swap the servers Vault Client 335 tvc := &TestVaultClient{} 336 s1.vault = tvc 337 338 // Put some Vault accessors in the state store for that node 339 state := s1.fsm.State() 340 va1 := mock.VaultAccessor() 341 va1.NodeID = node.ID 342 va2 := mock.VaultAccessor() 343 va2.NodeID = node.ID 344 state.UpsertVaultAccessor(100, []*structs.VaultAccessor{va1, va2}) 345 346 // Deregister 347 dereg := &structs.NodeDeregisterRequest{ 348 NodeID: node.ID, 349 WriteRequest: structs.WriteRequest{Region: "global"}, 350 } 351 var resp2 structs.GenericResponse 352 if err := msgpackrpc.CallWithCodec(codec, "Node.Deregister", dereg, &resp2); err != nil { 353 t.Fatalf("err: %v", err) 354 } 355 if resp2.Index == 0 { 356 t.Fatalf("bad index: %d", resp2.Index) 357 } 358 359 // Check for the node in the FSM 360 ws := memdb.NewWatchSet() 361 out, err := state.NodeByID(ws, node.ID) 362 if err != nil { 363 t.Fatalf("err: %v", err) 364 } 365 if out != nil { 366 t.Fatalf("unexpected node") 367 } 368 369 // Check that the endpoint revoked the tokens 370 if l := len(tvc.RevokedTokens); l != 2 { 371 t.Fatalf("Deregister revoked %d tokens; want 2", l) 372 } 373 } 374 375 func TestClientEndpoint_UpdateStatus(t *testing.T) { 376 t.Parallel() 377 require := require.New(t) 378 s1 := TestServer(t, nil) 379 defer s1.Shutdown() 380 codec := rpcClient(t, s1) 381 testutil.WaitForLeader(t, s1.RPC) 382 383 // Check that we have no client connections 384 require.Empty(s1.connectedNodes()) 385 386 // Create the register request 387 node := mock.Node() 388 reg := &structs.NodeRegisterRequest{ 389 Node: node, 390 WriteRequest: structs.WriteRequest{Region: "global"}, 391 } 392 393 // Fetch the response 394 var resp structs.NodeUpdateResponse 395 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 396 t.Fatalf("err: %v", err) 397 } 398 399 // Check for heartbeat interval 400 ttl := resp.HeartbeatTTL 401 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 402 t.Fatalf("bad: %#v", ttl) 403 } 404 405 // Update the status 406 dereg := &structs.NodeUpdateStatusRequest{ 407 NodeID: node.ID, 408 Status: structs.NodeStatusInit, 409 WriteRequest: structs.WriteRequest{Region: "global"}, 410 } 411 var resp2 structs.NodeUpdateResponse 412 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 413 t.Fatalf("err: %v", err) 414 } 415 if resp2.Index == 0 { 416 t.Fatalf("bad index: %d", resp2.Index) 417 } 418 419 // Check for heartbeat interval 420 ttl = resp2.HeartbeatTTL 421 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 422 t.Fatalf("bad: %#v", ttl) 423 } 424 425 // Check that we have the client connections 426 nodes := s1.connectedNodes() 427 require.Len(nodes, 1) 428 require.Contains(nodes, node.ID) 429 430 // Check for the node in the FSM 431 state := s1.fsm.State() 432 ws := memdb.NewWatchSet() 433 out, err := state.NodeByID(ws, node.ID) 434 if err != nil { 435 t.Fatalf("err: %v", err) 436 } 437 if out == nil { 438 t.Fatalf("expected node") 439 } 440 if out.ModifyIndex != resp2.Index { 441 t.Fatalf("index mis-match") 442 } 443 444 // Close the connection and check that we remove the client connections 445 require.Nil(codec.Close()) 446 testutil.WaitForResult(func() (bool, error) { 447 nodes := s1.connectedNodes() 448 return len(nodes) == 0, nil 449 }, func(err error) { 450 t.Fatalf("should have no clients") 451 }) 452 } 453 454 func TestClientEndpoint_UpdateStatus_Vault(t *testing.T) { 455 t.Parallel() 456 s1 := TestServer(t, nil) 457 defer s1.Shutdown() 458 codec := rpcClient(t, s1) 459 testutil.WaitForLeader(t, s1.RPC) 460 461 // Create the register request 462 node := mock.Node() 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 // Swap the servers Vault Client 481 tvc := &TestVaultClient{} 482 s1.vault = tvc 483 484 // Put some Vault accessors in the state store for that node 485 state := s1.fsm.State() 486 va1 := mock.VaultAccessor() 487 va1.NodeID = node.ID 488 va2 := mock.VaultAccessor() 489 va2.NodeID = node.ID 490 state.UpsertVaultAccessor(100, []*structs.VaultAccessor{va1, va2}) 491 492 // Update the status to be down 493 dereg := &structs.NodeUpdateStatusRequest{ 494 NodeID: node.ID, 495 Status: structs.NodeStatusDown, 496 WriteRequest: structs.WriteRequest{Region: "global"}, 497 } 498 var resp2 structs.NodeUpdateResponse 499 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 500 t.Fatalf("err: %v", err) 501 } 502 if resp2.Index == 0 { 503 t.Fatalf("bad index: %d", resp2.Index) 504 } 505 506 // Check that the endpoint revoked the tokens 507 if l := len(tvc.RevokedTokens); l != 2 { 508 t.Fatalf("Deregister revoked %d tokens; want 2", l) 509 } 510 } 511 512 func TestClientEndpoint_UpdateStatus_HeartbeatRecovery(t *testing.T) { 513 t.Parallel() 514 require := require.New(t) 515 s1 := TestServer(t, nil) 516 defer s1.Shutdown() 517 codec := rpcClient(t, s1) 518 testutil.WaitForLeader(t, s1.RPC) 519 520 // Check that we have no client connections 521 require.Empty(s1.connectedNodes()) 522 523 // Create the register request but make the node down 524 node := mock.Node() 525 node.Status = structs.NodeStatusDown 526 reg := &structs.NodeRegisterRequest{ 527 Node: node, 528 WriteRequest: structs.WriteRequest{Region: "global"}, 529 } 530 531 // Fetch the response 532 var resp structs.NodeUpdateResponse 533 require.NoError(msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp)) 534 535 // Update the status 536 dereg := &structs.NodeUpdateStatusRequest{ 537 NodeID: node.ID, 538 Status: structs.NodeStatusInit, 539 WriteRequest: structs.WriteRequest{Region: "global"}, 540 } 541 var resp2 structs.NodeUpdateResponse 542 require.NoError(msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2)) 543 require.NotZero(resp2.Index) 544 545 // Check for heartbeat interval 546 ttl := resp2.HeartbeatTTL 547 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 548 t.Fatalf("bad: %#v", ttl) 549 } 550 551 // Check for the node in the FSM 552 state := s1.fsm.State() 553 ws := memdb.NewWatchSet() 554 out, err := state.NodeByID(ws, node.ID) 555 require.NoError(err) 556 require.NotNil(out) 557 require.EqualValues(resp2.Index, out.ModifyIndex) 558 require.Len(out.Events, 2) 559 require.Equal(NodeHeartbeatEventReregistered, out.Events[1].Message) 560 } 561 562 func TestClientEndpoint_Register_GetEvals(t *testing.T) { 563 t.Parallel() 564 s1 := TestServer(t, nil) 565 defer s1.Shutdown() 566 codec := rpcClient(t, s1) 567 testutil.WaitForLeader(t, s1.RPC) 568 569 // Register a system job. 570 job := mock.SystemJob() 571 state := s1.fsm.State() 572 if err := state.UpsertJob(1, job); err != nil { 573 t.Fatalf("err: %v", err) 574 } 575 576 // Create the register request going directly to ready 577 node := mock.Node() 578 node.Status = structs.NodeStatusReady 579 reg := &structs.NodeRegisterRequest{ 580 Node: node, 581 WriteRequest: structs.WriteRequest{Region: "global"}, 582 } 583 584 // Fetch the response 585 var resp structs.NodeUpdateResponse 586 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 587 t.Fatalf("err: %v", err) 588 } 589 590 // Check for heartbeat interval 591 ttl := resp.HeartbeatTTL 592 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 593 t.Fatalf("bad: %#v", ttl) 594 } 595 596 // Check for an eval caused by the system job. 597 if len(resp.EvalIDs) != 1 { 598 t.Fatalf("expected one eval; got %#v", resp.EvalIDs) 599 } 600 601 evalID := resp.EvalIDs[0] 602 ws := memdb.NewWatchSet() 603 eval, err := state.EvalByID(ws, evalID) 604 if err != nil { 605 t.Fatalf("could not get eval %v", evalID) 606 } 607 608 if eval.Type != "system" { 609 t.Fatalf("unexpected eval type; got %v; want %q", eval.Type, "system") 610 } 611 612 // Check for the node in the FSM 613 out, err := state.NodeByID(ws, node.ID) 614 if err != nil { 615 t.Fatalf("err: %v", err) 616 } 617 if out == nil { 618 t.Fatalf("expected node") 619 } 620 if out.ModifyIndex != resp.Index { 621 t.Fatalf("index mis-match") 622 } 623 624 // Transition it to down and then ready 625 node.Status = structs.NodeStatusDown 626 reg = &structs.NodeRegisterRequest{ 627 Node: node, 628 WriteRequest: structs.WriteRequest{Region: "global"}, 629 } 630 631 // Fetch the response 632 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 633 t.Fatalf("err: %v", err) 634 } 635 636 if len(resp.EvalIDs) != 1 { 637 t.Fatalf("expected one eval; got %#v", resp.EvalIDs) 638 } 639 640 node.Status = structs.NodeStatusReady 641 reg = &structs.NodeRegisterRequest{ 642 Node: node, 643 WriteRequest: structs.WriteRequest{Region: "global"}, 644 } 645 646 // Fetch the response 647 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 648 t.Fatalf("err: %v", err) 649 } 650 651 if len(resp.EvalIDs) != 1 { 652 t.Fatalf("expected one eval; got %#v", resp.EvalIDs) 653 } 654 } 655 656 func TestClientEndpoint_UpdateStatus_GetEvals(t *testing.T) { 657 t.Parallel() 658 s1 := TestServer(t, nil) 659 defer s1.Shutdown() 660 codec := rpcClient(t, s1) 661 testutil.WaitForLeader(t, s1.RPC) 662 663 // Register a system job. 664 job := mock.SystemJob() 665 state := s1.fsm.State() 666 if err := state.UpsertJob(1, job); err != nil { 667 t.Fatalf("err: %v", err) 668 } 669 670 // Create the register request 671 node := mock.Node() 672 node.Status = structs.NodeStatusInit 673 reg := &structs.NodeRegisterRequest{ 674 Node: node, 675 WriteRequest: structs.WriteRequest{Region: "global"}, 676 } 677 678 // Fetch the response 679 var resp structs.NodeUpdateResponse 680 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 681 t.Fatalf("err: %v", err) 682 } 683 684 // Check for heartbeat interval 685 ttl := resp.HeartbeatTTL 686 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 687 t.Fatalf("bad: %#v", ttl) 688 } 689 690 // Update the status 691 update := &structs.NodeUpdateStatusRequest{ 692 NodeID: node.ID, 693 Status: structs.NodeStatusReady, 694 WriteRequest: structs.WriteRequest{Region: "global"}, 695 } 696 var resp2 structs.NodeUpdateResponse 697 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", update, &resp2); err != nil { 698 t.Fatalf("err: %v", err) 699 } 700 if resp2.Index == 0 { 701 t.Fatalf("bad index: %d", resp2.Index) 702 } 703 704 // Check for an eval caused by the system job. 705 if len(resp2.EvalIDs) != 1 { 706 t.Fatalf("expected one eval; got %#v", resp2.EvalIDs) 707 } 708 709 evalID := resp2.EvalIDs[0] 710 ws := memdb.NewWatchSet() 711 eval, err := state.EvalByID(ws, evalID) 712 if err != nil { 713 t.Fatalf("could not get eval %v", evalID) 714 } 715 716 if eval.Type != "system" { 717 t.Fatalf("unexpected eval type; got %v; want %q", eval.Type, "system") 718 } 719 720 // Check for heartbeat interval 721 ttl = resp2.HeartbeatTTL 722 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 723 t.Fatalf("bad: %#v", ttl) 724 } 725 726 // Check for the node in the FSM 727 out, err := state.NodeByID(ws, node.ID) 728 if err != nil { 729 t.Fatalf("err: %v", err) 730 } 731 if out == nil { 732 t.Fatalf("expected node") 733 } 734 if out.ModifyIndex != resp2.Index { 735 t.Fatalf("index mis-match") 736 } 737 } 738 739 func TestClientEndpoint_UpdateStatus_HeartbeatOnly(t *testing.T) { 740 t.Parallel() 741 s1 := TestServer(t, nil) 742 defer s1.Shutdown() 743 744 s2 := TestServer(t, func(c *Config) { 745 c.DevDisableBootstrap = true 746 }) 747 defer s2.Shutdown() 748 749 s3 := TestServer(t, func(c *Config) { 750 c.DevDisableBootstrap = true 751 }) 752 defer s3.Shutdown() 753 servers := []*Server{s1, s2, s3} 754 TestJoin(t, s1, s2, s3) 755 756 for _, s := range servers { 757 testutil.WaitForResult(func() (bool, error) { 758 peers, _ := s.numPeers() 759 return peers == 3, nil 760 }, func(err error) { 761 t.Fatalf("should have 3 peers") 762 }) 763 } 764 765 codec := rpcClient(t, s1) 766 testutil.WaitForLeader(t, s1.RPC) 767 768 // Create the register request 769 node := mock.Node() 770 reg := &structs.NodeRegisterRequest{ 771 Node: node, 772 WriteRequest: structs.WriteRequest{Region: "global"}, 773 } 774 775 // Fetch the response 776 var resp structs.NodeUpdateResponse 777 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 778 t.Fatalf("err: %v", err) 779 } 780 781 // Check for heartbeat interval 782 ttl := resp.HeartbeatTTL 783 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 784 t.Fatalf("bad: %#v", ttl) 785 } 786 787 // Check for heartbeat servers 788 serverAddrs := resp.Servers 789 if len(serverAddrs) == 0 { 790 t.Fatalf("bad: %#v", serverAddrs) 791 } 792 793 // Update the status, static state 794 dereg := &structs.NodeUpdateStatusRequest{ 795 NodeID: node.ID, 796 Status: node.Status, 797 WriteRequest: structs.WriteRequest{Region: "global"}, 798 } 799 var resp2 structs.NodeUpdateResponse 800 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateStatus", dereg, &resp2); err != nil { 801 t.Fatalf("err: %v", err) 802 } 803 if resp2.Index != 0 { 804 t.Fatalf("bad index: %d", resp2.Index) 805 } 806 807 // Check for heartbeat interval 808 ttl = resp2.HeartbeatTTL 809 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 810 t.Fatalf("bad: %#v", ttl) 811 } 812 } 813 814 func TestClientEndpoint_UpdateStatus_HeartbeatOnly_Advertise(t *testing.T) { 815 t.Parallel() 816 require := require.New(t) 817 818 advAddr := "127.0.1.1:1234" 819 adv, err := net.ResolveTCPAddr("tcp", advAddr) 820 require.Nil(err) 821 822 s1 := TestServer(t, func(c *Config) { 823 c.ClientRPCAdvertise = adv 824 }) 825 defer s1.Shutdown() 826 codec := rpcClient(t, s1) 827 testutil.WaitForLeader(t, s1.RPC) 828 829 // Create the register request 830 node := mock.Node() 831 reg := &structs.NodeRegisterRequest{ 832 Node: node, 833 WriteRequest: structs.WriteRequest{Region: "global"}, 834 } 835 836 // Fetch the response 837 var resp structs.NodeUpdateResponse 838 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 839 t.Fatalf("err: %v", err) 840 } 841 842 // Check for heartbeat interval 843 ttl := resp.HeartbeatTTL 844 if ttl < s1.config.MinHeartbeatTTL || ttl > 2*s1.config.MinHeartbeatTTL { 845 t.Fatalf("bad: %#v", ttl) 846 } 847 848 // Check for heartbeat servers 849 require.Len(resp.Servers, 1) 850 require.Equal(resp.Servers[0].RPCAdvertiseAddr, advAddr) 851 } 852 853 func TestClientEndpoint_UpdateDrain(t *testing.T) { 854 t.Parallel() 855 require := require.New(t) 856 s1 := TestServer(t, nil) 857 defer s1.Shutdown() 858 codec := rpcClient(t, s1) 859 testutil.WaitForLeader(t, s1.RPC) 860 861 // Disable drainer to prevent drain from completing during test 862 s1.nodeDrainer.SetEnabled(false, nil) 863 864 // Create the register request 865 node := mock.Node() 866 reg := &structs.NodeRegisterRequest{ 867 Node: node, 868 WriteRequest: structs.WriteRequest{Region: "global"}, 869 } 870 871 // Fetch the response 872 var resp structs.NodeUpdateResponse 873 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp)) 874 875 beforeUpdate := time.Now() 876 strategy := &structs.DrainStrategy{ 877 DrainSpec: structs.DrainSpec{ 878 Deadline: 10 * time.Second, 879 }, 880 } 881 882 // Update the status 883 dereg := &structs.NodeUpdateDrainRequest{ 884 NodeID: node.ID, 885 DrainStrategy: strategy, 886 WriteRequest: structs.WriteRequest{Region: "global"}, 887 } 888 var resp2 structs.NodeDrainUpdateResponse 889 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp2)) 890 require.NotZero(resp2.Index) 891 892 // Check for the node in the FSM 893 state := s1.fsm.State() 894 ws := memdb.NewWatchSet() 895 out, err := state.NodeByID(ws, node.ID) 896 require.Nil(err) 897 require.True(out.Drain) 898 require.Equal(strategy.Deadline, out.DrainStrategy.Deadline) 899 require.Len(out.Events, 2) 900 require.Equal(NodeDrainEventDrainSet, out.Events[1].Message) 901 902 // before+deadline should be before the forced deadline 903 require.True(beforeUpdate.Add(strategy.Deadline).Before(out.DrainStrategy.ForceDeadline)) 904 905 // now+deadline should be after the forced deadline 906 require.True(time.Now().Add(strategy.Deadline).After(out.DrainStrategy.ForceDeadline)) 907 908 // Register a system job 909 job := mock.SystemJob() 910 require.Nil(s1.State().UpsertJob(10, job)) 911 912 // Update the eligibility and expect evals 913 dereg.DrainStrategy = nil 914 dereg.MarkEligible = true 915 var resp3 structs.NodeDrainUpdateResponse 916 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp3)) 917 require.NotZero(resp3.Index) 918 require.NotZero(resp3.EvalCreateIndex) 919 require.Len(resp3.EvalIDs, 1) 920 921 // Check for updated node in the FSM 922 ws = memdb.NewWatchSet() 923 out, err = state.NodeByID(ws, node.ID) 924 require.NoError(err) 925 require.Len(out.Events, 3) 926 require.Equal(NodeDrainEventDrainDisabled, out.Events[2].Message) 927 928 // Check that calling UpdateDrain with the same DrainStrategy does not emit 929 // a node event. 930 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp3)) 931 ws = memdb.NewWatchSet() 932 out, err = state.NodeByID(ws, node.ID) 933 require.NoError(err) 934 require.Len(out.Events, 3) 935 } 936 937 func TestClientEndpoint_UpdateDrain_ACL(t *testing.T) { 938 t.Parallel() 939 s1, root := TestACLServer(t, nil) 940 defer s1.Shutdown() 941 codec := rpcClient(t, s1) 942 testutil.WaitForLeader(t, s1.RPC) 943 require := require.New(t) 944 945 // Create the node 946 node := mock.Node() 947 state := s1.fsm.State() 948 949 require.Nil(state.UpsertNode(1, node), "UpsertNode") 950 951 // Create the policy and tokens 952 validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid", mock.NodePolicy(acl.PolicyWrite)) 953 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", mock.NodePolicy(acl.PolicyRead)) 954 955 // Update the status without a token and expect failure 956 dereg := &structs.NodeUpdateDrainRequest{ 957 NodeID: node.ID, 958 DrainStrategy: &structs.DrainStrategy{ 959 DrainSpec: structs.DrainSpec{ 960 Deadline: 10 * time.Second, 961 }, 962 }, 963 WriteRequest: structs.WriteRequest{Region: "global"}, 964 } 965 { 966 var resp structs.NodeDrainUpdateResponse 967 err := msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp) 968 require.NotNil(err, "RPC") 969 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 970 } 971 972 // Try with a valid token 973 dereg.AuthToken = validToken.SecretID 974 { 975 var resp structs.NodeDrainUpdateResponse 976 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp), "RPC") 977 } 978 979 // Try with a invalid token 980 dereg.AuthToken = invalidToken.SecretID 981 { 982 var resp structs.NodeDrainUpdateResponse 983 err := msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp) 984 require.NotNil(err, "RPC") 985 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 986 } 987 988 // Try with a root token 989 dereg.AuthToken = root.SecretID 990 { 991 var resp structs.NodeDrainUpdateResponse 992 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp), "RPC") 993 } 994 } 995 996 // This test ensures that Nomad marks client state of allocations which are in 997 // pending/running state to lost when a node is marked as down. 998 func TestClientEndpoint_Drain_Down(t *testing.T) { 999 t.Parallel() 1000 s1 := TestServer(t, nil) 1001 defer s1.Shutdown() 1002 codec := rpcClient(t, s1) 1003 testutil.WaitForLeader(t, s1.RPC) 1004 require := require.New(t) 1005 1006 // Register a node 1007 node := mock.Node() 1008 reg := &structs.NodeRegisterRequest{ 1009 Node: node, 1010 WriteRequest: structs.WriteRequest{Region: "global"}, 1011 } 1012 // Fetch the response 1013 var resp structs.NodeUpdateResponse 1014 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp)) 1015 1016 // Register a service job 1017 var jobResp structs.JobRegisterResponse 1018 job := mock.Job() 1019 job.TaskGroups[0].Count = 1 1020 jobReq := &structs.JobRegisterRequest{ 1021 Job: job, 1022 WriteRequest: structs.WriteRequest{ 1023 Region: "global", 1024 Namespace: job.Namespace, 1025 }, 1026 } 1027 require.Nil(msgpackrpc.CallWithCodec(codec, "Job.Register", jobReq, &jobResp)) 1028 1029 // Register a system job 1030 var jobResp1 structs.JobRegisterResponse 1031 job1 := mock.SystemJob() 1032 job1.TaskGroups[0].Count = 1 1033 jobReq1 := &structs.JobRegisterRequest{ 1034 Job: job1, 1035 WriteRequest: structs.WriteRequest{ 1036 Region: "global", 1037 Namespace: job1.Namespace, 1038 }, 1039 } 1040 require.Nil(msgpackrpc.CallWithCodec(codec, "Job.Register", jobReq1, &jobResp1)) 1041 1042 // Wait for the scheduler to create an allocation 1043 testutil.WaitForResult(func() (bool, error) { 1044 ws := memdb.NewWatchSet() 1045 allocs, err := s1.fsm.state.AllocsByJob(ws, job.Namespace, job.ID, true) 1046 if err != nil { 1047 return false, err 1048 } 1049 allocs1, err := s1.fsm.state.AllocsByJob(ws, job1.Namespace, job1.ID, true) 1050 if err != nil { 1051 return false, err 1052 } 1053 return len(allocs) > 0 && len(allocs1) > 0, nil 1054 }, func(err error) { 1055 t.Fatalf("err: %v", err) 1056 }) 1057 1058 // Drain the node 1059 dereg := &structs.NodeUpdateDrainRequest{ 1060 NodeID: node.ID, 1061 DrainStrategy: &structs.DrainStrategy{ 1062 DrainSpec: structs.DrainSpec{ 1063 Deadline: -1 * time.Second, 1064 }, 1065 }, 1066 WriteRequest: structs.WriteRequest{Region: "global"}, 1067 } 1068 var resp2 structs.NodeDrainUpdateResponse 1069 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateDrain", dereg, &resp2)) 1070 1071 // Mark the node as down 1072 node.Status = structs.NodeStatusDown 1073 reg = &structs.NodeRegisterRequest{ 1074 Node: node, 1075 WriteRequest: structs.WriteRequest{Region: "global"}, 1076 } 1077 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp)) 1078 1079 // Ensure that the allocation has transitioned to lost 1080 testutil.WaitForResult(func() (bool, error) { 1081 ws := memdb.NewWatchSet() 1082 summary, err := s1.fsm.state.JobSummaryByID(ws, job.Namespace, job.ID) 1083 if err != nil { 1084 return false, err 1085 } 1086 expectedSummary := &structs.JobSummary{ 1087 JobID: job.ID, 1088 Namespace: job.Namespace, 1089 Summary: map[string]structs.TaskGroupSummary{ 1090 "web": { 1091 Queued: 1, 1092 Lost: 1, 1093 }, 1094 }, 1095 Children: new(structs.JobChildrenSummary), 1096 CreateIndex: jobResp.JobModifyIndex, 1097 ModifyIndex: summary.ModifyIndex, 1098 } 1099 if !reflect.DeepEqual(summary, expectedSummary) { 1100 return false, fmt.Errorf("Service: expected: %#v, actual: %#v", expectedSummary, summary) 1101 } 1102 1103 summary1, err := s1.fsm.state.JobSummaryByID(ws, job1.Namespace, job1.ID) 1104 if err != nil { 1105 return false, err 1106 } 1107 expectedSummary1 := &structs.JobSummary{ 1108 JobID: job1.ID, 1109 Namespace: job1.Namespace, 1110 Summary: map[string]structs.TaskGroupSummary{ 1111 "web": { 1112 Lost: 1, 1113 }, 1114 }, 1115 Children: new(structs.JobChildrenSummary), 1116 CreateIndex: jobResp1.JobModifyIndex, 1117 ModifyIndex: summary1.ModifyIndex, 1118 } 1119 if !reflect.DeepEqual(summary1, expectedSummary1) { 1120 return false, fmt.Errorf("System: expected: %#v, actual: %#v", expectedSummary1, summary1) 1121 } 1122 return true, nil 1123 }, func(err error) { 1124 t.Fatalf("err: %v", err) 1125 }) 1126 } 1127 1128 func TestClientEndpoint_UpdateEligibility(t *testing.T) { 1129 t.Parallel() 1130 require := require.New(t) 1131 s1 := TestServer(t, nil) 1132 defer s1.Shutdown() 1133 codec := rpcClient(t, s1) 1134 testutil.WaitForLeader(t, s1.RPC) 1135 1136 // Create the register request 1137 node := mock.Node() 1138 reg := &structs.NodeRegisterRequest{ 1139 Node: node, 1140 WriteRequest: structs.WriteRequest{Region: "global"}, 1141 } 1142 1143 // Fetch the response 1144 var resp structs.NodeUpdateResponse 1145 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp)) 1146 1147 // Update the eligibility 1148 elig := &structs.NodeUpdateEligibilityRequest{ 1149 NodeID: node.ID, 1150 Eligibility: structs.NodeSchedulingIneligible, 1151 WriteRequest: structs.WriteRequest{Region: "global"}, 1152 } 1153 var resp2 structs.NodeEligibilityUpdateResponse 1154 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateEligibility", elig, &resp2)) 1155 require.NotZero(resp2.Index) 1156 require.Zero(resp2.EvalCreateIndex) 1157 require.Empty(resp2.EvalIDs) 1158 1159 // Check for the node in the FSM 1160 state := s1.fsm.State() 1161 out, err := state.NodeByID(nil, node.ID) 1162 require.Nil(err) 1163 require.Equal(out.SchedulingEligibility, structs.NodeSchedulingIneligible) 1164 require.Len(out.Events, 2) 1165 require.Equal(NodeEligibilityEventIneligible, out.Events[1].Message) 1166 1167 // Register a system job 1168 job := mock.SystemJob() 1169 require.Nil(s1.State().UpsertJob(10, job)) 1170 1171 // Update the eligibility and expect evals 1172 elig.Eligibility = structs.NodeSchedulingEligible 1173 var resp3 structs.NodeEligibilityUpdateResponse 1174 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateEligibility", elig, &resp3)) 1175 require.NotZero(resp3.Index) 1176 require.NotZero(resp3.EvalCreateIndex) 1177 require.Len(resp3.EvalIDs, 1) 1178 1179 out, err = state.NodeByID(nil, node.ID) 1180 require.Nil(err) 1181 require.Len(out.Events, 3) 1182 require.Equal(NodeEligibilityEventEligible, out.Events[2].Message) 1183 } 1184 1185 func TestClientEndpoint_UpdateEligibility_ACL(t *testing.T) { 1186 t.Parallel() 1187 s1, root := TestACLServer(t, nil) 1188 defer s1.Shutdown() 1189 codec := rpcClient(t, s1) 1190 testutil.WaitForLeader(t, s1.RPC) 1191 require := require.New(t) 1192 1193 // Create the node 1194 node := mock.Node() 1195 state := s1.fsm.State() 1196 1197 require.Nil(state.UpsertNode(1, node), "UpsertNode") 1198 1199 // Create the policy and tokens 1200 validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid", mock.NodePolicy(acl.PolicyWrite)) 1201 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", mock.NodePolicy(acl.PolicyRead)) 1202 1203 // Update the status without a token and expect failure 1204 dereg := &structs.NodeUpdateEligibilityRequest{ 1205 NodeID: node.ID, 1206 Eligibility: structs.NodeSchedulingIneligible, 1207 WriteRequest: structs.WriteRequest{Region: "global"}, 1208 } 1209 { 1210 var resp structs.NodeEligibilityUpdateResponse 1211 err := msgpackrpc.CallWithCodec(codec, "Node.UpdateEligibility", dereg, &resp) 1212 require.NotNil(err, "RPC") 1213 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 1214 } 1215 1216 // Try with a valid token 1217 dereg.AuthToken = validToken.SecretID 1218 { 1219 var resp structs.NodeEligibilityUpdateResponse 1220 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateEligibility", dereg, &resp), "RPC") 1221 } 1222 1223 // Try with a invalid token 1224 dereg.AuthToken = invalidToken.SecretID 1225 { 1226 var resp structs.NodeEligibilityUpdateResponse 1227 err := msgpackrpc.CallWithCodec(codec, "Node.UpdateEligibility", dereg, &resp) 1228 require.NotNil(err, "RPC") 1229 require.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 1230 } 1231 1232 // Try with a root token 1233 dereg.AuthToken = root.SecretID 1234 { 1235 var resp structs.NodeEligibilityUpdateResponse 1236 require.Nil(msgpackrpc.CallWithCodec(codec, "Node.UpdateEligibility", dereg, &resp), "RPC") 1237 } 1238 } 1239 1240 func TestClientEndpoint_GetNode(t *testing.T) { 1241 t.Parallel() 1242 s1 := TestServer(t, nil) 1243 defer s1.Shutdown() 1244 codec := rpcClient(t, s1) 1245 testutil.WaitForLeader(t, s1.RPC) 1246 1247 // Create the register request 1248 node := mock.Node() 1249 reg := &structs.NodeRegisterRequest{ 1250 Node: node, 1251 WriteRequest: structs.WriteRequest{Region: "global"}, 1252 } 1253 1254 // Fetch the response 1255 var resp structs.GenericResponse 1256 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1257 t.Fatalf("err: %v", err) 1258 } 1259 node.CreateIndex = resp.Index 1260 node.ModifyIndex = resp.Index 1261 1262 // Lookup the node 1263 get := &structs.NodeSpecificRequest{ 1264 NodeID: node.ID, 1265 QueryOptions: structs.QueryOptions{Region: "global"}, 1266 } 1267 var resp2 structs.SingleNodeResponse 1268 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil { 1269 t.Fatalf("err: %v", err) 1270 } 1271 if resp2.Index != resp.Index { 1272 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 1273 } 1274 1275 if resp2.Node.ComputedClass == "" { 1276 t.Fatalf("bad ComputedClass: %#v", resp2.Node) 1277 } 1278 1279 // Update the status updated at value 1280 node.StatusUpdatedAt = resp2.Node.StatusUpdatedAt 1281 node.SecretID = "" 1282 node.Events = resp2.Node.Events 1283 if !reflect.DeepEqual(node, resp2.Node) { 1284 t.Fatalf("bad: %#v \n %#v", node, resp2.Node) 1285 } 1286 1287 // assert that the node register event was set correctly 1288 if len(resp2.Node.Events) != 1 { 1289 t.Fatalf("Did not set node events: %#v", resp2.Node) 1290 } 1291 if resp2.Node.Events[0].Message != state.NodeRegisterEventRegistered { 1292 t.Fatalf("Did not set node register event correctly: %#v", resp2.Node) 1293 } 1294 1295 // Lookup non-existing node 1296 get.NodeID = "12345678-abcd-efab-cdef-123456789abc" 1297 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", get, &resp2); err != nil { 1298 t.Fatalf("err: %v", err) 1299 } 1300 if resp2.Index != resp.Index { 1301 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 1302 } 1303 if resp2.Node != nil { 1304 t.Fatalf("unexpected node") 1305 } 1306 } 1307 1308 func TestClientEndpoint_GetNode_ACL(t *testing.T) { 1309 t.Parallel() 1310 s1, root := TestACLServer(t, nil) 1311 defer s1.Shutdown() 1312 codec := rpcClient(t, s1) 1313 testutil.WaitForLeader(t, s1.RPC) 1314 assert := assert.New(t) 1315 1316 // Create the node 1317 node := mock.Node() 1318 state := s1.fsm.State() 1319 assert.Nil(state.UpsertNode(1, node), "UpsertNode") 1320 1321 // Create the policy and tokens 1322 validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid", mock.NodePolicy(acl.PolicyRead)) 1323 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", mock.NodePolicy(acl.PolicyDeny)) 1324 1325 // Lookup the node without a token and expect failure 1326 req := &structs.NodeSpecificRequest{ 1327 NodeID: node.ID, 1328 QueryOptions: structs.QueryOptions{Region: "global"}, 1329 } 1330 { 1331 var resp structs.SingleNodeResponse 1332 err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp) 1333 assert.NotNil(err, "RPC") 1334 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 1335 } 1336 1337 // Try with a valid token 1338 req.AuthToken = validToken.SecretID 1339 { 1340 var resp structs.SingleNodeResponse 1341 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp), "RPC") 1342 assert.Equal(node.ID, resp.Node.ID) 1343 } 1344 1345 // Try with a Node.SecretID 1346 req.AuthToken = node.SecretID 1347 { 1348 var resp structs.SingleNodeResponse 1349 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp), "RPC") 1350 assert.Equal(node.ID, resp.Node.ID) 1351 } 1352 1353 // Try with a invalid token 1354 req.AuthToken = invalidToken.SecretID 1355 { 1356 var resp structs.SingleNodeResponse 1357 err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp) 1358 assert.NotNil(err, "RPC") 1359 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 1360 } 1361 1362 // Try with a root token 1363 req.AuthToken = root.SecretID 1364 { 1365 var resp structs.SingleNodeResponse 1366 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp), "RPC") 1367 assert.Equal(node.ID, resp.Node.ID) 1368 } 1369 } 1370 1371 func TestClientEndpoint_GetNode_Blocking(t *testing.T) { 1372 t.Parallel() 1373 s1 := TestServer(t, nil) 1374 defer s1.Shutdown() 1375 state := s1.fsm.State() 1376 codec := rpcClient(t, s1) 1377 testutil.WaitForLeader(t, s1.RPC) 1378 1379 // Create the node 1380 node1 := mock.Node() 1381 node2 := mock.Node() 1382 1383 // First create an unrelated node. 1384 time.AfterFunc(100*time.Millisecond, func() { 1385 if err := state.UpsertNode(100, node1); err != nil { 1386 t.Fatalf("err: %v", err) 1387 } 1388 }) 1389 1390 // Upsert the node we are watching later 1391 time.AfterFunc(200*time.Millisecond, func() { 1392 if err := state.UpsertNode(200, node2); err != nil { 1393 t.Fatalf("err: %v", err) 1394 } 1395 }) 1396 1397 // Lookup the node 1398 req := &structs.NodeSpecificRequest{ 1399 NodeID: node2.ID, 1400 QueryOptions: structs.QueryOptions{ 1401 Region: "global", 1402 MinQueryIndex: 150, 1403 }, 1404 } 1405 var resp structs.SingleNodeResponse 1406 start := time.Now() 1407 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp); err != nil { 1408 t.Fatalf("err: %v", err) 1409 } 1410 1411 if elapsed := time.Since(start); elapsed < 200*time.Millisecond { 1412 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 1413 } 1414 if resp.Index != 200 { 1415 t.Fatalf("Bad index: %d %d", resp.Index, 200) 1416 } 1417 if resp.Node == nil || resp.Node.ID != node2.ID { 1418 t.Fatalf("bad: %#v", resp.Node) 1419 } 1420 1421 // Node update triggers watches 1422 time.AfterFunc(100*time.Millisecond, func() { 1423 nodeUpdate := mock.Node() 1424 nodeUpdate.ID = node2.ID 1425 nodeUpdate.Status = structs.NodeStatusDown 1426 if err := state.UpsertNode(300, nodeUpdate); err != nil { 1427 t.Fatalf("err: %v", err) 1428 } 1429 }) 1430 1431 req.QueryOptions.MinQueryIndex = 250 1432 var resp2 structs.SingleNodeResponse 1433 start = time.Now() 1434 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp2); err != nil { 1435 t.Fatalf("err: %v", err) 1436 } 1437 1438 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 1439 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 1440 } 1441 if resp2.Index != 300 { 1442 t.Fatalf("Bad index: %d %d", resp2.Index, 300) 1443 } 1444 if resp2.Node == nil || resp2.Node.Status != structs.NodeStatusDown { 1445 t.Fatalf("bad: %#v", resp2.Node) 1446 } 1447 1448 // Node delete triggers watches 1449 time.AfterFunc(100*time.Millisecond, func() { 1450 if err := state.DeleteNode(400, node2.ID); err != nil { 1451 t.Fatalf("err: %v", err) 1452 } 1453 }) 1454 1455 req.QueryOptions.MinQueryIndex = 350 1456 var resp3 structs.SingleNodeResponse 1457 start = time.Now() 1458 if err := msgpackrpc.CallWithCodec(codec, "Node.GetNode", req, &resp3); err != nil { 1459 t.Fatalf("err: %v", err) 1460 } 1461 1462 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 1463 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 1464 } 1465 if resp3.Index != 400 { 1466 t.Fatalf("Bad index: %d %d", resp2.Index, 400) 1467 } 1468 if resp3.Node != nil { 1469 t.Fatalf("bad: %#v", resp3.Node) 1470 } 1471 } 1472 1473 func TestClientEndpoint_GetAllocs(t *testing.T) { 1474 t.Parallel() 1475 s1 := TestServer(t, nil) 1476 defer s1.Shutdown() 1477 codec := rpcClient(t, s1) 1478 testutil.WaitForLeader(t, s1.RPC) 1479 1480 // Create the register request 1481 node := mock.Node() 1482 reg := &structs.NodeRegisterRequest{ 1483 Node: node, 1484 WriteRequest: structs.WriteRequest{Region: "global"}, 1485 } 1486 1487 // Fetch the response 1488 var resp structs.GenericResponse 1489 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1490 t.Fatalf("err: %v", err) 1491 } 1492 node.CreateIndex = resp.Index 1493 node.ModifyIndex = resp.Index 1494 1495 // Inject fake evaluations 1496 alloc := mock.Alloc() 1497 alloc.NodeID = node.ID 1498 state := s1.fsm.State() 1499 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1500 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1501 if err != nil { 1502 t.Fatalf("err: %v", err) 1503 } 1504 1505 // Lookup the allocs 1506 get := &structs.NodeSpecificRequest{ 1507 NodeID: node.ID, 1508 QueryOptions: structs.QueryOptions{Region: "global"}, 1509 } 1510 var resp2 structs.NodeAllocsResponse 1511 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil { 1512 t.Fatalf("err: %v", err) 1513 } 1514 if resp2.Index != 100 { 1515 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1516 } 1517 1518 if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID { 1519 t.Fatalf("bad: %#v", resp2.Allocs) 1520 } 1521 1522 // Lookup non-existing node 1523 get.NodeID = "foobarbaz" 1524 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", get, &resp2); err != nil { 1525 t.Fatalf("err: %v", err) 1526 } 1527 if resp2.Index != 100 { 1528 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1529 } 1530 if len(resp2.Allocs) != 0 { 1531 t.Fatalf("unexpected node") 1532 } 1533 } 1534 1535 func TestClientEndpoint_GetAllocs_ACL_Basic(t *testing.T) { 1536 t.Parallel() 1537 s1, root := TestACLServer(t, nil) 1538 defer s1.Shutdown() 1539 codec := rpcClient(t, s1) 1540 testutil.WaitForLeader(t, s1.RPC) 1541 assert := assert.New(t) 1542 1543 // Create the node 1544 allocDefaultNS := mock.Alloc() 1545 node := mock.Node() 1546 allocDefaultNS.NodeID = node.ID 1547 state := s1.fsm.State() 1548 assert.Nil(state.UpsertNode(1, node), "UpsertNode") 1549 assert.Nil(state.UpsertJobSummary(2, mock.JobSummary(allocDefaultNS.JobID)), "UpsertJobSummary") 1550 allocs := []*structs.Allocation{allocDefaultNS} 1551 assert.Nil(state.UpsertAllocs(5, allocs), "UpsertAllocs") 1552 1553 // Create the namespace policy and tokens 1554 validDefaultToken := mock.CreatePolicyAndToken(t, state, 1001, "test-default-valid", mock.NodePolicy(acl.PolicyRead)+ 1555 mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob})) 1556 invalidToken := mock.CreatePolicyAndToken(t, state, 1004, "test-invalid", 1557 mock.NamespacePolicy(structs.DefaultNamespace, "", []string{acl.NamespaceCapabilityReadJob})) 1558 1559 req := &structs.NodeSpecificRequest{ 1560 NodeID: node.ID, 1561 QueryOptions: structs.QueryOptions{ 1562 Region: "global", 1563 }, 1564 } 1565 1566 // Lookup the node without a token and expect failure 1567 { 1568 var resp structs.NodeAllocsResponse 1569 err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp) 1570 assert.NotNil(err, "RPC") 1571 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 1572 } 1573 1574 // Try with a valid token for the default namespace 1575 req.AuthToken = validDefaultToken.SecretID 1576 { 1577 var resp structs.NodeAllocsResponse 1578 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp), "RPC") 1579 assert.Len(resp.Allocs, 1) 1580 assert.Equal(allocDefaultNS.ID, resp.Allocs[0].ID) 1581 } 1582 1583 // Try with a invalid token 1584 req.AuthToken = invalidToken.SecretID 1585 { 1586 var resp structs.NodeAllocsResponse 1587 err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp) 1588 assert.NotNil(err, "RPC") 1589 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 1590 } 1591 1592 // Try with a root token 1593 req.AuthToken = root.SecretID 1594 { 1595 var resp structs.NodeAllocsResponse 1596 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp), "RPC") 1597 assert.Len(resp.Allocs, 1) 1598 for _, alloc := range resp.Allocs { 1599 switch alloc.ID { 1600 case allocDefaultNS.ID: 1601 // expected 1602 default: 1603 t.Errorf("unexpected alloc %q for namespace %q", alloc.ID, alloc.Namespace) 1604 } 1605 } 1606 } 1607 } 1608 1609 func TestClientEndpoint_GetClientAllocs(t *testing.T) { 1610 t.Parallel() 1611 require := require.New(t) 1612 s1 := TestServer(t, nil) 1613 defer s1.Shutdown() 1614 codec := rpcClient(t, s1) 1615 testutil.WaitForLeader(t, s1.RPC) 1616 1617 // Check that we have no client connections 1618 require.Empty(s1.connectedNodes()) 1619 1620 // Create the register request 1621 node := mock.Node() 1622 state := s1.fsm.State() 1623 require.Nil(state.UpsertNode(98, node)) 1624 1625 // Inject fake evaluations 1626 alloc := mock.Alloc() 1627 alloc.NodeID = node.ID 1628 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1629 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1630 if err != nil { 1631 t.Fatalf("err: %v", err) 1632 } 1633 1634 // Lookup the allocs 1635 get := &structs.NodeSpecificRequest{ 1636 NodeID: node.ID, 1637 SecretID: node.SecretID, 1638 QueryOptions: structs.QueryOptions{Region: "global"}, 1639 } 1640 var resp2 structs.NodeClientAllocsResponse 1641 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp2); err != nil { 1642 t.Fatalf("err: %v", err) 1643 } 1644 if resp2.Index != 100 { 1645 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1646 } 1647 1648 if len(resp2.Allocs) != 1 || resp2.Allocs[alloc.ID] != 100 { 1649 t.Fatalf("bad: %#v", resp2.Allocs) 1650 } 1651 1652 // Check that we have the client connections 1653 nodes := s1.connectedNodes() 1654 require.Len(nodes, 1) 1655 require.Contains(nodes, node.ID) 1656 1657 // Lookup node with bad SecretID 1658 get.SecretID = "foobarbaz" 1659 var resp3 structs.NodeClientAllocsResponse 1660 err = msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp3) 1661 if err == nil || !strings.Contains(err.Error(), "does not match") { 1662 t.Fatalf("err: %v", err) 1663 } 1664 1665 // Lookup non-existing node 1666 get.NodeID = uuid.Generate() 1667 var resp4 structs.NodeClientAllocsResponse 1668 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp4); err != nil { 1669 t.Fatalf("err: %v", err) 1670 } 1671 if resp4.Index != 100 { 1672 t.Fatalf("Bad index: %d %d", resp3.Index, 100) 1673 } 1674 if len(resp4.Allocs) != 0 { 1675 t.Fatalf("unexpected node %#v", resp3.Allocs) 1676 } 1677 1678 // Close the connection and check that we remove the client connections 1679 require.Nil(codec.Close()) 1680 testutil.WaitForResult(func() (bool, error) { 1681 nodes := s1.connectedNodes() 1682 return len(nodes) == 0, nil 1683 }, func(err error) { 1684 t.Fatalf("should have no clients") 1685 }) 1686 } 1687 1688 func TestClientEndpoint_GetClientAllocs_Blocking(t *testing.T) { 1689 t.Parallel() 1690 s1 := TestServer(t, nil) 1691 defer s1.Shutdown() 1692 codec := rpcClient(t, s1) 1693 testutil.WaitForLeader(t, s1.RPC) 1694 1695 // Create the register request 1696 node := mock.Node() 1697 reg := &structs.NodeRegisterRequest{ 1698 Node: node, 1699 WriteRequest: structs.WriteRequest{Region: "global"}, 1700 } 1701 1702 // Fetch the response 1703 var resp structs.GenericResponse 1704 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1705 t.Fatalf("err: %v", err) 1706 } 1707 node.CreateIndex = resp.Index 1708 node.ModifyIndex = resp.Index 1709 1710 // Inject fake evaluations async 1711 now := time.Now().UTC().UnixNano() 1712 alloc := mock.Alloc() 1713 alloc.NodeID = node.ID 1714 alloc.ModifyTime = now 1715 state := s1.fsm.State() 1716 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1717 start := time.Now() 1718 time.AfterFunc(100*time.Millisecond, func() { 1719 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1720 if err != nil { 1721 t.Fatalf("err: %v", err) 1722 } 1723 }) 1724 1725 // Lookup the allocs in a blocking query 1726 req := &structs.NodeSpecificRequest{ 1727 NodeID: node.ID, 1728 SecretID: node.SecretID, 1729 QueryOptions: structs.QueryOptions{ 1730 Region: "global", 1731 MinQueryIndex: 50, 1732 MaxQueryTime: time.Second, 1733 }, 1734 } 1735 var resp2 structs.NodeClientAllocsResponse 1736 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", req, &resp2); err != nil { 1737 t.Fatalf("err: %v", err) 1738 } 1739 1740 // Should block at least 100ms 1741 if time.Since(start) < 100*time.Millisecond { 1742 t.Fatalf("too fast") 1743 } 1744 1745 if resp2.Index != 100 { 1746 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1747 } 1748 1749 if len(resp2.Allocs) != 1 || resp2.Allocs[alloc.ID] != 100 { 1750 t.Fatalf("bad: %#v", resp2.Allocs) 1751 } 1752 1753 iter, err := state.AllocsByIDPrefix(nil, structs.DefaultNamespace, alloc.ID) 1754 if err != nil { 1755 t.Fatalf("err: %v", err) 1756 } 1757 1758 getAllocs := func(iter memdb.ResultIterator) []*structs.Allocation { 1759 var allocs []*structs.Allocation 1760 for { 1761 raw := iter.Next() 1762 if raw == nil { 1763 break 1764 } 1765 allocs = append(allocs, raw.(*structs.Allocation)) 1766 } 1767 return allocs 1768 } 1769 out := getAllocs(iter) 1770 1771 if len(out) != 1 { 1772 t.Fatalf("Expected to get one allocation but got:%v", out) 1773 } 1774 1775 if out[0].ModifyTime != now { 1776 t.Fatalf("Invalid modify time %v", out[0].ModifyTime) 1777 } 1778 1779 // Alloc updates fire watches 1780 time.AfterFunc(100*time.Millisecond, func() { 1781 allocUpdate := mock.Alloc() 1782 allocUpdate.NodeID = alloc.NodeID 1783 allocUpdate.ID = alloc.ID 1784 allocUpdate.ClientStatus = structs.AllocClientStatusRunning 1785 state.UpsertJobSummary(199, mock.JobSummary(allocUpdate.JobID)) 1786 err := state.UpsertAllocs(200, []*structs.Allocation{allocUpdate}) 1787 if err != nil { 1788 t.Fatalf("err: %v", err) 1789 } 1790 }) 1791 1792 req.QueryOptions.MinQueryIndex = 150 1793 var resp3 structs.NodeClientAllocsResponse 1794 if err := msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", req, &resp3); err != nil { 1795 t.Fatalf("err: %v", err) 1796 } 1797 1798 if time.Since(start) < 100*time.Millisecond { 1799 t.Fatalf("too fast") 1800 } 1801 if resp3.Index != 200 { 1802 t.Fatalf("Bad index: %d %d", resp3.Index, 200) 1803 } 1804 if len(resp3.Allocs) != 1 || resp3.Allocs[alloc.ID] != 200 { 1805 t.Fatalf("bad: %#v", resp3.Allocs) 1806 } 1807 } 1808 1809 func TestClientEndpoint_GetClientAllocs_Blocking_GC(t *testing.T) { 1810 t.Parallel() 1811 assert := assert.New(t) 1812 s1 := TestServer(t, nil) 1813 defer s1.Shutdown() 1814 codec := rpcClient(t, s1) 1815 testutil.WaitForLeader(t, s1.RPC) 1816 1817 // Create the register request 1818 node := mock.Node() 1819 reg := &structs.NodeRegisterRequest{ 1820 Node: node, 1821 WriteRequest: structs.WriteRequest{Region: "global"}, 1822 } 1823 1824 // Fetch the response 1825 var resp structs.GenericResponse 1826 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp)) 1827 node.CreateIndex = resp.Index 1828 node.ModifyIndex = resp.Index 1829 1830 // Inject fake allocations async 1831 alloc1 := mock.Alloc() 1832 alloc1.NodeID = node.ID 1833 alloc2 := mock.Alloc() 1834 alloc2.NodeID = node.ID 1835 state := s1.fsm.State() 1836 state.UpsertJobSummary(99, mock.JobSummary(alloc1.JobID)) 1837 start := time.Now() 1838 time.AfterFunc(100*time.Millisecond, func() { 1839 assert.Nil(state.UpsertAllocs(100, []*structs.Allocation{alloc1, alloc2})) 1840 }) 1841 1842 // Lookup the allocs in a blocking query 1843 req := &structs.NodeSpecificRequest{ 1844 NodeID: node.ID, 1845 SecretID: node.SecretID, 1846 QueryOptions: structs.QueryOptions{ 1847 Region: "global", 1848 MinQueryIndex: 50, 1849 MaxQueryTime: time.Second, 1850 }, 1851 } 1852 var resp2 structs.NodeClientAllocsResponse 1853 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", req, &resp2)) 1854 1855 // Should block at least 100ms 1856 if time.Since(start) < 100*time.Millisecond { 1857 t.Fatalf("too fast") 1858 } 1859 1860 assert.EqualValues(100, resp2.Index) 1861 if assert.Len(resp2.Allocs, 2) { 1862 assert.EqualValues(100, resp2.Allocs[alloc1.ID]) 1863 } 1864 1865 // Delete an allocation 1866 time.AfterFunc(100*time.Millisecond, func() { 1867 assert.Nil(state.DeleteEval(200, nil, []string{alloc2.ID})) 1868 }) 1869 1870 req.QueryOptions.MinQueryIndex = 150 1871 var resp3 structs.NodeClientAllocsResponse 1872 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", req, &resp3)) 1873 1874 if time.Since(start) < 100*time.Millisecond { 1875 t.Fatalf("too fast") 1876 } 1877 assert.EqualValues(200, resp3.Index) 1878 if assert.Len(resp3.Allocs, 1) { 1879 assert.EqualValues(100, resp3.Allocs[alloc1.ID]) 1880 } 1881 } 1882 1883 // A MigrateToken should not be created if an allocation shares the same node 1884 // with its previous allocation 1885 func TestClientEndpoint_GetClientAllocs_WithoutMigrateTokens(t *testing.T) { 1886 t.Parallel() 1887 assert := assert.New(t) 1888 1889 s1 := TestServer(t, nil) 1890 defer s1.Shutdown() 1891 codec := rpcClient(t, s1) 1892 testutil.WaitForLeader(t, s1.RPC) 1893 1894 // Create the register request 1895 node := mock.Node() 1896 reg := &structs.NodeRegisterRequest{ 1897 Node: node, 1898 WriteRequest: structs.WriteRequest{Region: "global"}, 1899 } 1900 1901 // Fetch the response 1902 var resp structs.GenericResponse 1903 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1904 t.Fatalf("err: %v", err) 1905 } 1906 node.CreateIndex = resp.Index 1907 node.ModifyIndex = resp.Index 1908 1909 // Inject fake evaluations 1910 prevAlloc := mock.Alloc() 1911 prevAlloc.NodeID = node.ID 1912 alloc := mock.Alloc() 1913 alloc.NodeID = node.ID 1914 alloc.PreviousAllocation = prevAlloc.ID 1915 alloc.DesiredStatus = structs.AllocClientStatusComplete 1916 state := s1.fsm.State() 1917 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1918 err := state.UpsertAllocs(100, []*structs.Allocation{prevAlloc, alloc}) 1919 assert.Nil(err) 1920 1921 // Lookup the allocs 1922 get := &structs.NodeSpecificRequest{ 1923 NodeID: node.ID, 1924 SecretID: node.SecretID, 1925 QueryOptions: structs.QueryOptions{Region: "global"}, 1926 } 1927 var resp2 structs.NodeClientAllocsResponse 1928 1929 err = msgpackrpc.CallWithCodec(codec, "Node.GetClientAllocs", get, &resp2) 1930 assert.Nil(err) 1931 1932 assert.Equal(uint64(100), resp2.Index) 1933 assert.Equal(2, len(resp2.Allocs)) 1934 assert.Equal(uint64(100), resp2.Allocs[alloc.ID]) 1935 assert.Equal(0, len(resp2.MigrateTokens)) 1936 } 1937 1938 func TestClientEndpoint_GetAllocs_Blocking(t *testing.T) { 1939 t.Parallel() 1940 s1 := TestServer(t, nil) 1941 defer s1.Shutdown() 1942 codec := rpcClient(t, s1) 1943 testutil.WaitForLeader(t, s1.RPC) 1944 1945 // Create the register request 1946 node := mock.Node() 1947 reg := &structs.NodeRegisterRequest{ 1948 Node: node, 1949 WriteRequest: structs.WriteRequest{Region: "global"}, 1950 } 1951 1952 // Fetch the response 1953 var resp structs.GenericResponse 1954 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 1955 t.Fatalf("err: %v", err) 1956 } 1957 node.CreateIndex = resp.Index 1958 node.ModifyIndex = resp.Index 1959 1960 // Inject fake evaluations async 1961 alloc := mock.Alloc() 1962 alloc.NodeID = node.ID 1963 state := s1.fsm.State() 1964 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 1965 start := time.Now() 1966 time.AfterFunc(100*time.Millisecond, func() { 1967 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 1968 if err != nil { 1969 t.Fatalf("err: %v", err) 1970 } 1971 }) 1972 1973 // Lookup the allocs in a blocking query 1974 req := &structs.NodeSpecificRequest{ 1975 NodeID: node.ID, 1976 QueryOptions: structs.QueryOptions{ 1977 Region: "global", 1978 MinQueryIndex: 50, 1979 MaxQueryTime: time.Second, 1980 }, 1981 } 1982 var resp2 structs.NodeAllocsResponse 1983 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp2); err != nil { 1984 t.Fatalf("err: %v", err) 1985 } 1986 1987 // Should block at least 100ms 1988 if time.Since(start) < 100*time.Millisecond { 1989 t.Fatalf("too fast") 1990 } 1991 1992 if resp2.Index != 100 { 1993 t.Fatalf("Bad index: %d %d", resp2.Index, 100) 1994 } 1995 1996 if len(resp2.Allocs) != 1 || resp2.Allocs[0].ID != alloc.ID { 1997 t.Fatalf("bad: %#v", resp2.Allocs) 1998 } 1999 2000 // Alloc updates fire watches 2001 time.AfterFunc(100*time.Millisecond, func() { 2002 allocUpdate := mock.Alloc() 2003 allocUpdate.NodeID = alloc.NodeID 2004 allocUpdate.ID = alloc.ID 2005 allocUpdate.ClientStatus = structs.AllocClientStatusRunning 2006 state.UpsertJobSummary(199, mock.JobSummary(allocUpdate.JobID)) 2007 err := state.UpdateAllocsFromClient(200, []*structs.Allocation{allocUpdate}) 2008 if err != nil { 2009 t.Fatalf("err: %v", err) 2010 } 2011 }) 2012 2013 req.QueryOptions.MinQueryIndex = 150 2014 var resp3 structs.NodeAllocsResponse 2015 if err := msgpackrpc.CallWithCodec(codec, "Node.GetAllocs", req, &resp3); err != nil { 2016 t.Fatalf("err: %v", err) 2017 } 2018 2019 if time.Since(start) < 100*time.Millisecond { 2020 t.Fatalf("too fast") 2021 } 2022 if resp3.Index != 200 { 2023 t.Fatalf("Bad index: %d %d", resp3.Index, 200) 2024 } 2025 if len(resp3.Allocs) != 1 || resp3.Allocs[0].ClientStatus != structs.AllocClientStatusRunning { 2026 t.Fatalf("bad: %#v", resp3.Allocs[0]) 2027 } 2028 } 2029 2030 func TestClientEndpoint_UpdateAlloc(t *testing.T) { 2031 t.Parallel() 2032 s1 := TestServer(t, func(c *Config) { 2033 // Disabling scheduling in this test so that we can 2034 // ensure that the state store doesn't accumulate more evals 2035 // than what we expect the unit test to add 2036 c.NumSchedulers = 0 2037 }) 2038 2039 defer s1.Shutdown() 2040 codec := rpcClient(t, s1) 2041 testutil.WaitForLeader(t, s1.RPC) 2042 require := require.New(t) 2043 2044 // Create the register request 2045 node := mock.Node() 2046 reg := &structs.NodeRegisterRequest{ 2047 Node: node, 2048 WriteRequest: structs.WriteRequest{Region: "global"}, 2049 } 2050 2051 // Fetch the response 2052 var resp structs.GenericResponse 2053 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 2054 t.Fatalf("err: %v", err) 2055 } 2056 2057 state := s1.fsm.State() 2058 // Inject mock job 2059 job := mock.Job() 2060 job.ID = "mytestjob" 2061 err := state.UpsertJob(101, job) 2062 require.Nil(err) 2063 2064 // Inject fake allocations 2065 alloc := mock.Alloc() 2066 alloc.JobID = job.ID 2067 alloc.NodeID = node.ID 2068 err = state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 2069 require.Nil(err) 2070 alloc.TaskGroup = job.TaskGroups[0].Name 2071 2072 alloc2 := mock.Alloc() 2073 alloc2.JobID = job.ID 2074 alloc2.NodeID = node.ID 2075 err = state.UpsertJobSummary(99, mock.JobSummary(alloc2.JobID)) 2076 require.Nil(err) 2077 alloc2.TaskGroup = job.TaskGroups[0].Name 2078 2079 err = state.UpsertAllocs(100, []*structs.Allocation{alloc, alloc2}) 2080 require.Nil(err) 2081 2082 // Attempt updates of more than one alloc for the same job 2083 clientAlloc1 := new(structs.Allocation) 2084 *clientAlloc1 = *alloc 2085 clientAlloc1.ClientStatus = structs.AllocClientStatusFailed 2086 2087 clientAlloc2 := new(structs.Allocation) 2088 *clientAlloc2 = *alloc2 2089 clientAlloc2.ClientStatus = structs.AllocClientStatusFailed 2090 2091 // Update the alloc 2092 update := &structs.AllocUpdateRequest{ 2093 Alloc: []*structs.Allocation{clientAlloc1, clientAlloc2}, 2094 WriteRequest: structs.WriteRequest{Region: "global"}, 2095 } 2096 var resp2 structs.NodeAllocsResponse 2097 start := time.Now() 2098 err = msgpackrpc.CallWithCodec(codec, "Node.UpdateAlloc", update, &resp2) 2099 require.Nil(err) 2100 require.NotEqual(0, resp2.Index) 2101 2102 if diff := time.Since(start); diff < batchUpdateInterval { 2103 t.Fatalf("too fast: %v", diff) 2104 } 2105 2106 // Lookup the alloc 2107 ws := memdb.NewWatchSet() 2108 out, err := state.AllocByID(ws, alloc.ID) 2109 require.Nil(err) 2110 require.Equal(structs.AllocClientStatusFailed, out.ClientStatus) 2111 require.True(out.ModifyTime > 0) 2112 2113 // Assert that exactly one eval with TriggeredBy EvalTriggerRetryFailedAlloc exists 2114 evaluations, err := state.EvalsByJob(ws, job.Namespace, job.ID) 2115 require.Nil(err) 2116 require.True(len(evaluations) != 0) 2117 foundCount := 0 2118 for _, resultEval := range evaluations { 2119 if resultEval.TriggeredBy == structs.EvalTriggerRetryFailedAlloc && resultEval.WaitUntil.IsZero() { 2120 foundCount++ 2121 } 2122 } 2123 require.Equal(1, foundCount, "Should create exactly one eval for failed allocs") 2124 2125 } 2126 2127 func TestClientEndpoint_BatchUpdate(t *testing.T) { 2128 t.Parallel() 2129 s1 := TestServer(t, nil) 2130 defer s1.Shutdown() 2131 codec := rpcClient(t, s1) 2132 testutil.WaitForLeader(t, s1.RPC) 2133 2134 // Create the register request 2135 node := mock.Node() 2136 reg := &structs.NodeRegisterRequest{ 2137 Node: node, 2138 WriteRequest: structs.WriteRequest{Region: "global"}, 2139 } 2140 2141 // Fetch the response 2142 var resp structs.GenericResponse 2143 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 2144 t.Fatalf("err: %v", err) 2145 } 2146 2147 // Inject fake evaluations 2148 alloc := mock.Alloc() 2149 alloc.NodeID = node.ID 2150 state := s1.fsm.State() 2151 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 2152 err := state.UpsertAllocs(100, []*structs.Allocation{alloc}) 2153 if err != nil { 2154 t.Fatalf("err: %v", err) 2155 } 2156 2157 // Attempt update 2158 clientAlloc := new(structs.Allocation) 2159 *clientAlloc = *alloc 2160 clientAlloc.ClientStatus = structs.AllocClientStatusFailed 2161 2162 // Call to do the batch update 2163 bf := structs.NewBatchFuture() 2164 endpoint := s1.staticEndpoints.Node 2165 endpoint.batchUpdate(bf, []*structs.Allocation{clientAlloc}, nil) 2166 if err := bf.Wait(); err != nil { 2167 t.Fatalf("err: %v", err) 2168 } 2169 if bf.Index() == 0 { 2170 t.Fatalf("Bad index: %d", bf.Index()) 2171 } 2172 2173 // Lookup the alloc 2174 ws := memdb.NewWatchSet() 2175 out, err := state.AllocByID(ws, alloc.ID) 2176 if err != nil { 2177 t.Fatalf("err: %v", err) 2178 } 2179 if out.ClientStatus != structs.AllocClientStatusFailed { 2180 t.Fatalf("Bad: %#v", out) 2181 } 2182 } 2183 2184 func TestClientEndpoint_UpdateAlloc_Vault(t *testing.T) { 2185 t.Parallel() 2186 s1 := TestServer(t, nil) 2187 defer s1.Shutdown() 2188 codec := rpcClient(t, s1) 2189 testutil.WaitForLeader(t, s1.RPC) 2190 2191 // Create the register request 2192 node := mock.Node() 2193 reg := &structs.NodeRegisterRequest{ 2194 Node: node, 2195 WriteRequest: structs.WriteRequest{Region: "global"}, 2196 } 2197 2198 // Fetch the response 2199 var resp structs.GenericResponse 2200 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 2201 t.Fatalf("err: %v", err) 2202 } 2203 2204 // Swap the servers Vault Client 2205 tvc := &TestVaultClient{} 2206 s1.vault = tvc 2207 2208 // Inject fake allocation and vault accessor 2209 alloc := mock.Alloc() 2210 alloc.NodeID = node.ID 2211 state := s1.fsm.State() 2212 state.UpsertJobSummary(99, mock.JobSummary(alloc.JobID)) 2213 if err := state.UpsertAllocs(100, []*structs.Allocation{alloc}); err != nil { 2214 t.Fatalf("err: %v", err) 2215 } 2216 2217 va := mock.VaultAccessor() 2218 va.NodeID = node.ID 2219 va.AllocID = alloc.ID 2220 if err := state.UpsertVaultAccessor(101, []*structs.VaultAccessor{va}); err != nil { 2221 t.Fatalf("err: %v", err) 2222 } 2223 2224 // Inject mock job 2225 job := mock.Job() 2226 job.ID = alloc.JobID 2227 err := state.UpsertJob(101, job) 2228 if err != nil { 2229 t.Fatalf("err: %v", err) 2230 } 2231 2232 // Attempt update 2233 clientAlloc := new(structs.Allocation) 2234 *clientAlloc = *alloc 2235 clientAlloc.ClientStatus = structs.AllocClientStatusFailed 2236 2237 // Update the alloc 2238 update := &structs.AllocUpdateRequest{ 2239 Alloc: []*structs.Allocation{clientAlloc}, 2240 WriteRequest: structs.WriteRequest{Region: "global"}, 2241 } 2242 var resp2 structs.NodeAllocsResponse 2243 start := time.Now() 2244 if err := msgpackrpc.CallWithCodec(codec, "Node.UpdateAlloc", update, &resp2); err != nil { 2245 t.Fatalf("err: %v", err) 2246 } 2247 if resp2.Index == 0 { 2248 t.Fatalf("Bad index: %d", resp2.Index) 2249 } 2250 if diff := time.Since(start); diff < batchUpdateInterval { 2251 t.Fatalf("too fast: %v", diff) 2252 } 2253 2254 // Lookup the alloc 2255 ws := memdb.NewWatchSet() 2256 out, err := state.AllocByID(ws, alloc.ID) 2257 if err != nil { 2258 t.Fatalf("err: %v", err) 2259 } 2260 if out.ClientStatus != structs.AllocClientStatusFailed { 2261 t.Fatalf("Bad: %#v", out) 2262 } 2263 2264 if l := len(tvc.RevokedTokens); l != 1 { 2265 t.Fatalf("Deregister revoked %d tokens; want 1", l) 2266 } 2267 } 2268 2269 func TestClientEndpoint_CreateNodeEvals(t *testing.T) { 2270 t.Parallel() 2271 s1 := TestServer(t, nil) 2272 defer s1.Shutdown() 2273 testutil.WaitForLeader(t, s1.RPC) 2274 2275 // Inject fake evaluations 2276 alloc := mock.Alloc() 2277 state := s1.fsm.State() 2278 state.UpsertJobSummary(1, mock.JobSummary(alloc.JobID)) 2279 if err := state.UpsertAllocs(2, []*structs.Allocation{alloc}); err != nil { 2280 t.Fatalf("err: %v", err) 2281 } 2282 2283 // Inject a fake system job. 2284 job := mock.SystemJob() 2285 if err := state.UpsertJob(3, job); err != nil { 2286 t.Fatalf("err: %v", err) 2287 } 2288 2289 // Create some evaluations 2290 ids, index, err := s1.staticEndpoints.Node.createNodeEvals(alloc.NodeID, 1) 2291 if err != nil { 2292 t.Fatalf("err: %v", err) 2293 } 2294 if index == 0 { 2295 t.Fatalf("bad: %d", index) 2296 } 2297 if len(ids) != 2 { 2298 t.Fatalf("bad: %s", ids) 2299 } 2300 2301 // Lookup the evaluations 2302 ws := memdb.NewWatchSet() 2303 evalByType := make(map[string]*structs.Evaluation, 2) 2304 for _, id := range ids { 2305 eval, err := state.EvalByID(ws, id) 2306 if err != nil { 2307 t.Fatalf("err: %v", err) 2308 } 2309 if eval == nil { 2310 t.Fatalf("expected eval") 2311 } 2312 2313 if old, ok := evalByType[eval.Type]; ok { 2314 t.Fatalf("multiple evals of the same type: %v and %v", old, eval) 2315 } 2316 2317 evalByType[eval.Type] = eval 2318 } 2319 2320 if len(evalByType) != 2 { 2321 t.Fatalf("Expected a service and system job; got %#v", evalByType) 2322 } 2323 2324 // Ensure the evals are correct. 2325 for schedType, eval := range evalByType { 2326 expPriority := alloc.Job.Priority 2327 expJobID := alloc.JobID 2328 if schedType == "system" { 2329 expPriority = job.Priority 2330 expJobID = job.ID 2331 } 2332 2333 if eval.CreateIndex != index { 2334 t.Fatalf("CreateIndex mis-match on type %v: %#v", schedType, eval) 2335 } 2336 if eval.TriggeredBy != structs.EvalTriggerNodeUpdate { 2337 t.Fatalf("TriggeredBy incorrect on type %v: %#v", schedType, eval) 2338 } 2339 if eval.NodeID != alloc.NodeID { 2340 t.Fatalf("NodeID incorrect on type %v: %#v", schedType, eval) 2341 } 2342 if eval.NodeModifyIndex != 1 { 2343 t.Fatalf("NodeModifyIndex incorrect on type %v: %#v", schedType, eval) 2344 } 2345 if eval.Status != structs.EvalStatusPending { 2346 t.Fatalf("Status incorrect on type %v: %#v", schedType, eval) 2347 } 2348 if eval.Priority != expPriority { 2349 t.Fatalf("Priority incorrect on type %v: %#v", schedType, eval) 2350 } 2351 if eval.JobID != expJobID { 2352 t.Fatalf("JobID incorrect on type %v: %#v", schedType, eval) 2353 } 2354 } 2355 } 2356 2357 func TestClientEndpoint_Evaluate(t *testing.T) { 2358 t.Parallel() 2359 s1 := TestServer(t, func(c *Config) { 2360 c.NumSchedulers = 0 // Prevent automatic dequeue 2361 }) 2362 defer s1.Shutdown() 2363 codec := rpcClient(t, s1) 2364 testutil.WaitForLeader(t, s1.RPC) 2365 2366 // Inject fake evaluations 2367 alloc := mock.Alloc() 2368 node := mock.Node() 2369 node.ID = alloc.NodeID 2370 state := s1.fsm.State() 2371 err := state.UpsertNode(1, node) 2372 if err != nil { 2373 t.Fatalf("err: %v", err) 2374 } 2375 state.UpsertJobSummary(2, mock.JobSummary(alloc.JobID)) 2376 err = state.UpsertAllocs(3, []*structs.Allocation{alloc}) 2377 if err != nil { 2378 t.Fatalf("err: %v", err) 2379 } 2380 2381 // Re-evaluate 2382 req := &structs.NodeEvaluateRequest{ 2383 NodeID: alloc.NodeID, 2384 WriteRequest: structs.WriteRequest{Region: "global"}, 2385 } 2386 2387 // Fetch the response 2388 var resp structs.NodeUpdateResponse 2389 if err := msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp); err != nil { 2390 t.Fatalf("err: %v", err) 2391 } 2392 if resp.Index == 0 { 2393 t.Fatalf("bad index: %d", resp.Index) 2394 } 2395 2396 // Create some evaluations 2397 ids := resp.EvalIDs 2398 if len(ids) != 1 { 2399 t.Fatalf("bad: %s", ids) 2400 } 2401 2402 // Lookup the evaluation 2403 ws := memdb.NewWatchSet() 2404 eval, err := state.EvalByID(ws, ids[0]) 2405 if err != nil { 2406 t.Fatalf("err: %v", err) 2407 } 2408 if eval == nil { 2409 t.Fatalf("expected eval") 2410 } 2411 if eval.CreateIndex != resp.Index { 2412 t.Fatalf("index mis-match") 2413 } 2414 2415 if eval.Priority != alloc.Job.Priority { 2416 t.Fatalf("bad: %#v", eval) 2417 } 2418 if eval.Type != alloc.Job.Type { 2419 t.Fatalf("bad: %#v", eval) 2420 } 2421 if eval.TriggeredBy != structs.EvalTriggerNodeUpdate { 2422 t.Fatalf("bad: %#v", eval) 2423 } 2424 if eval.JobID != alloc.JobID { 2425 t.Fatalf("bad: %#v", eval) 2426 } 2427 if eval.NodeID != alloc.NodeID { 2428 t.Fatalf("bad: %#v", eval) 2429 } 2430 if eval.NodeModifyIndex != 1 { 2431 t.Fatalf("bad: %#v", eval) 2432 } 2433 if eval.Status != structs.EvalStatusPending { 2434 t.Fatalf("bad: %#v", eval) 2435 } 2436 } 2437 2438 func TestClientEndpoint_Evaluate_ACL(t *testing.T) { 2439 t.Parallel() 2440 s1, root := TestACLServer(t, nil) 2441 defer s1.Shutdown() 2442 codec := rpcClient(t, s1) 2443 testutil.WaitForLeader(t, s1.RPC) 2444 assert := assert.New(t) 2445 2446 // Create the node with an alloc 2447 alloc := mock.Alloc() 2448 node := mock.Node() 2449 node.ID = alloc.NodeID 2450 state := s1.fsm.State() 2451 2452 assert.Nil(state.UpsertNode(1, node), "UpsertNode") 2453 assert.Nil(state.UpsertJobSummary(2, mock.JobSummary(alloc.JobID)), "UpsertJobSummary") 2454 assert.Nil(state.UpsertAllocs(3, []*structs.Allocation{alloc}), "UpsertAllocs") 2455 2456 // Create the policy and tokens 2457 validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid", mock.NodePolicy(acl.PolicyWrite)) 2458 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", mock.NodePolicy(acl.PolicyRead)) 2459 2460 // Re-evaluate without a token and expect failure 2461 req := &structs.NodeEvaluateRequest{ 2462 NodeID: alloc.NodeID, 2463 WriteRequest: structs.WriteRequest{Region: "global"}, 2464 } 2465 { 2466 var resp structs.NodeUpdateResponse 2467 err := msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp) 2468 assert.NotNil(err, "RPC") 2469 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 2470 } 2471 2472 // Try with a valid token 2473 req.AuthToken = validToken.SecretID 2474 { 2475 var resp structs.NodeUpdateResponse 2476 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp), "RPC") 2477 } 2478 2479 // Try with a invalid token 2480 req.AuthToken = invalidToken.SecretID 2481 { 2482 var resp structs.NodeUpdateResponse 2483 err := msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp) 2484 assert.NotNil(err, "RPC") 2485 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 2486 } 2487 2488 // Try with a root token 2489 req.AuthToken = root.SecretID 2490 { 2491 var resp structs.NodeUpdateResponse 2492 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.Evaluate", req, &resp), "RPC") 2493 } 2494 } 2495 2496 func TestClientEndpoint_ListNodes(t *testing.T) { 2497 t.Parallel() 2498 s1 := TestServer(t, nil) 2499 defer s1.Shutdown() 2500 codec := rpcClient(t, s1) 2501 testutil.WaitForLeader(t, s1.RPC) 2502 2503 // Create the register request 2504 node := mock.Node() 2505 reg := &structs.NodeRegisterRequest{ 2506 Node: node, 2507 WriteRequest: structs.WriteRequest{Region: "global"}, 2508 } 2509 2510 // Fetch the response 2511 var resp structs.GenericResponse 2512 if err := msgpackrpc.CallWithCodec(codec, "Node.Register", reg, &resp); err != nil { 2513 t.Fatalf("err: %v", err) 2514 } 2515 node.CreateIndex = resp.Index 2516 node.ModifyIndex = resp.Index 2517 2518 // Lookup the node 2519 get := &structs.NodeListRequest{ 2520 QueryOptions: structs.QueryOptions{Region: "global"}, 2521 } 2522 var resp2 structs.NodeListResponse 2523 if err := msgpackrpc.CallWithCodec(codec, "Node.List", get, &resp2); err != nil { 2524 t.Fatalf("err: %v", err) 2525 } 2526 if resp2.Index != resp.Index { 2527 t.Fatalf("Bad index: %d %d", resp2.Index, resp.Index) 2528 } 2529 2530 if len(resp2.Nodes) != 1 { 2531 t.Fatalf("bad: %#v", resp2.Nodes) 2532 } 2533 if resp2.Nodes[0].ID != node.ID { 2534 t.Fatalf("bad: %#v", resp2.Nodes[0]) 2535 } 2536 2537 // Lookup the node with prefix 2538 get = &structs.NodeListRequest{ 2539 QueryOptions: structs.QueryOptions{Region: "global", Prefix: node.ID[:4]}, 2540 } 2541 var resp3 structs.NodeListResponse 2542 if err := msgpackrpc.CallWithCodec(codec, "Node.List", get, &resp3); err != nil { 2543 t.Fatalf("err: %v", err) 2544 } 2545 if resp3.Index != resp.Index { 2546 t.Fatalf("Bad index: %d %d", resp3.Index, resp2.Index) 2547 } 2548 2549 if len(resp3.Nodes) != 1 { 2550 t.Fatalf("bad: %#v", resp3.Nodes) 2551 } 2552 if resp3.Nodes[0].ID != node.ID { 2553 t.Fatalf("bad: %#v", resp3.Nodes[0]) 2554 } 2555 } 2556 2557 func TestClientEndpoint_ListNodes_ACL(t *testing.T) { 2558 t.Parallel() 2559 s1, root := TestACLServer(t, nil) 2560 defer s1.Shutdown() 2561 codec := rpcClient(t, s1) 2562 testutil.WaitForLeader(t, s1.RPC) 2563 assert := assert.New(t) 2564 2565 // Create the node 2566 node := mock.Node() 2567 state := s1.fsm.State() 2568 assert.Nil(state.UpsertNode(1, node), "UpsertNode") 2569 2570 // Create the namespace policy and tokens 2571 validToken := mock.CreatePolicyAndToken(t, state, 1001, "test-valid", mock.NodePolicy(acl.PolicyRead)) 2572 invalidToken := mock.CreatePolicyAndToken(t, state, 1003, "test-invalid", mock.NodePolicy(acl.PolicyDeny)) 2573 2574 // Lookup the node without a token and expect failure 2575 req := &structs.NodeListRequest{ 2576 QueryOptions: structs.QueryOptions{Region: "global"}, 2577 } 2578 { 2579 var resp structs.NodeListResponse 2580 err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp) 2581 assert.NotNil(err, "RPC") 2582 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 2583 } 2584 2585 // Try with a valid token 2586 req.AuthToken = validToken.SecretID 2587 { 2588 var resp structs.NodeListResponse 2589 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp), "RPC") 2590 assert.Equal(node.ID, resp.Nodes[0].ID) 2591 } 2592 2593 // Try with a invalid token 2594 req.AuthToken = invalidToken.SecretID 2595 { 2596 var resp structs.NodeListResponse 2597 err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp) 2598 assert.NotNil(err, "RPC") 2599 assert.Equal(err.Error(), structs.ErrPermissionDenied.Error()) 2600 } 2601 2602 // Try with a root token 2603 req.AuthToken = root.SecretID 2604 { 2605 var resp structs.NodeListResponse 2606 assert.Nil(msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp), "RPC") 2607 assert.Equal(node.ID, resp.Nodes[0].ID) 2608 } 2609 } 2610 2611 func TestClientEndpoint_ListNodes_Blocking(t *testing.T) { 2612 t.Parallel() 2613 s1 := TestServer(t, nil) 2614 defer s1.Shutdown() 2615 state := s1.fsm.State() 2616 codec := rpcClient(t, s1) 2617 testutil.WaitForLeader(t, s1.RPC) 2618 2619 // Disable drainer to prevent drain from completing during test 2620 s1.nodeDrainer.SetEnabled(false, nil) 2621 2622 // Create the node 2623 node := mock.Node() 2624 2625 // Node upsert triggers watches 2626 errCh := make(chan error, 1) 2627 timer := time.AfterFunc(100*time.Millisecond, func() { 2628 errCh <- state.UpsertNode(2, node) 2629 }) 2630 defer timer.Stop() 2631 2632 req := &structs.NodeListRequest{ 2633 QueryOptions: structs.QueryOptions{ 2634 Region: "global", 2635 MinQueryIndex: 1, 2636 }, 2637 } 2638 start := time.Now() 2639 var resp structs.NodeListResponse 2640 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp); err != nil { 2641 t.Fatalf("err: %v", err) 2642 } 2643 2644 if err := <-errCh; err != nil { 2645 t.Fatalf("error from timer: %v", err) 2646 } 2647 2648 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 2649 t.Fatalf("should block (returned in %s) %#v", elapsed, resp) 2650 } 2651 if resp.Index != 2 { 2652 t.Fatalf("Bad index: %d %d", resp.Index, 2) 2653 } 2654 if len(resp.Nodes) != 1 || resp.Nodes[0].ID != node.ID { 2655 t.Fatalf("bad: %#v", resp.Nodes) 2656 } 2657 2658 // Node drain updates trigger watches. 2659 time.AfterFunc(100*time.Millisecond, func() { 2660 s := &structs.DrainStrategy{ 2661 DrainSpec: structs.DrainSpec{ 2662 Deadline: 10 * time.Second, 2663 }, 2664 } 2665 errCh <- state.UpdateNodeDrain(3, node.ID, s, false, nil) 2666 }) 2667 2668 req.MinQueryIndex = 2 2669 var resp2 structs.NodeListResponse 2670 start = time.Now() 2671 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp2); err != nil { 2672 t.Fatalf("err: %v", err) 2673 } 2674 2675 if err := <-errCh; err != nil { 2676 t.Fatalf("error from timer: %v", err) 2677 } 2678 2679 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 2680 t.Fatalf("should block (returned in %s) %#v", elapsed, resp2) 2681 } 2682 if resp2.Index != 3 { 2683 t.Fatalf("Bad index: %d %d", resp2.Index, 3) 2684 } 2685 if len(resp2.Nodes) != 1 || !resp2.Nodes[0].Drain { 2686 t.Fatalf("bad: %#v", resp2.Nodes) 2687 } 2688 2689 // Node status update triggers watches 2690 time.AfterFunc(100*time.Millisecond, func() { 2691 errCh <- state.UpdateNodeStatus(40, node.ID, structs.NodeStatusDown, nil) 2692 }) 2693 2694 req.MinQueryIndex = 38 2695 var resp3 structs.NodeListResponse 2696 start = time.Now() 2697 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp3); err != nil { 2698 t.Fatalf("err: %v", err) 2699 } 2700 2701 if err := <-errCh; err != nil { 2702 t.Fatalf("error from timer: %v", err) 2703 } 2704 2705 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 2706 t.Fatalf("should block (returned in %s) %#v", elapsed, resp3) 2707 } 2708 if resp3.Index != 40 { 2709 t.Fatalf("Bad index: %d %d", resp3.Index, 40) 2710 } 2711 if len(resp3.Nodes) != 1 || resp3.Nodes[0].Status != structs.NodeStatusDown { 2712 t.Fatalf("bad: %#v", resp3.Nodes) 2713 } 2714 2715 // Node delete triggers watches. 2716 time.AfterFunc(100*time.Millisecond, func() { 2717 errCh <- state.DeleteNode(50, node.ID) 2718 }) 2719 2720 req.MinQueryIndex = 45 2721 var resp4 structs.NodeListResponse 2722 start = time.Now() 2723 if err := msgpackrpc.CallWithCodec(codec, "Node.List", req, &resp4); err != nil { 2724 t.Fatalf("err: %v", err) 2725 } 2726 2727 if err := <-errCh; err != nil { 2728 t.Fatalf("error from timer: %v", err) 2729 } 2730 2731 if elapsed := time.Since(start); elapsed < 100*time.Millisecond { 2732 t.Fatalf("should block (returned in %s) %#v", elapsed, resp4) 2733 } 2734 if resp4.Index != 50 { 2735 t.Fatalf("Bad index: %d %d", resp4.Index, 50) 2736 } 2737 if len(resp4.Nodes) != 0 { 2738 t.Fatalf("bad: %#v", resp4.Nodes) 2739 } 2740 } 2741 2742 func TestClientEndpoint_DeriveVaultToken_Bad(t *testing.T) { 2743 t.Parallel() 2744 s1 := TestServer(t, nil) 2745 defer s1.Shutdown() 2746 state := s1.fsm.State() 2747 codec := rpcClient(t, s1) 2748 testutil.WaitForLeader(t, s1.RPC) 2749 2750 // Create the node 2751 node := mock.Node() 2752 if err := state.UpsertNode(2, node); err != nil { 2753 t.Fatalf("err: %v", err) 2754 } 2755 2756 // Create an alloc 2757 alloc := mock.Alloc() 2758 task := alloc.Job.TaskGroups[0].Tasks[0] 2759 tasks := []string{task.Name} 2760 if err := state.UpsertAllocs(3, []*structs.Allocation{alloc}); err != nil { 2761 t.Fatalf("err: %v", err) 2762 } 2763 2764 req := &structs.DeriveVaultTokenRequest{ 2765 NodeID: node.ID, 2766 SecretID: uuid.Generate(), 2767 AllocID: alloc.ID, 2768 Tasks: tasks, 2769 QueryOptions: structs.QueryOptions{ 2770 Region: "global", 2771 }, 2772 } 2773 2774 var resp structs.DeriveVaultTokenResponse 2775 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 2776 t.Fatalf("bad: %v", err) 2777 } 2778 2779 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "SecretID mismatch") { 2780 t.Fatalf("Expected SecretID mismatch: %v", resp.Error) 2781 } 2782 2783 // Put the correct SecretID 2784 req.SecretID = node.SecretID 2785 2786 // Now we should get an error about the allocation not running on the node 2787 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 2788 t.Fatalf("bad: %v", err) 2789 } 2790 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "not running on Node") { 2791 t.Fatalf("Expected not running on node error: %v", resp.Error) 2792 } 2793 2794 // Update to be running on the node 2795 alloc.NodeID = node.ID 2796 if err := state.UpsertAllocs(4, []*structs.Allocation{alloc}); err != nil { 2797 t.Fatalf("err: %v", err) 2798 } 2799 2800 // Now we should get an error about the job not needing any Vault secrets 2801 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 2802 t.Fatalf("bad: %v", err) 2803 } 2804 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "does not require") { 2805 t.Fatalf("Expected no policies error: %v", resp.Error) 2806 } 2807 2808 // Update to be terminal 2809 alloc.DesiredStatus = structs.AllocDesiredStatusStop 2810 if err := state.UpsertAllocs(5, []*structs.Allocation{alloc}); err != nil { 2811 t.Fatalf("err: %v", err) 2812 } 2813 2814 // Now we should get an error about the job not needing any Vault secrets 2815 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 2816 t.Fatalf("bad: %v", err) 2817 } 2818 if resp.Error == nil || !strings.Contains(resp.Error.Error(), "terminal") { 2819 t.Fatalf("Expected terminal allocation error: %v", resp.Error) 2820 } 2821 } 2822 2823 func TestClientEndpoint_DeriveVaultToken(t *testing.T) { 2824 t.Parallel() 2825 s1 := TestServer(t, nil) 2826 defer s1.Shutdown() 2827 state := s1.fsm.State() 2828 codec := rpcClient(t, s1) 2829 testutil.WaitForLeader(t, s1.RPC) 2830 2831 // Enable vault and allow authenticated 2832 tr := true 2833 s1.config.VaultConfig.Enabled = &tr 2834 s1.config.VaultConfig.AllowUnauthenticated = &tr 2835 2836 // Replace the Vault Client on the server 2837 tvc := &TestVaultClient{} 2838 s1.vault = tvc 2839 2840 // Create the node 2841 node := mock.Node() 2842 if err := state.UpsertNode(2, node); err != nil { 2843 t.Fatalf("err: %v", err) 2844 } 2845 2846 // Create an alloc an allocation that has vault policies required 2847 alloc := mock.Alloc() 2848 alloc.NodeID = node.ID 2849 task := alloc.Job.TaskGroups[0].Tasks[0] 2850 tasks := []string{task.Name} 2851 task.Vault = &structs.Vault{Policies: []string{"a", "b"}} 2852 if err := state.UpsertAllocs(3, []*structs.Allocation{alloc}); err != nil { 2853 t.Fatalf("err: %v", err) 2854 } 2855 2856 // Return a secret for the task 2857 token := uuid.Generate() 2858 accessor := uuid.Generate() 2859 ttl := 10 2860 secret := &vapi.Secret{ 2861 WrapInfo: &vapi.SecretWrapInfo{ 2862 Token: token, 2863 WrappedAccessor: accessor, 2864 TTL: ttl, 2865 }, 2866 } 2867 tvc.SetCreateTokenSecret(alloc.ID, task.Name, secret) 2868 2869 req := &structs.DeriveVaultTokenRequest{ 2870 NodeID: node.ID, 2871 SecretID: node.SecretID, 2872 AllocID: alloc.ID, 2873 Tasks: tasks, 2874 QueryOptions: structs.QueryOptions{ 2875 Region: "global", 2876 }, 2877 } 2878 2879 var resp structs.DeriveVaultTokenResponse 2880 if err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp); err != nil { 2881 t.Fatalf("bad: %v", err) 2882 } 2883 if resp.Error != nil { 2884 t.Fatalf("bad: %v", resp.Error) 2885 } 2886 2887 // Check the state store and ensure that we created a VaultAccessor 2888 ws := memdb.NewWatchSet() 2889 va, err := state.VaultAccessor(ws, accessor) 2890 if err != nil { 2891 t.Fatalf("bad: %v", err) 2892 } 2893 if va == nil { 2894 t.Fatalf("bad: %v", va) 2895 } 2896 2897 if va.CreateIndex == 0 { 2898 t.Fatalf("bad: %v", va) 2899 } 2900 2901 va.CreateIndex = 0 2902 expected := &structs.VaultAccessor{ 2903 AllocID: alloc.ID, 2904 Task: task.Name, 2905 NodeID: alloc.NodeID, 2906 Accessor: accessor, 2907 CreationTTL: ttl, 2908 } 2909 2910 if !reflect.DeepEqual(expected, va) { 2911 t.Fatalf("Got %#v; want %#v", va, expected) 2912 } 2913 } 2914 2915 func TestClientEndpoint_DeriveVaultToken_VaultError(t *testing.T) { 2916 t.Parallel() 2917 s1 := TestServer(t, nil) 2918 defer s1.Shutdown() 2919 state := s1.fsm.State() 2920 codec := rpcClient(t, s1) 2921 testutil.WaitForLeader(t, s1.RPC) 2922 2923 // Enable vault and allow authenticated 2924 tr := true 2925 s1.config.VaultConfig.Enabled = &tr 2926 s1.config.VaultConfig.AllowUnauthenticated = &tr 2927 2928 // Replace the Vault Client on the server 2929 tvc := &TestVaultClient{} 2930 s1.vault = tvc 2931 2932 // Create the node 2933 node := mock.Node() 2934 if err := state.UpsertNode(2, node); err != nil { 2935 t.Fatalf("err: %v", err) 2936 } 2937 2938 // Create an alloc an allocation that has vault policies required 2939 alloc := mock.Alloc() 2940 alloc.NodeID = node.ID 2941 task := alloc.Job.TaskGroups[0].Tasks[0] 2942 tasks := []string{task.Name} 2943 task.Vault = &structs.Vault{Policies: []string{"a", "b"}} 2944 if err := state.UpsertAllocs(3, []*structs.Allocation{alloc}); err != nil { 2945 t.Fatalf("err: %v", err) 2946 } 2947 2948 // Return an error when creating the token 2949 tvc.SetCreateTokenError(alloc.ID, task.Name, 2950 structs.NewRecoverableError(fmt.Errorf("recover"), true)) 2951 2952 req := &structs.DeriveVaultTokenRequest{ 2953 NodeID: node.ID, 2954 SecretID: node.SecretID, 2955 AllocID: alloc.ID, 2956 Tasks: tasks, 2957 QueryOptions: structs.QueryOptions{ 2958 Region: "global", 2959 }, 2960 } 2961 2962 var resp structs.DeriveVaultTokenResponse 2963 err := msgpackrpc.CallWithCodec(codec, "Node.DeriveVaultToken", req, &resp) 2964 if err != nil { 2965 t.Fatalf("bad: %v", err) 2966 } 2967 if resp.Error == nil || !resp.Error.IsRecoverable() { 2968 t.Fatalf("bad: %+v", resp.Error) 2969 } 2970 } 2971 2972 func TestClientEndpoint_EmitEvents(t *testing.T) { 2973 t.Parallel() 2974 require := require.New(t) 2975 2976 s1 := TestServer(t, nil) 2977 state := s1.fsm.State() 2978 defer s1.Shutdown() 2979 codec := rpcClient(t, s1) 2980 testutil.WaitForLeader(t, s1.RPC) 2981 2982 // create a node that we can register our event to 2983 node := mock.Node() 2984 err := state.UpsertNode(2, node) 2985 require.Nil(err) 2986 2987 nodeEvent := &structs.NodeEvent{ 2988 Message: "Registration failed", 2989 Subsystem: "Server", 2990 Timestamp: time.Now(), 2991 } 2992 2993 nodeEvents := map[string][]*structs.NodeEvent{node.ID: {nodeEvent}} 2994 req := structs.EmitNodeEventsRequest{ 2995 NodeEvents: nodeEvents, 2996 WriteRequest: structs.WriteRequest{Region: "global"}, 2997 } 2998 2999 var resp structs.GenericResponse 3000 err = msgpackrpc.CallWithCodec(codec, "Node.EmitEvents", &req, &resp) 3001 require.Nil(err) 3002 require.NotEqual(0, resp.Index) 3003 3004 // Check for the node in the FSM 3005 ws := memdb.NewWatchSet() 3006 out, err := state.NodeByID(ws, node.ID) 3007 require.Nil(err) 3008 require.False(len(out.Events) < 2) 3009 }