github.com/sl1pm4t/consul@v1.4.5-0.20190325224627-74c31c540f9c/agent/consul/state/catalog_test.go (about) 1 package state 2 3 import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "strings" 8 "testing" 9 10 "github.com/hashicorp/consul/agent/structs" 11 "github.com/hashicorp/consul/api" 12 "github.com/hashicorp/consul/lib" 13 "github.com/hashicorp/consul/types" 14 "github.com/hashicorp/go-memdb" 15 uuid "github.com/hashicorp/go-uuid" 16 "github.com/pascaldekloe/goe/verify" 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func makeRandomNodeID(t *testing.T) types.NodeID { 22 id, err := uuid.GenerateUUID() 23 if err != nil { 24 t.Fatalf("err: %v", err) 25 } 26 return types.NodeID(id) 27 } 28 29 func TestStateStore_GetNodeID(t *testing.T) { 30 s := testStateStore(t) 31 _, out, err := s.GetNodeID(types.NodeID("wrongId")) 32 if err == nil || out != nil || !strings.Contains(err.Error(), "node lookup by ID failed, wrong UUID") { 33 t.Fatalf("want an error, nil value, err:=%q ; out:=%q", err.Error(), out) 34 } 35 _, out, err = s.GetNodeID(types.NodeID("0123456789abcdefghijklmnopqrstuvwxyz")) 36 if err == nil || out != nil || !strings.Contains(err.Error(), "node lookup by ID failed, wrong UUID") { 37 t.Fatalf("want an error, nil value, err:=%q ; out:=%q", err, out) 38 } 39 40 _, out, err = s.GetNodeID(types.NodeID("00a916bc-a357-4a19-b886-59419fcee50Z")) 41 if err == nil || out != nil || !strings.Contains(err.Error(), "node lookup by ID failed, wrong UUID") { 42 t.Fatalf("want an error, nil value, err:=%q ; out:=%q", err, out) 43 } 44 45 _, out, err = s.GetNodeID(types.NodeID("00a916bc-a357-4a19-b886-59419fcee506")) 46 if err != nil || out != nil { 47 t.Fatalf("do not want any error nor returned value, err:=%q ; out:=%q", err, out) 48 } 49 50 nodeID := types.NodeID("00a916bc-a357-4a19-b886-59419fceeaaa") 51 req := &structs.RegisterRequest{ 52 ID: nodeID, 53 Node: "node1", 54 Address: "1.2.3.4", 55 } 56 if err := s.EnsureRegistration(1, req); err != nil { 57 t.Fatalf("err: %s", err) 58 } 59 60 _, out, err = s.GetNodeID(nodeID) 61 if err != nil { 62 t.Fatalf("got err %s want nil", err) 63 } 64 if out == nil || out.ID != nodeID { 65 t.Fatalf("out should not be nil and contain nodeId, but was:=%#v", out) 66 } 67 // Case insensitive lookup should work as well 68 _, out, err = s.GetNodeID(types.NodeID("00a916bC-a357-4a19-b886-59419fceeAAA")) 69 if err != nil { 70 t.Fatalf("got err %s want nil", err) 71 } 72 if out == nil || out.ID != nodeID { 73 t.Fatalf("out should not be nil and contain nodeId, but was:=%#v", out) 74 } 75 } 76 77 func TestStateStore_ensureNoNodeWithSimilarNameTxn(t *testing.T) { 78 t.Parallel() 79 s := testStateStore(t) 80 nodeID := makeRandomNodeID(t) 81 req := &structs.RegisterRequest{ 82 ID: nodeID, 83 Node: "node1", 84 Address: "1.2.3.4", 85 TaggedAddresses: map[string]string{"hello": "world"}, 86 NodeMeta: map[string]string{"somekey": "somevalue"}, 87 } 88 if err := s.EnsureRegistration(1, req); err != nil { 89 t.Fatalf("err: %s", err) 90 } 91 req = &structs.RegisterRequest{ 92 ID: types.NodeID(""), 93 Node: "node2", 94 Address: "10.0.0.1", 95 } 96 if err := s.EnsureRegistration(2, req); err != nil { 97 t.Fatalf("err: %s", err) 98 } 99 tx := s.db.Txn(true) 100 defer tx.Abort() 101 node := &structs.Node{ 102 ID: makeRandomNodeID(t), 103 Node: "NOdE1", // Name is similar but case is different 104 Address: "2.3.4.5", 105 } 106 // Lets conflict with node1 (has an ID) 107 if err := s.ensureNoNodeWithSimilarNameTxn(tx, node, false); err == nil { 108 t.Fatalf("Should return an error since another name with similar name exists") 109 } 110 if err := s.ensureNoNodeWithSimilarNameTxn(tx, node, true); err == nil { 111 t.Fatalf("Should return an error since another name with similar name exists") 112 } 113 // Lets conflict with node without ID 114 node.Node = "NoDe2" 115 if err := s.ensureNoNodeWithSimilarNameTxn(tx, node, false); err == nil { 116 t.Fatalf("Should return an error since another name with similar name exists") 117 } 118 if err := s.ensureNoNodeWithSimilarNameTxn(tx, node, true); err != nil { 119 t.Fatalf("Should not clash with another similar node name without ID, err:=%q", err) 120 } 121 122 } 123 124 func TestStateStore_EnsureRegistration(t *testing.T) { 125 t.Parallel() 126 s := testStateStore(t) 127 128 // Start with just a node. 129 nodeID := makeRandomNodeID(t) 130 req := &structs.RegisterRequest{ 131 ID: nodeID, 132 Node: "node1", 133 Address: "1.2.3.4", 134 TaggedAddresses: map[string]string{"hello": "world"}, 135 NodeMeta: map[string]string{"somekey": "somevalue"}, 136 } 137 if err := s.EnsureRegistration(1, req); err != nil { 138 t.Fatalf("err: %s", err) 139 } 140 141 // Retrieve the node and verify its contents. 142 verifyNode := func() { 143 node := &structs.Node{ 144 ID: nodeID, 145 Node: "node1", 146 Address: "1.2.3.4", 147 TaggedAddresses: map[string]string{"hello": "world"}, 148 Meta: map[string]string{"somekey": "somevalue"}, 149 RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 1}, 150 } 151 152 _, out, err := s.GetNode("node1") 153 if err != nil { 154 t.Fatalf("got err %s want nil", err) 155 } 156 if got, want := out, node; !verify.Values(t, "GetNode", got, want) { 157 t.FailNow() 158 } 159 160 _, out2, err := s.GetNodeID(nodeID) 161 if err != nil { 162 t.Fatalf("got err %s want nil", err) 163 } 164 if out2 == nil { 165 t.Fatalf("out2 should not be nil") 166 } 167 if got, want := out, out2; !verify.Values(t, "GetNodeID", got, want) { 168 t.FailNow() 169 } 170 } 171 verifyNode() 172 173 // Add in a invalid service definition with too long Key value for Meta 174 req.Service = &structs.NodeService{ 175 ID: "redis1", 176 Service: "redis", 177 Address: "1.1.1.1", 178 Port: 8080, 179 Meta: map[string]string{strings.Repeat("a", 129): "somevalue"}, 180 Tags: []string{"master"}, 181 } 182 if err := s.EnsureRegistration(9, req); err == nil { 183 t.Fatalf("Service should not have been registered since Meta is invalid") 184 } 185 186 // Add in a service definition. 187 req.Service = &structs.NodeService{ 188 ID: "redis1", 189 Service: "redis", 190 Address: "1.1.1.1", 191 Port: 8080, 192 Tags: []string{"master"}, 193 Weights: &structs.Weights{Passing: 1, Warning: 1}, 194 } 195 if err := s.EnsureRegistration(2, req); err != nil { 196 t.Fatalf("err: %s", err) 197 } 198 199 // Verify that the service got registered. 200 verifyService := func() { 201 svcmap := map[string]*structs.NodeService{ 202 "redis1": &structs.NodeService{ 203 ID: "redis1", 204 Service: "redis", 205 Address: "1.1.1.1", 206 Port: 8080, 207 Tags: []string{"master"}, 208 Weights: &structs.Weights{Passing: 1, Warning: 1}, 209 RaftIndex: structs.RaftIndex{CreateIndex: 2, ModifyIndex: 2}, 210 }, 211 } 212 213 idx, out, err := s.NodeServices(nil, "node1") 214 if gotidx, wantidx := idx, uint64(2); err != nil || gotidx != wantidx { 215 t.Fatalf("got err, idx: %s, %d want nil, %d", err, gotidx, wantidx) 216 } 217 if got, want := out.Services, svcmap; !verify.Values(t, "NodeServices", got, want) { 218 t.FailNow() 219 } 220 221 idx, r, err := s.NodeService("node1", "redis1") 222 if gotidx, wantidx := idx, uint64(2); err != nil || gotidx != wantidx { 223 t.Fatalf("got err, idx: %s, %d want nil, %d", err, gotidx, wantidx) 224 } 225 if got, want := r, svcmap["redis1"]; !verify.Values(t, "NodeService", got, want) { 226 t.FailNow() 227 } 228 } 229 verifyNode() 230 verifyService() 231 232 // Add in a top-level check. 233 req.Check = &structs.HealthCheck{ 234 Node: "node1", 235 CheckID: "check1", 236 Name: "check", 237 } 238 if err := s.EnsureRegistration(3, req); err != nil { 239 t.Fatalf("err: %s", err) 240 } 241 242 // Verify that the check got registered. 243 verifyCheck := func() { 244 checks := structs.HealthChecks{ 245 &structs.HealthCheck{ 246 Node: "node1", 247 CheckID: "check1", 248 Name: "check", 249 Status: "critical", 250 RaftIndex: structs.RaftIndex{CreateIndex: 3, ModifyIndex: 3}, 251 }, 252 } 253 254 idx, out, err := s.NodeChecks(nil, "node1") 255 if gotidx, wantidx := idx, uint64(3); err != nil || gotidx != wantidx { 256 t.Fatalf("got err, idx: %s, %d want nil, %d", err, gotidx, wantidx) 257 } 258 if got, want := out, checks; !verify.Values(t, "NodeChecks", got, want) { 259 t.FailNow() 260 } 261 262 idx, c, err := s.NodeCheck("node1", "check1") 263 if gotidx, wantidx := idx, uint64(3); err != nil || gotidx != wantidx { 264 t.Fatalf("got err, idx: %s, %d want nil, %d", err, gotidx, wantidx) 265 } 266 if got, want := c, checks[0]; !verify.Values(t, "NodeCheck", got, want) { 267 t.FailNow() 268 } 269 } 270 verifyNode() 271 verifyService() 272 verifyCheck() 273 274 // Add a service check which should populate the ServiceName 275 // and ServiceTags fields in the response. 276 req.Checks = structs.HealthChecks{ 277 &structs.HealthCheck{ 278 Node: "node1", 279 CheckID: "check2", 280 Name: "check", 281 ServiceID: "redis1", 282 }, 283 } 284 if err := s.EnsureRegistration(4, req); err != nil { 285 t.Fatalf("err: %s", err) 286 } 287 288 // Verify that the additional check got registered. 289 verifyNode() 290 verifyService() 291 verifyChecks := func() { 292 checks := structs.HealthChecks{ 293 &structs.HealthCheck{ 294 Node: "node1", 295 CheckID: "check1", 296 Name: "check", 297 Status: "critical", 298 RaftIndex: structs.RaftIndex{CreateIndex: 3, ModifyIndex: 3}, 299 }, 300 &structs.HealthCheck{ 301 Node: "node1", 302 CheckID: "check2", 303 Name: "check", 304 Status: "critical", 305 ServiceID: "redis1", 306 ServiceName: "redis", 307 ServiceTags: []string{"master"}, 308 RaftIndex: structs.RaftIndex{CreateIndex: 4, ModifyIndex: 4}, 309 }, 310 } 311 312 idx, out, err := s.NodeChecks(nil, "node1") 313 if gotidx, wantidx := idx, uint64(4); err != nil || gotidx != wantidx { 314 t.Fatalf("got err, idx: %s, %d want nil, %d", err, gotidx, wantidx) 315 } 316 if got, want := out, checks; !verify.Values(t, "NodeChecks", got, want) { 317 t.FailNow() 318 } 319 } 320 verifyChecks() 321 322 // Try to register a check for some other node (top-level check). 323 req.Check = &structs.HealthCheck{ 324 Node: "nope", 325 CheckID: "check1", 326 Name: "check", 327 } 328 err := s.EnsureRegistration(5, req) 329 if err == nil || !strings.Contains(err.Error(), "does not match node") { 330 t.Fatalf("err: %s", err) 331 } 332 verifyNode() 333 verifyService() 334 verifyChecks() 335 336 // Try to register a check for some other node (checks array). 337 req.Check = nil 338 req.Checks = structs.HealthChecks{ 339 &structs.HealthCheck{ 340 Node: "nope", 341 CheckID: "check2", 342 Name: "check", 343 }, 344 } 345 err = s.EnsureRegistration(6, req) 346 if err == nil || !strings.Contains(err.Error(), "does not match node") { 347 t.Fatalf("err: %s", err) 348 } 349 verifyNode() 350 verifyService() 351 verifyChecks() 352 } 353 354 func TestStateStore_EnsureRegistration_Restore(t *testing.T) { 355 s := testStateStore(t) 356 357 // Start with just a node. 358 req := &structs.RegisterRequest{ 359 ID: makeRandomNodeID(t), 360 Node: "node1", 361 Address: "1.2.3.4", 362 } 363 nodeID := string(req.ID) 364 nodeName := string(req.Node) 365 restore := s.Restore() 366 if err := restore.Registration(1, req); err != nil { 367 t.Fatalf("err: %s", err) 368 } 369 restore.Commit() 370 371 // Retrieve the node and verify its contents. 372 verifyNode := func(nodeLookup string) { 373 _, out, err := s.GetNode(nodeLookup) 374 if err != nil { 375 t.Fatalf("err: %s", err) 376 } 377 if out == nil { 378 _, out, err = s.GetNodeID(types.NodeID(nodeLookup)) 379 if err != nil { 380 t.Fatalf("err: %s", err) 381 } 382 } 383 384 if out == nil || out.Address != "1.2.3.4" || 385 !(out.Node == nodeLookup || string(out.ID) == nodeLookup) || 386 out.CreateIndex != 1 || out.ModifyIndex != 1 { 387 t.Fatalf("bad node returned: %#v", out) 388 } 389 } 390 verifyNode(nodeID) 391 verifyNode(nodeName) 392 393 // Add in a service definition. 394 req.Service = &structs.NodeService{ 395 ID: "redis1", 396 Service: "redis", 397 Address: "1.1.1.1", 398 Port: 8080, 399 Weights: &structs.Weights{Passing: 1, Warning: 1}, 400 } 401 restore = s.Restore() 402 if err := restore.Registration(2, req); err != nil { 403 t.Fatalf("err: %s", err) 404 } 405 restore.Commit() 406 407 // Verify that the service got registered. 408 verifyService := func(nodeLookup string) { 409 idx, out, err := s.NodeServices(nil, nodeLookup) 410 if err != nil { 411 t.Fatalf("err: %s", err) 412 } 413 if idx != 2 { 414 t.Fatalf("bad index: %d", idx) 415 } 416 if len(out.Services) != 1 { 417 t.Fatalf("bad: %#v", out.Services) 418 } 419 s := out.Services["redis1"] 420 if s.ID != "redis1" || s.Service != "redis" || 421 s.Address != "1.1.1.1" || s.Port != 8080 || 422 s.CreateIndex != 2 || s.ModifyIndex != 2 { 423 t.Fatalf("bad service returned: %#v", s) 424 } 425 } 426 427 // Add in a top-level check. 428 req.Check = &structs.HealthCheck{ 429 Node: nodeName, 430 CheckID: "check1", 431 Name: "check", 432 } 433 restore = s.Restore() 434 if err := restore.Registration(3, req); err != nil { 435 t.Fatalf("err: %s", err) 436 } 437 restore.Commit() 438 439 // Verify that the check got registered. 440 verifyCheck := func() { 441 idx, out, err := s.NodeChecks(nil, nodeName) 442 if err != nil { 443 t.Fatalf("err: %s", err) 444 } 445 if idx != 3 { 446 t.Fatalf("bad index: %d", idx) 447 } 448 if len(out) != 1 { 449 t.Fatalf("bad: %#v", out) 450 } 451 c := out[0] 452 if c.Node != nodeName || c.CheckID != "check1" || c.Name != "check" || 453 c.CreateIndex != 3 || c.ModifyIndex != 3 { 454 t.Fatalf("bad check returned: %#v", c) 455 } 456 } 457 verifyNode(nodeID) 458 verifyNode(nodeName) 459 verifyService(nodeID) 460 verifyService(nodeName) 461 verifyCheck() 462 463 // Add in another check via the slice. 464 req.Checks = structs.HealthChecks{ 465 &structs.HealthCheck{ 466 Node: nodeName, 467 CheckID: "check2", 468 Name: "check", 469 }, 470 } 471 restore = s.Restore() 472 if err := restore.Registration(4, req); err != nil { 473 t.Fatalf("err: %s", err) 474 } 475 restore.Commit() 476 477 // Verify that the additional check got registered. 478 verifyNode(nodeID) 479 verifyNode(nodeName) 480 verifyService(nodeID) 481 verifyService(nodeName) 482 func() { 483 idx, out, err := s.NodeChecks(nil, nodeName) 484 if err != nil { 485 t.Fatalf("err: %s", err) 486 } 487 if idx != 4 { 488 t.Fatalf("bad index: %d", idx) 489 } 490 if len(out) != 2 { 491 t.Fatalf("bad: %#v", out) 492 } 493 c1 := out[0] 494 if c1.Node != nodeName || c1.CheckID != "check1" || c1.Name != "check" || 495 c1.CreateIndex != 3 || c1.ModifyIndex != 3 { 496 t.Fatalf("bad check returned, should not be modified: %#v", c1) 497 } 498 499 c2 := out[1] 500 if c2.Node != nodeName || c2.CheckID != "check2" || c2.Name != "check" || 501 c2.CreateIndex != 4 || c2.ModifyIndex != 4 { 502 t.Fatalf("bad check returned: %#v", c2) 503 } 504 }() 505 } 506 507 func deprecatedEnsureNodeWithoutIDCanRegister(t *testing.T, s *Store, nodeName string, txIdx uint64) { 508 // All the following is deprecated, and should be removed in future Consul versions 509 in := &structs.Node{ 510 Node: nodeName, 511 Address: "1.1.1.9", 512 Meta: map[string]string{ 513 "version": string(txIdx), 514 }, 515 } 516 if err := s.EnsureNode(txIdx, in); err != nil { 517 t.Fatalf("err: %s", err) 518 } 519 idx, out, err := s.GetNode(nodeName) 520 if err != nil { 521 t.Fatalf("err: %s", err) 522 } 523 if idx != txIdx { 524 t.Fatalf("index should be %v, was: %v", txIdx, idx) 525 } 526 if out.Node != nodeName { 527 t.Fatalf("unexpected result out = %v, nodeName supposed to be %s", out, nodeName) 528 } 529 } 530 531 func TestStateStore_EnsureNodeDeprecated(t *testing.T) { 532 s := testStateStore(t) 533 534 firstNodeName := "node-without-id" 535 deprecatedEnsureNodeWithoutIDCanRegister(t, s, firstNodeName, 1) 536 537 newNodeID := types.NodeID("00a916bc-a357-4a19-b886-59419fcee50c") 538 // With this request, we basically add a node ID to existing node 539 // and change its address 540 in := &structs.Node{ 541 ID: newNodeID, 542 Node: firstNodeName, 543 Address: "1.1.7.8", 544 } 545 if err := s.EnsureNode(4, in); err != nil { 546 t.Fatalf("err: %v", err) 547 } 548 // Retrieve the node again 549 idx, out, err := s.GetNode(firstNodeName) 550 if err != nil { 551 t.Fatalf("err: %s", err) 552 } 553 554 // Node has updated information 555 if idx != 4 || out.Node != firstNodeName || out.ID != newNodeID || out.Address != "1.1.7.8" { 556 t.Fatalf("[DEPRECATED] bad node returned: %#v", out) 557 } 558 if out.CreateIndex != 1 || out.ModifyIndex != 4 { 559 t.Fatalf("[DEPRECATED] bad CreateIndex/ModifyIndex returned: %#v", out) 560 } 561 562 // Now, lets update IP Address without providing any ID 563 // Only name of node will be used to match 564 in = &structs.Node{ 565 Node: firstNodeName, 566 Address: "1.1.7.10", 567 } 568 if err := s.EnsureNode(7, in); err != nil { 569 t.Fatalf("err: %v", err) 570 } 571 // Retrieve the node again 572 idx, out, err = s.GetNode(firstNodeName) 573 if err != nil { 574 t.Fatalf("err: %s", err) 575 } 576 577 // Node has updated information, its ID has been removed (deprecated, but working) 578 if idx != 7 || out.Node != firstNodeName || out.ID != "" || out.Address != "1.1.7.10" { 579 t.Fatalf("[DEPRECATED] bad node returned: %#v", out) 580 } 581 if out.CreateIndex != 1 || out.ModifyIndex != 7 { 582 t.Fatalf("[DEPRECATED] bad CreateIndex/ModifyIndex returned: %#v", out) 583 } 584 } 585 586 func TestNodeRenamingNodes(t *testing.T) { 587 s := testStateStore(t) 588 589 nodeID1 := types.NodeID("b789bf0a-d96b-4f70-a4a6-ac5dfaece53d") 590 nodeID2 := types.NodeID("27bee224-a4d7-45d0-9b8e-65b3c94a61ba") 591 592 // Node1 with ID 593 in1 := &structs.Node{ 594 ID: nodeID1, 595 Node: "node1", 596 Address: "1.1.1.1", 597 } 598 599 if err := s.EnsureNode(1, in1); err != nil { 600 t.Fatalf("err: %s", err) 601 } 602 603 // Node2 with ID 604 in2 := &structs.Node{ 605 ID: nodeID2, 606 Node: "node2", 607 Address: "1.1.1.2", 608 } 609 610 if err := s.EnsureNode(2, in2); err != nil { 611 t.Fatalf("err: %s", err) 612 } 613 614 // Node3 without ID 615 in3 := &structs.Node{ 616 Node: "node3", 617 Address: "1.1.1.3", 618 } 619 620 if err := s.EnsureNode(3, in3); err != nil { 621 t.Fatalf("err: %s", err) 622 } 623 624 if _, node, err := s.GetNodeID(nodeID1); err != nil || node == nil || node.ID != nodeID1 { 625 t.Fatalf("err: %s, node:= %q", err, node) 626 } 627 628 if _, node, err := s.GetNodeID(nodeID2); err != nil && node == nil || node.ID != nodeID2 { 629 t.Fatalf("err: %s", err) 630 } 631 632 // Renaming node2 into node1 should fail 633 in2Modify := &structs.Node{ 634 ID: nodeID2, 635 Node: "node1", 636 Address: "1.1.1.2", 637 } 638 if err := s.EnsureNode(4, in2Modify); err == nil { 639 t.Fatalf("Renaming node2 into node1 should fail") 640 } 641 642 // Conflict with case insensitive matching as well 643 in2Modify = &structs.Node{ 644 ID: nodeID2, 645 Node: "NoDe1", 646 Address: "1.1.1.2", 647 } 648 if err := s.EnsureNode(5, in2Modify); err == nil { 649 t.Fatalf("Renaming node2 into node1 should fail") 650 } 651 652 // Conflict with case insensitive on node without ID 653 in2Modify = &structs.Node{ 654 ID: nodeID2, 655 Node: "NoDe3", 656 Address: "1.1.1.2", 657 } 658 if err := s.EnsureNode(6, in2Modify); err == nil { 659 t.Fatalf("Renaming node2 into node1 should fail") 660 } 661 662 // No conflict, should work 663 in2Modify = &structs.Node{ 664 ID: nodeID2, 665 Node: "node2bis", 666 Address: "1.1.1.2", 667 } 668 if err := s.EnsureNode(6, in2Modify); err != nil { 669 t.Fatalf("Renaming node2 into node1 should fail") 670 } 671 672 // Retrieve the node again 673 idx, out, err := s.GetNode("node2bis") 674 if err != nil { 675 t.Fatalf("err: %s", err) 676 } 677 678 // Retrieve the node again 679 idx2, out2, err := s.GetNodeID(nodeID2) 680 if err != nil { 681 t.Fatalf("err: %s", err) 682 } 683 684 if idx != idx2 { 685 t.Fatalf("node should be the same") 686 } 687 688 if out.ID != out2.ID || out.Node != out2.Node { 689 t.Fatalf("all should match") 690 } 691 } 692 693 func TestStateStore_EnsureNode(t *testing.T) { 694 s := testStateStore(t) 695 696 // Fetching a non-existent node returns nil 697 if _, node, err := s.GetNode("node1"); node != nil || err != nil { 698 t.Fatalf("expected (nil, nil), got: (%#v, %#v)", node, err) 699 } 700 701 // Create a node registration request 702 in := &structs.Node{ 703 ID: types.NodeID("cda916bc-a357-4a19-b886-59419fcee50c"), 704 Node: "node1", 705 Address: "1.1.1.1", 706 } 707 708 // Ensure the node is registered in the db 709 if err := s.EnsureNode(1, in); err != nil { 710 t.Fatalf("err: %s", err) 711 } 712 713 // Retrieve the node again 714 idx, out, err := s.GetNode("node1") 715 if err != nil { 716 t.Fatalf("err: %s", err) 717 } 718 719 // Correct node was returned 720 if out.Node != "node1" || out.Address != "1.1.1.1" { 721 t.Fatalf("bad node returned: %#v", out) 722 } 723 724 // Indexes are set properly 725 if out.CreateIndex != 1 || out.ModifyIndex != 1 { 726 t.Fatalf("bad node index: %#v", out) 727 } 728 if idx != 1 { 729 t.Fatalf("bad index: %d", idx) 730 } 731 732 // Update the node registration 733 in2 := &structs.Node{ 734 ID: in.ID, 735 Node: in.Node, 736 Address: "1.1.1.2", 737 } 738 if err := s.EnsureNode(2, in2); err != nil { 739 t.Fatalf("err: %s", err) 740 } 741 742 // Retrieve the node 743 idx, out, err = s.GetNode("node1") 744 if err != nil { 745 t.Fatalf("err: %s", err) 746 } 747 748 // Node and indexes were updated 749 if out.CreateIndex != 1 || out.ModifyIndex != 2 || out.Address != "1.1.1.2" { 750 t.Fatalf("bad: %#v", out) 751 } 752 if idx != 2 { 753 t.Fatalf("bad index: %d", idx) 754 } 755 756 // Re-inserting data should not modify ModifiedIndex 757 if err := s.EnsureNode(3, in2); err != nil { 758 t.Fatalf("err: %s", err) 759 } 760 idx, out, err = s.GetNode("node1") 761 if err != nil { 762 t.Fatalf("err: %s", err) 763 } 764 if out.CreateIndex != 1 || out.ModifyIndex != 2 || out.Address != "1.1.1.2" { 765 t.Fatalf("node was modified: %#v", out) 766 } 767 768 // Node upsert preserves the create index 769 in3 := &structs.Node{ 770 ID: in.ID, 771 Node: in.Node, 772 Address: "1.1.1.3", 773 } 774 if err := s.EnsureNode(3, in3); err != nil { 775 t.Fatalf("err: %s", err) 776 } 777 idx, out, err = s.GetNode("node1") 778 if err != nil { 779 t.Fatalf("err: %s", err) 780 } 781 if out.CreateIndex != 1 || out.ModifyIndex != 3 || out.Address != "1.1.1.3" { 782 t.Fatalf("node was modified: %#v", out) 783 } 784 if idx != 3 { 785 t.Fatalf("bad index: %d", idx) 786 } 787 788 // Update index to 4, no change 789 if err := s.EnsureNode(4, in); err != nil { 790 t.Fatalf("err: %v", err) 791 } 792 793 // Now try to add another node with the same ID 794 in = &structs.Node{ 795 Node: "node1-renamed", 796 ID: types.NodeID("cda916bc-a357-4a19-b886-59419fcee50c"), 797 Address: "1.1.1.2", 798 } 799 if err := s.EnsureNode(6, in); err != nil { 800 t.Fatalf("err: %s", err) 801 } 802 803 // Retrieve the node 804 idx, out, err = s.GetNode("node1") 805 if out != nil { 806 t.Fatalf("Node should not exist anymore: %q", out) 807 } 808 809 idx, out, err = s.GetNode("node1-renamed") 810 if err != nil { 811 t.Fatalf("err: %s", err) 812 } 813 814 if out == nil { 815 t.Fatalf("err: %s", err) 816 } 817 818 // Node and indexes were updated 819 if out.CreateIndex != 1 || out.ModifyIndex != 6 || out.Address != "1.1.1.2" || out.Node != "node1-renamed" { 820 t.Fatalf("bad: %#v", out) 821 } 822 if idx != 6 { 823 t.Fatalf("bad index: %d", idx) 824 } 825 826 newNodeID := types.NodeID("d0347693-65cc-4d9f-a6e0-5025b2e6513f") 827 828 // Adding another node with same name should fail 829 in = &structs.Node{ 830 Node: "node1-renamed", 831 ID: newNodeID, 832 Address: "1.1.1.7", 833 } 834 if err := s.EnsureNode(8, in); err == nil { 835 t.Fatalf("There should be an error since node1-renamed already exists") 836 } 837 838 // Adding another node with same name but different case should fail 839 in = &structs.Node{ 840 Node: "Node1-RENAMED", 841 ID: newNodeID, 842 Address: "1.1.1.7", 843 } 844 if err := s.EnsureNode(8, in); err == nil { 845 t.Fatalf("err: %s", err) 846 } 847 848 // Lets add another valid node now 849 in = &structs.Node{ 850 Node: "Node1bis", 851 ID: newNodeID, 852 Address: "1.1.1.7", 853 } 854 if err := s.EnsureNode(9, in); err != nil { 855 t.Fatalf("err: %s", err) 856 } 857 858 // Retrieve the node 859 idx, out, err = s.GetNode("Node1bis") 860 if out == nil { 861 t.Fatalf("Node should exist, but was null") 862 } 863 864 // Renaming should fail 865 in = &structs.Node{ 866 Node: "Node1bis", 867 ID: newNodeID, 868 Address: "1.1.1.7", 869 } 870 if err := s.EnsureNode(9, in); err != nil { 871 t.Fatalf("err: %s", err) 872 } 873 874 idx, out, err = s.GetNode("Node1bis") 875 if err != nil { 876 t.Fatalf("err: %s", err) 877 } 878 879 // Node and indexes were updated 880 if out.ID != newNodeID || out.CreateIndex != 9 || out.ModifyIndex != 9 || out.Address != "1.1.1.7" || out.Node != "Node1bis" { 881 t.Fatalf("bad: %#v", out) 882 } 883 if idx != 9 { 884 t.Fatalf("bad index: %d", idx) 885 } 886 887 // Renaming to same value as first node should fail as well 888 // Adding another node with same name but different case should fail 889 in = &structs.Node{ 890 Node: "node1-renamed", 891 ID: newNodeID, 892 Address: "1.1.1.7", 893 } 894 if err := s.EnsureNode(10, in); err == nil { 895 t.Fatalf("err: %s", err) 896 } 897 898 // It should fail also with different case 899 in = &structs.Node{ 900 Node: "Node1-Renamed", 901 ID: newNodeID, 902 Address: "1.1.1.7", 903 } 904 if err := s.EnsureNode(10, in); err == nil { 905 t.Fatalf("err: %s", err) 906 } 907 908 // But should work if names are different 909 in = &structs.Node{ 910 Node: "Node1-Renamed2", 911 ID: newNodeID, 912 Address: "1.1.1.7", 913 } 914 if err := s.EnsureNode(11, in); err != nil { 915 t.Fatalf("err: %s", err) 916 } 917 idx, out, err = s.GetNode("Node1-Renamed2") 918 if err != nil { 919 t.Fatalf("err: %s", err) 920 } 921 922 // Node and indexes were updated 923 if out.ID != newNodeID || out.CreateIndex != 9 || out.ModifyIndex != 11 || out.Address != "1.1.1.7" || out.Node != "Node1-Renamed2" { 924 t.Fatalf("bad: %#v", out) 925 } 926 if idx != 11 { 927 t.Fatalf("bad index: %d", idx) 928 } 929 930 // All the remaining tests are deprecated, please remove them on next Consul major release 931 // See https://github.com/hashicorp/consul/pull/3983 for context 932 933 // Deprecated behavior is following 934 deprecatedEnsureNodeWithoutIDCanRegister(t, s, "new-node-without-id", 12) 935 936 // Deprecated, but should work as well 937 deprecatedEnsureNodeWithoutIDCanRegister(t, s, "new-node-without-id", 13) 938 939 // All of this is deprecated as well, should be removed 940 in = &structs.Node{ 941 Node: "Node1-Renamed2", 942 Address: "1.1.1.66", 943 } 944 if err := s.EnsureNode(14, in); err != nil { 945 t.Fatalf("[DEPRECATED] it should work, err:= %q", err) 946 } 947 idx, out, err = s.GetNode("Node1-Renamed2") 948 if err != nil { 949 t.Fatalf("[DEPRECATED] err: %s", err) 950 } 951 if out.CreateIndex != 9 { 952 t.Fatalf("[DEPRECATED] We expected to modify node previously added, but add index = %d for node %q", out.CreateIndex, out) 953 } 954 if out.Address != "1.1.1.66" || out.ModifyIndex != 14 { 955 t.Fatalf("[DEPRECATED] Node with newNodeID should have been updated, but was: %d with content := %q", out.CreateIndex, out) 956 } 957 } 958 959 func TestStateStore_GetNodes(t *testing.T) { 960 s := testStateStore(t) 961 962 // Listing with no results returns nil. 963 ws := memdb.NewWatchSet() 964 idx, res, err := s.Nodes(ws) 965 if idx != 0 || res != nil || err != nil { 966 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 967 } 968 969 // Create some nodes in the state store. 970 testRegisterNode(t, s, 0, "node0") 971 testRegisterNode(t, s, 1, "node1") 972 testRegisterNode(t, s, 2, "node2") 973 if !watchFired(ws) { 974 t.Fatalf("bad") 975 } 976 977 // Retrieve the nodes. 978 ws = memdb.NewWatchSet() 979 idx, nodes, err := s.Nodes(ws) 980 if err != nil { 981 t.Fatalf("err: %s", err) 982 } 983 984 // Highest index was returned. 985 if idx != 2 { 986 t.Fatalf("bad index: %d", idx) 987 } 988 989 // All nodes were returned. 990 if n := len(nodes); n != 3 { 991 t.Fatalf("bad node count: %d", n) 992 } 993 994 // Make sure the nodes match. 995 for i, node := range nodes { 996 if node.CreateIndex != uint64(i) || node.ModifyIndex != uint64(i) { 997 t.Fatalf("bad node index: %d, %d", node.CreateIndex, node.ModifyIndex) 998 } 999 name := fmt.Sprintf("node%d", i) 1000 if node.Node != name { 1001 t.Fatalf("bad: %#v", node) 1002 } 1003 } 1004 1005 // Make sure a node delete fires the watch. 1006 if watchFired(ws) { 1007 t.Fatalf("bad") 1008 } 1009 if err := s.DeleteNode(3, "node1"); err != nil { 1010 t.Fatalf("err: %s", err) 1011 } 1012 if !watchFired(ws) { 1013 t.Fatalf("bad") 1014 } 1015 } 1016 1017 func BenchmarkGetNodes(b *testing.B) { 1018 s, err := NewStateStore(nil) 1019 if err != nil { 1020 b.Fatalf("err: %s", err) 1021 } 1022 1023 if err := s.EnsureNode(100, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil { 1024 b.Fatalf("err: %v", err) 1025 } 1026 if err := s.EnsureNode(101, &structs.Node{Node: "bar", Address: "127.0.0.2"}); err != nil { 1027 b.Fatalf("err: %v", err) 1028 } 1029 1030 ws := memdb.NewWatchSet() 1031 for i := 0; i < b.N; i++ { 1032 s.Nodes(ws) 1033 } 1034 } 1035 1036 func TestStateStore_GetNodesByMeta(t *testing.T) { 1037 s := testStateStore(t) 1038 1039 // Listing with no results returns nil 1040 ws := memdb.NewWatchSet() 1041 idx, res, err := s.NodesByMeta(ws, map[string]string{"somekey": "somevalue"}) 1042 if idx != 0 || res != nil || err != nil { 1043 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 1044 } 1045 1046 // Create some nodes in the state store. 1047 testRegisterNodeWithMeta(t, s, 0, "node0", map[string]string{"role": "client"}) 1048 testRegisterNodeWithMeta(t, s, 1, "node1", map[string]string{"role": "client", "common": "1"}) 1049 testRegisterNodeWithMeta(t, s, 2, "node2", map[string]string{"role": "server", "common": "1"}) 1050 if !watchFired(ws) { 1051 t.Fatalf("bad") 1052 } 1053 1054 cases := []struct { 1055 filters map[string]string 1056 nodes []string 1057 }{ 1058 // Simple meta filter 1059 { 1060 filters: map[string]string{"role": "server"}, 1061 nodes: []string{"node2"}, 1062 }, 1063 // Common meta filter 1064 { 1065 filters: map[string]string{"common": "1"}, 1066 nodes: []string{"node1", "node2"}, 1067 }, 1068 // Invalid meta filter 1069 { 1070 filters: map[string]string{"invalid": "nope"}, 1071 nodes: []string{}, 1072 }, 1073 // Multiple meta filters 1074 { 1075 filters: map[string]string{"role": "client", "common": "1"}, 1076 nodes: []string{"node1"}, 1077 }, 1078 } 1079 1080 for _, tc := range cases { 1081 _, result, err := s.NodesByMeta(nil, tc.filters) 1082 if err != nil { 1083 t.Fatalf("bad: %v", err) 1084 } 1085 1086 if len(result) != len(tc.nodes) { 1087 t.Fatalf("bad: %v %v", result, tc.nodes) 1088 } 1089 1090 for i, node := range result { 1091 if node.Node != tc.nodes[i] { 1092 t.Fatalf("bad: %v %v", node.Node, tc.nodes[i]) 1093 } 1094 } 1095 } 1096 1097 // Set up a watch. 1098 ws = memdb.NewWatchSet() 1099 _, _, err = s.NodesByMeta(ws, map[string]string{"role": "client"}) 1100 if err != nil { 1101 t.Fatalf("err: %v", err) 1102 } 1103 1104 // Make an unrelated modification and make sure the watch doesn't fire. 1105 testRegisterNodeWithMeta(t, s, 3, "node3", map[string]string{"foo": "bar"}) 1106 if watchFired(ws) { 1107 t.Fatalf("bad") 1108 } 1109 1110 // Change a watched key and make sure it fires. 1111 testRegisterNodeWithMeta(t, s, 4, "node0", map[string]string{"role": "different"}) 1112 if !watchFired(ws) { 1113 t.Fatalf("bad") 1114 } 1115 } 1116 1117 func TestStateStore_NodeServices(t *testing.T) { 1118 s := testStateStore(t) 1119 1120 // Register some nodes with similar IDs. 1121 { 1122 req := &structs.RegisterRequest{ 1123 ID: types.NodeID("40e4a748-2192-161a-0510-aaaaaaaaaaaa"), 1124 Node: "node1", 1125 Address: "1.2.3.4", 1126 } 1127 if err := s.EnsureRegistration(1, req); err != nil { 1128 t.Fatalf("err: %s", err) 1129 } 1130 } 1131 { 1132 req := &structs.RegisterRequest{ 1133 ID: types.NodeID("40e4a748-2192-161a-0510-bbbbbbbbbbbb"), 1134 Node: "node2", 1135 Address: "5.6.7.8", 1136 } 1137 if err := s.EnsureRegistration(2, req); err != nil { 1138 t.Fatalf("err: %s", err) 1139 } 1140 } 1141 1142 // Look up by name. 1143 { 1144 _, ns, err := s.NodeServices(nil, "node1") 1145 if err != nil { 1146 t.Fatalf("err: %v", err) 1147 } 1148 if ns == nil || ns.Node.Node != "node1" { 1149 t.Fatalf("bad: %#v", *ns) 1150 } 1151 } 1152 { 1153 _, ns, err := s.NodeServices(nil, "node2") 1154 if err != nil { 1155 t.Fatalf("err: %v", err) 1156 } 1157 if ns == nil || ns.Node.Node != "node2" { 1158 t.Fatalf("bad: %#v", *ns) 1159 } 1160 } 1161 1162 // Look up by UUID. 1163 { 1164 _, ns, err := s.NodeServices(nil, "40e4a748-2192-161a-0510-aaaaaaaaaaaa") 1165 if err != nil { 1166 t.Fatalf("err: %v", err) 1167 } 1168 if ns == nil || ns.Node.Node != "node1" { 1169 t.Fatalf("bad: %#v", ns) 1170 } 1171 } 1172 { 1173 _, ns, err := s.NodeServices(nil, "40e4a748-2192-161a-0510-bbbbbbbbbbbb") 1174 if err != nil { 1175 t.Fatalf("err: %v", err) 1176 } 1177 if ns == nil || ns.Node.Node != "node2" { 1178 t.Fatalf("bad: %#v", ns) 1179 } 1180 } 1181 1182 // Ambiguous prefix. 1183 { 1184 _, ns, err := s.NodeServices(nil, "40e4a748-2192-161a-0510") 1185 if err != nil { 1186 t.Fatalf("err: %v", err) 1187 } 1188 if ns != nil { 1189 t.Fatalf("bad: %#v", ns) 1190 } 1191 } 1192 1193 // Bad node, and not a UUID (should not get a UUID error). 1194 { 1195 _, ns, err := s.NodeServices(nil, "nope") 1196 if err != nil { 1197 t.Fatalf("err: %v", err) 1198 } 1199 if ns != nil { 1200 t.Fatalf("bad: %#v", ns) 1201 } 1202 } 1203 1204 // Specific prefix. 1205 { 1206 _, ns, err := s.NodeServices(nil, "40e4a748-2192-161a-0510-bb") 1207 if err != nil { 1208 t.Fatalf("err: %v", err) 1209 } 1210 if ns == nil || ns.Node.Node != "node2" { 1211 t.Fatalf("bad: %#v", ns) 1212 } 1213 } 1214 } 1215 1216 func TestStateStore_DeleteNode(t *testing.T) { 1217 s := testStateStore(t) 1218 1219 // Create a node and register a service and health check with it. 1220 testRegisterNode(t, s, 0, "node1") 1221 testRegisterService(t, s, 1, "node1", "service1") 1222 testRegisterCheck(t, s, 2, "node1", "", "check1", api.HealthPassing) 1223 1224 // Delete the node 1225 if err := s.DeleteNode(3, "node1"); err != nil { 1226 t.Fatalf("err: %s", err) 1227 } 1228 1229 // The node was removed 1230 if idx, n, err := s.GetNode("node1"); err != nil || n != nil || idx != 3 { 1231 t.Fatalf("bad: %#v %d (err: %#v)", n, idx, err) 1232 } 1233 1234 // Associated service was removed. Need to query this directly out of 1235 // the DB to make sure it is actually gone. 1236 tx := s.db.Txn(false) 1237 defer tx.Abort() 1238 services, err := tx.Get("services", "id", "node1", "service1") 1239 if err != nil { 1240 t.Fatalf("err: %s", err) 1241 } 1242 if service := services.Next(); service != nil { 1243 t.Fatalf("bad: %#v", service) 1244 } 1245 1246 // Associated health check was removed. 1247 checks, err := tx.Get("checks", "id", "node1", "check1") 1248 if err != nil { 1249 t.Fatalf("err: %s", err) 1250 } 1251 if check := checks.Next(); check != nil { 1252 t.Fatalf("bad: %#v", check) 1253 } 1254 1255 // Indexes were updated. 1256 for _, tbl := range []string{"nodes", "services", "checks"} { 1257 if idx := s.maxIndex(tbl); idx != 3 { 1258 t.Fatalf("bad index: %d (%s)", idx, tbl) 1259 } 1260 } 1261 1262 // Deleting a nonexistent node should be idempotent and not return 1263 // an error 1264 if err := s.DeleteNode(4, "node1"); err != nil { 1265 t.Fatalf("err: %s", err) 1266 } 1267 if idx := s.maxIndex("nodes"); idx != 3 { 1268 t.Fatalf("bad index: %d", idx) 1269 } 1270 } 1271 1272 func TestStateStore_Node_Snapshot(t *testing.T) { 1273 s := testStateStore(t) 1274 1275 // Create some nodes in the state store. 1276 testRegisterNode(t, s, 0, "node0") 1277 testRegisterNode(t, s, 1, "node1") 1278 testRegisterNode(t, s, 2, "node2") 1279 1280 // Snapshot the nodes. 1281 snap := s.Snapshot() 1282 defer snap.Close() 1283 1284 // Alter the real state store. 1285 testRegisterNode(t, s, 3, "node3") 1286 1287 // Verify the snapshot. 1288 if idx := snap.LastIndex(); idx != 2 { 1289 t.Fatalf("bad index: %d", idx) 1290 } 1291 nodes, err := snap.Nodes() 1292 if err != nil { 1293 t.Fatalf("err: %s", err) 1294 } 1295 for i := 0; i < 3; i++ { 1296 node := nodes.Next().(*structs.Node) 1297 if node == nil { 1298 t.Fatalf("unexpected end of nodes") 1299 } 1300 1301 if node.CreateIndex != uint64(i) || node.ModifyIndex != uint64(i) { 1302 t.Fatalf("bad node index: %d, %d", node.CreateIndex, node.ModifyIndex) 1303 } 1304 if node.Node != fmt.Sprintf("node%d", i) { 1305 t.Fatalf("bad: %#v", node) 1306 } 1307 } 1308 if nodes.Next() != nil { 1309 t.Fatalf("unexpected extra nodes") 1310 } 1311 } 1312 1313 func TestStateStore_EnsureService(t *testing.T) { 1314 s := testStateStore(t) 1315 1316 // Fetching services for a node with none returns nil. 1317 ws := memdb.NewWatchSet() 1318 idx, res, err := s.NodeServices(ws, "node1") 1319 if err != nil || res != nil || idx != 0 { 1320 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 1321 } 1322 1323 // Create the service registration. 1324 ns1 := &structs.NodeService{ 1325 ID: "service1", 1326 Service: "redis", 1327 Tags: []string{"prod"}, 1328 Address: "1.1.1.1", 1329 Port: 1111, 1330 Weights: &structs.Weights{Passing: 1, Warning: 0}, 1331 } 1332 1333 // Creating a service without a node returns an error. 1334 if err := s.EnsureService(1, "node1", ns1); err != ErrMissingNode { 1335 t.Fatalf("expected %#v, got: %#v", ErrMissingNode, err) 1336 } 1337 if watchFired(ws) { 1338 t.Fatalf("bad") 1339 } 1340 1341 // Register the nodes. 1342 testRegisterNode(t, s, 0, "node1") 1343 testRegisterNode(t, s, 1, "node2") 1344 if !watchFired(ws) { 1345 t.Fatalf("bad") 1346 } 1347 1348 // Service successfully registers into the state store. 1349 ws = memdb.NewWatchSet() 1350 _, _, err = s.NodeServices(ws, "node1") 1351 if err != nil { 1352 t.Fatalf("err: %v", err) 1353 } 1354 if err = s.EnsureService(10, "node1", ns1); err != nil { 1355 t.Fatalf("err: %s", err) 1356 } 1357 if !watchFired(ws) { 1358 t.Fatalf("bad") 1359 } 1360 1361 // Register a similar service against both nodes. 1362 ns2 := *ns1 1363 ns2.ID = "service2" 1364 for _, n := range []string{"node1", "node2"} { 1365 if err := s.EnsureService(20, n, &ns2); err != nil { 1366 t.Fatalf("err: %s", err) 1367 } 1368 } 1369 1370 // Register a different service on the bad node. 1371 ws = memdb.NewWatchSet() 1372 _, _, err = s.NodeServices(ws, "node1") 1373 if err != nil { 1374 t.Fatalf("err: %v", err) 1375 } 1376 ns3 := *ns1 1377 ns3.ID = "service3" 1378 if err := s.EnsureService(30, "node2", &ns3); err != nil { 1379 t.Fatalf("err: %s", err) 1380 } 1381 if watchFired(ws) { 1382 t.Fatalf("bad") 1383 } 1384 1385 // Retrieve the services. 1386 ws = memdb.NewWatchSet() 1387 idx, out, err := s.NodeServices(ws, "node1") 1388 if err != nil { 1389 t.Fatalf("err: %s", err) 1390 } 1391 if idx != 30 { 1392 t.Fatalf("bad index: %d", idx) 1393 } 1394 1395 // Only the services for the requested node are returned. 1396 if out == nil || len(out.Services) != 2 { 1397 t.Fatalf("bad services: %#v", out) 1398 } 1399 1400 // Results match the inserted services and have the proper indexes set. 1401 expect1 := *ns1 1402 expect1.CreateIndex, expect1.ModifyIndex = 10, 10 1403 if svc := out.Services["service1"]; !reflect.DeepEqual(&expect1, svc) { 1404 t.Fatalf("bad: %#v", svc) 1405 } 1406 1407 expect2 := ns2 1408 expect2.CreateIndex, expect2.ModifyIndex = 20, 20 1409 if svc := out.Services["service2"]; !reflect.DeepEqual(&expect2, svc) { 1410 t.Fatalf("bad: %#v %#v", ns2, svc) 1411 } 1412 1413 // Index tables were updated. 1414 if idx := s.maxIndex("services"); idx != 30 { 1415 t.Fatalf("bad index: %d", idx) 1416 } 1417 1418 // Update a service registration. 1419 ns1.Address = "1.1.1.2" 1420 if err := s.EnsureService(40, "node1", ns1); err != nil { 1421 t.Fatalf("err: %s", err) 1422 } 1423 if !watchFired(ws) { 1424 t.Fatalf("bad") 1425 } 1426 1427 // Retrieve the service again and ensure it matches.. 1428 idx, out, err = s.NodeServices(nil, "node1") 1429 if err != nil { 1430 t.Fatalf("err: %s", err) 1431 } 1432 if idx != 40 { 1433 t.Fatalf("bad index: %d", idx) 1434 } 1435 if out == nil || len(out.Services) != 2 { 1436 t.Fatalf("bad: %#v", out) 1437 } 1438 expect1.Address = "1.1.1.2" 1439 expect1.ModifyIndex = 40 1440 if svc := out.Services["service1"]; !reflect.DeepEqual(&expect1, svc) { 1441 t.Fatalf("bad: %#v", svc) 1442 } 1443 1444 // Index tables were updated. 1445 if idx := s.maxIndex("services"); idx != 40 { 1446 t.Fatalf("bad index: %d", idx) 1447 } 1448 } 1449 1450 func TestStateStore_EnsureService_connectProxy(t *testing.T) { 1451 assert := assert.New(t) 1452 s := testStateStore(t) 1453 1454 // Create the service registration. 1455 ns1 := &structs.NodeService{ 1456 Kind: structs.ServiceKindConnectProxy, 1457 ID: "connect-proxy", 1458 Service: "connect-proxy", 1459 Address: "1.1.1.1", 1460 Port: 1111, 1461 Weights: &structs.Weights{ 1462 Passing: 1, 1463 Warning: 1, 1464 }, 1465 Proxy: structs.ConnectProxyConfig{DestinationServiceName: "foo"}, 1466 } 1467 1468 // Service successfully registers into the state store. 1469 testRegisterNode(t, s, 0, "node1") 1470 assert.Nil(s.EnsureService(10, "node1", ns1)) 1471 1472 // Retrieve and verify 1473 _, out, err := s.NodeServices(nil, "node1") 1474 assert.Nil(err) 1475 assert.NotNil(out) 1476 assert.Len(out.Services, 1) 1477 1478 expect1 := *ns1 1479 expect1.CreateIndex, expect1.ModifyIndex = 10, 10 1480 assert.Equal(&expect1, out.Services["connect-proxy"]) 1481 } 1482 1483 func TestStateStore_Services(t *testing.T) { 1484 s := testStateStore(t) 1485 1486 // Listing with no results returns an empty list. 1487 ws := memdb.NewWatchSet() 1488 idx, services, err := s.Services(ws) 1489 if err != nil { 1490 t.Fatalf("err: %s", err) 1491 } 1492 if idx != 0 { 1493 t.Fatalf("bad: %d", idx) 1494 } 1495 if len(services) != 0 { 1496 t.Fatalf("bad: %v", services) 1497 } 1498 1499 // Register several nodes and services. 1500 testRegisterNode(t, s, 1, "node1") 1501 ns1 := &structs.NodeService{ 1502 ID: "service1", 1503 Service: "redis", 1504 Tags: []string{"prod", "master"}, 1505 Address: "1.1.1.1", 1506 Port: 1111, 1507 } 1508 if err := s.EnsureService(2, "node1", ns1); err != nil { 1509 t.Fatalf("err: %s", err) 1510 } 1511 testRegisterService(t, s, 3, "node1", "dogs") 1512 testRegisterNode(t, s, 4, "node2") 1513 ns2 := &structs.NodeService{ 1514 ID: "service3", 1515 Service: "redis", 1516 Tags: []string{"prod", "slave"}, 1517 Address: "1.1.1.1", 1518 Port: 1111, 1519 } 1520 if err := s.EnsureService(5, "node2", ns2); err != nil { 1521 t.Fatalf("err: %s", err) 1522 } 1523 if !watchFired(ws) { 1524 t.Fatalf("bad") 1525 } 1526 1527 // Pull all the services. 1528 ws = memdb.NewWatchSet() 1529 idx, services, err = s.Services(ws) 1530 if err != nil { 1531 t.Fatalf("err: %s", err) 1532 } 1533 if idx != 5 { 1534 t.Fatalf("bad index: %d", idx) 1535 } 1536 1537 // Verify the result. We sort the lists since the order is 1538 // non-deterministic (it's built using a map internally). 1539 expected := structs.Services{ 1540 "redis": []string{"prod", "master", "slave"}, 1541 "dogs": []string{}, 1542 } 1543 sort.Strings(expected["redis"]) 1544 for _, tags := range services { 1545 sort.Strings(tags) 1546 } 1547 if !reflect.DeepEqual(expected, services) { 1548 t.Fatalf("bad: %#v", services) 1549 } 1550 1551 // Deleting a node with a service should fire the watch. 1552 if err := s.DeleteNode(6, "node1"); err != nil { 1553 t.Fatalf("err: %s", err) 1554 } 1555 if !watchFired(ws) { 1556 t.Fatalf("bad") 1557 } 1558 } 1559 1560 func TestStateStore_ServicesByNodeMeta(t *testing.T) { 1561 s := testStateStore(t) 1562 1563 // Listing with no results returns nil. 1564 ws := memdb.NewWatchSet() 1565 idx, res, err := s.ServicesByNodeMeta(ws, map[string]string{"somekey": "somevalue"}) 1566 if idx != 0 || len(res) != 0 || err != nil { 1567 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 1568 } 1569 1570 // Create some nodes and services in the state store. 1571 node0 := &structs.Node{Node: "node0", Address: "127.0.0.1", Meta: map[string]string{"role": "client", "common": "1"}} 1572 if err := s.EnsureNode(0, node0); err != nil { 1573 t.Fatalf("err: %v", err) 1574 } 1575 node1 := &structs.Node{Node: "node1", Address: "127.0.0.1", Meta: map[string]string{"role": "server", "common": "1"}} 1576 if err := s.EnsureNode(1, node1); err != nil { 1577 t.Fatalf("err: %v", err) 1578 } 1579 ns1 := &structs.NodeService{ 1580 ID: "service1", 1581 Service: "redis", 1582 Tags: []string{"prod", "master"}, 1583 Address: "1.1.1.1", 1584 Port: 1111, 1585 } 1586 if err := s.EnsureService(2, "node0", ns1); err != nil { 1587 t.Fatalf("err: %s", err) 1588 } 1589 ns2 := &structs.NodeService{ 1590 ID: "service1", 1591 Service: "redis", 1592 Tags: []string{"prod", "slave"}, 1593 Address: "1.1.1.1", 1594 Port: 1111, 1595 } 1596 if err := s.EnsureService(3, "node1", ns2); err != nil { 1597 t.Fatalf("err: %s", err) 1598 } 1599 if !watchFired(ws) { 1600 t.Fatalf("bad") 1601 } 1602 1603 // Filter the services by the first node's meta value. 1604 ws = memdb.NewWatchSet() 1605 _, res, err = s.ServicesByNodeMeta(ws, map[string]string{"role": "client"}) 1606 if err != nil { 1607 t.Fatalf("err: %s", err) 1608 } 1609 expected := structs.Services{ 1610 "redis": []string{"master", "prod"}, 1611 } 1612 sort.Strings(res["redis"]) 1613 if !reflect.DeepEqual(res, expected) { 1614 t.Fatalf("bad: %v %v", res, expected) 1615 } 1616 1617 // Get all services using the common meta value 1618 _, res, err = s.ServicesByNodeMeta(ws, map[string]string{"common": "1"}) 1619 if err != nil { 1620 t.Fatalf("err: %s", err) 1621 } 1622 expected = structs.Services{ 1623 "redis": []string{"master", "prod", "slave"}, 1624 } 1625 sort.Strings(res["redis"]) 1626 if !reflect.DeepEqual(res, expected) { 1627 t.Fatalf("bad: %v %v", res, expected) 1628 } 1629 1630 // Get an empty list for an invalid meta value 1631 _, res, err = s.ServicesByNodeMeta(ws, map[string]string{"invalid": "nope"}) 1632 if err != nil { 1633 t.Fatalf("err: %s", err) 1634 } 1635 expected = structs.Services{} 1636 if !reflect.DeepEqual(res, expected) { 1637 t.Fatalf("bad: %v %v", res, expected) 1638 } 1639 1640 // Get the first node's service instance using multiple meta filters 1641 _, res, err = s.ServicesByNodeMeta(ws, map[string]string{"role": "client", "common": "1"}) 1642 if err != nil { 1643 t.Fatalf("err: %s", err) 1644 } 1645 expected = structs.Services{ 1646 "redis": []string{"master", "prod"}, 1647 } 1648 sort.Strings(res["redis"]) 1649 if !reflect.DeepEqual(res, expected) { 1650 t.Fatalf("bad: %v %v", res, expected) 1651 } 1652 1653 // Sanity check the watch before we proceed. 1654 if watchFired(ws) { 1655 t.Fatalf("bad") 1656 } 1657 1658 // Registering some unrelated node + service should not fire the watch. 1659 testRegisterNode(t, s, 4, "nope") 1660 testRegisterService(t, s, 5, "nope", "nope") 1661 if watchFired(ws) { 1662 t.Fatalf("bad") 1663 } 1664 1665 // Overwhelm the service tracking. 1666 idx = 6 1667 for i := 0; i < 2*watchLimit; i++ { 1668 node := fmt.Sprintf("many%d", i) 1669 testRegisterNodeWithMeta(t, s, idx, node, map[string]string{"common": "1"}) 1670 idx++ 1671 testRegisterService(t, s, idx, node, "nope") 1672 idx++ 1673 } 1674 1675 // Now get a fresh watch, which will be forced to watch the whole 1676 // service table. 1677 ws = memdb.NewWatchSet() 1678 _, _, err = s.ServicesByNodeMeta(ws, map[string]string{"common": "1"}) 1679 if err != nil { 1680 t.Fatalf("err: %s", err) 1681 } 1682 1683 // Registering some unrelated node + service should not fire the watch. 1684 testRegisterService(t, s, idx, "nope", "more-nope") 1685 if !watchFired(ws) { 1686 t.Fatalf("bad") 1687 } 1688 } 1689 1690 func TestStateStore_ServiceNodes(t *testing.T) { 1691 s := testStateStore(t) 1692 1693 // Listing with no results returns an empty list. 1694 ws := memdb.NewWatchSet() 1695 idx, nodes, err := s.ServiceNodes(ws, "db") 1696 if err != nil { 1697 t.Fatalf("err: %s", err) 1698 } 1699 if idx != 0 { 1700 t.Fatalf("bad: %d", idx) 1701 } 1702 if len(nodes) != 0 { 1703 t.Fatalf("bad: %v", nodes) 1704 } 1705 1706 // Create some nodes and services. 1707 if err := s.EnsureNode(10, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil { 1708 t.Fatalf("err: %v", err) 1709 } 1710 if err := s.EnsureNode(11, &structs.Node{Node: "bar", Address: "127.0.0.2"}); err != nil { 1711 t.Fatalf("err: %v", err) 1712 } 1713 if err := s.EnsureService(12, "foo", &structs.NodeService{ID: "api", Service: "api", Tags: nil, Address: "", Port: 5000}); err != nil { 1714 t.Fatalf("err: %v", err) 1715 } 1716 if err := s.EnsureService(13, "bar", &structs.NodeService{ID: "api", Service: "api", Tags: nil, Address: "", Port: 5000}); err != nil { 1717 t.Fatalf("err: %v", err) 1718 } 1719 if err := s.EnsureService(14, "foo", &structs.NodeService{ID: "db", Service: "db", Tags: []string{"master"}, Address: "", Port: 8000}); err != nil { 1720 t.Fatalf("err: %v", err) 1721 } 1722 if err := s.EnsureService(15, "bar", &structs.NodeService{ID: "db", Service: "db", Tags: []string{"slave"}, Address: "", Port: 8000}); err != nil { 1723 t.Fatalf("err: %v", err) 1724 } 1725 if err := s.EnsureService(16, "bar", &structs.NodeService{ID: "db2", Service: "db", Tags: []string{"slave"}, Address: "", Port: 8001}); err != nil { 1726 t.Fatalf("err: %v", err) 1727 } 1728 if !watchFired(ws) { 1729 t.Fatalf("bad") 1730 } 1731 1732 // Read everything back. 1733 ws = memdb.NewWatchSet() 1734 idx, nodes, err = s.ServiceNodes(ws, "db") 1735 if err != nil { 1736 t.Fatalf("err: %s", err) 1737 } 1738 if idx != 16 { 1739 t.Fatalf("bad: %d", idx) 1740 } 1741 if len(nodes) != 3 { 1742 t.Fatalf("bad: %v", nodes) 1743 } 1744 if nodes[0].Node != "bar" { 1745 t.Fatalf("bad: %v", nodes) 1746 } 1747 if nodes[0].Address != "127.0.0.2" { 1748 t.Fatalf("bad: %v", nodes) 1749 } 1750 if nodes[0].ServiceID != "db" { 1751 t.Fatalf("bad: %v", nodes) 1752 } 1753 if !lib.StrContains(nodes[0].ServiceTags, "slave") { 1754 t.Fatalf("bad: %v", nodes) 1755 } 1756 if nodes[0].ServicePort != 8000 { 1757 t.Fatalf("bad: %v", nodes) 1758 } 1759 if nodes[1].Node != "bar" { 1760 t.Fatalf("bad: %v", nodes) 1761 } 1762 if nodes[1].Address != "127.0.0.2" { 1763 t.Fatalf("bad: %v", nodes) 1764 } 1765 if nodes[1].ServiceID != "db2" { 1766 t.Fatalf("bad: %v", nodes) 1767 } 1768 if !lib.StrContains(nodes[1].ServiceTags, "slave") { 1769 t.Fatalf("bad: %v", nodes) 1770 } 1771 if nodes[1].ServicePort != 8001 { 1772 t.Fatalf("bad: %v", nodes) 1773 } 1774 if nodes[2].Node != "foo" { 1775 t.Fatalf("bad: %v", nodes) 1776 } 1777 if nodes[2].Address != "127.0.0.1" { 1778 t.Fatalf("bad: %v", nodes) 1779 } 1780 if nodes[2].ServiceID != "db" { 1781 t.Fatalf("bad: %v", nodes) 1782 } 1783 if !lib.StrContains(nodes[2].ServiceTags, "master") { 1784 t.Fatalf("bad: %v", nodes) 1785 } 1786 if nodes[2].ServicePort != 8000 { 1787 t.Fatalf("bad: %v", nodes) 1788 } 1789 1790 // Registering some unrelated node should not fire the watch. 1791 testRegisterNode(t, s, 17, "nope") 1792 if watchFired(ws) { 1793 t.Fatalf("bad") 1794 } 1795 1796 // But removing a node with the "db" service should fire the watch. 1797 if err := s.DeleteNode(18, "bar"); err != nil { 1798 t.Fatalf("err: %s", err) 1799 } 1800 if !watchFired(ws) { 1801 t.Fatalf("bad") 1802 } 1803 1804 // Overwhelm the node tracking. 1805 idx = 19 1806 for i := 0; i < 2*watchLimit; i++ { 1807 node := fmt.Sprintf("many%d", i) 1808 if err := s.EnsureNode(idx, &structs.Node{Node: node, Address: "127.0.0.1"}); err != nil { 1809 t.Fatalf("err: %v", err) 1810 } 1811 if err := s.EnsureService(idx, node, &structs.NodeService{ID: "db", Service: "db", Port: 8000}); err != nil { 1812 t.Fatalf("err: %v", err) 1813 } 1814 idx++ 1815 } 1816 1817 // Now get a fresh watch, which will be forced to watch the whole nodes 1818 // table. 1819 ws = memdb.NewWatchSet() 1820 _, _, err = s.ServiceNodes(ws, "db") 1821 if err != nil { 1822 t.Fatalf("err: %s", err) 1823 } 1824 1825 // Registering some unrelated node should fire the watch now. 1826 testRegisterNode(t, s, idx, "more-nope") 1827 if !watchFired(ws) { 1828 t.Fatalf("bad") 1829 } 1830 } 1831 1832 func TestStateStore_ServiceTagNodes(t *testing.T) { 1833 s := testStateStore(t) 1834 1835 // Listing with no results returns an empty list. 1836 ws := memdb.NewWatchSet() 1837 idx, nodes, err := s.ServiceTagNodes(ws, "db", []string{"master"}) 1838 if err != nil { 1839 t.Fatalf("err: %s", err) 1840 } 1841 if idx != 0 { 1842 t.Fatalf("bad: %d", idx) 1843 } 1844 if len(nodes) != 0 { 1845 t.Fatalf("bad: %v", nodes) 1846 } 1847 1848 // Create some nodes and services. 1849 if err := s.EnsureNode(15, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil { 1850 t.Fatalf("err: %v", err) 1851 } 1852 if err := s.EnsureNode(16, &structs.Node{Node: "bar", Address: "127.0.0.2"}); err != nil { 1853 t.Fatalf("err: %v", err) 1854 } 1855 if err := s.EnsureService(17, "foo", &structs.NodeService{ID: "db", Service: "db", Tags: []string{"master"}, Address: "", Port: 8000}); err != nil { 1856 t.Fatalf("err: %v", err) 1857 } 1858 if err := s.EnsureService(18, "foo", &structs.NodeService{ID: "db2", Service: "db", Tags: []string{"slave"}, Address: "", Port: 8001}); err != nil { 1859 t.Fatalf("err: %v", err) 1860 } 1861 if err := s.EnsureService(19, "bar", &structs.NodeService{ID: "db", Service: "db", Tags: []string{"slave"}, Address: "", Port: 8000}); err != nil { 1862 t.Fatalf("err: %v", err) 1863 } 1864 if !watchFired(ws) { 1865 t.Fatalf("bad") 1866 } 1867 1868 // Read everything back. 1869 ws = memdb.NewWatchSet() 1870 idx, nodes, err = s.ServiceTagNodes(ws, "db", []string{"master"}) 1871 if err != nil { 1872 t.Fatalf("err: %s", err) 1873 } 1874 if idx != 19 { 1875 t.Fatalf("bad: %v", idx) 1876 } 1877 if len(nodes) != 1 { 1878 t.Fatalf("bad: %v", nodes) 1879 } 1880 if nodes[0].Node != "foo" { 1881 t.Fatalf("bad: %v", nodes) 1882 } 1883 if nodes[0].Address != "127.0.0.1" { 1884 t.Fatalf("bad: %v", nodes) 1885 } 1886 if !lib.StrContains(nodes[0].ServiceTags, "master") { 1887 t.Fatalf("bad: %v", nodes) 1888 } 1889 if nodes[0].ServicePort != 8000 { 1890 t.Fatalf("bad: %v", nodes) 1891 } 1892 1893 // Registering some unrelated node should not fire the watch. 1894 testRegisterNode(t, s, 20, "nope") 1895 if watchFired(ws) { 1896 t.Fatalf("bad") 1897 } 1898 1899 // But removing a node with the "db:master" service should fire the watch. 1900 if err := s.DeleteNode(21, "foo"); err != nil { 1901 t.Fatalf("err: %s", err) 1902 } 1903 if !watchFired(ws) { 1904 t.Fatalf("bad") 1905 } 1906 } 1907 1908 func TestStateStore_ServiceTagNodes_MultipleTags(t *testing.T) { 1909 s := testStateStore(t) 1910 1911 if err := s.EnsureNode(15, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil { 1912 t.Fatalf("err: %v", err) 1913 } 1914 1915 if err := s.EnsureNode(16, &structs.Node{Node: "bar", Address: "127.0.0.2"}); err != nil { 1916 t.Fatalf("err: %v", err) 1917 } 1918 1919 if err := s.EnsureService(17, "foo", &structs.NodeService{ID: "db", Service: "db", Tags: []string{"master", "v2"}, Address: "", Port: 8000}); err != nil { 1920 t.Fatalf("err: %v", err) 1921 } 1922 1923 if err := s.EnsureService(18, "foo", &structs.NodeService{ID: "db2", Service: "db", Tags: []string{"slave", "v2", "dev"}, Address: "", Port: 8001}); err != nil { 1924 t.Fatalf("err: %v", err) 1925 } 1926 1927 if err := s.EnsureService(19, "bar", &structs.NodeService{ID: "db", Service: "db", Tags: []string{"slave", "v2"}, Address: "", Port: 8000}); err != nil { 1928 t.Fatalf("err: %v", err) 1929 } 1930 1931 idx, nodes, err := s.ServiceTagNodes(nil, "db", []string{"master"}) 1932 require.NoError(t, err) 1933 require.Equal(t, int(idx), 19) 1934 require.Len(t, nodes, 1) 1935 require.Equal(t, nodes[0].Node, "foo") 1936 require.Equal(t, nodes[0].Address, "127.0.0.1") 1937 require.Contains(t, nodes[0].ServiceTags, "master") 1938 require.Equal(t, nodes[0].ServicePort, 8000) 1939 1940 idx, nodes, err = s.ServiceTagNodes(nil, "db", []string{"v2"}) 1941 require.NoError(t, err) 1942 require.Equal(t, int(idx), 19) 1943 require.Len(t, nodes, 3) 1944 1945 // Test filtering on multiple tags 1946 idx, nodes, err = s.ServiceTagNodes(nil, "db", []string{"v2", "slave"}) 1947 require.NoError(t, err) 1948 require.Equal(t, int(idx), 19) 1949 require.Len(t, nodes, 2) 1950 require.Contains(t, nodes[0].ServiceTags, "v2") 1951 require.Contains(t, nodes[0].ServiceTags, "slave") 1952 require.Contains(t, nodes[1].ServiceTags, "v2") 1953 require.Contains(t, nodes[1].ServiceTags, "slave") 1954 1955 idx, nodes, err = s.ServiceTagNodes(nil, "db", []string{"dev"}) 1956 require.NoError(t, err) 1957 require.Equal(t, int(idx), 19) 1958 require.Len(t, nodes, 1) 1959 require.Equal(t, nodes[0].Node, "foo") 1960 require.Equal(t, nodes[0].Address, "127.0.0.1") 1961 require.Contains(t, nodes[0].ServiceTags, "dev") 1962 require.Equal(t, nodes[0].ServicePort, 8001) 1963 } 1964 1965 func TestStateStore_DeleteService(t *testing.T) { 1966 s := testStateStore(t) 1967 1968 // Register a node with one service and a check. 1969 testRegisterNode(t, s, 1, "node1") 1970 testRegisterService(t, s, 2, "node1", "service1") 1971 testRegisterCheck(t, s, 3, "node1", "service1", "check1", api.HealthPassing) 1972 1973 // Delete the service. 1974 ws := memdb.NewWatchSet() 1975 _, _, err := s.NodeServices(ws, "node1") 1976 if err := s.DeleteService(4, "node1", "service1"); err != nil { 1977 t.Fatalf("err: %s", err) 1978 } 1979 if !watchFired(ws) { 1980 t.Fatalf("bad") 1981 } 1982 1983 // Service doesn't exist. 1984 ws = memdb.NewWatchSet() 1985 _, ns, err := s.NodeServices(ws, "node1") 1986 if err != nil || ns == nil || len(ns.Services) != 0 { 1987 t.Fatalf("bad: %#v (err: %#v)", ns, err) 1988 } 1989 1990 // Check doesn't exist. Check using the raw DB so we can test 1991 // that it actually is removed in the state store. 1992 tx := s.db.Txn(false) 1993 defer tx.Abort() 1994 check, err := tx.First("checks", "id", "node1", "check1") 1995 if err != nil || check != nil { 1996 t.Fatalf("bad: %#v (err: %s)", check, err) 1997 } 1998 1999 // Index tables were updated. 2000 if idx := s.maxIndex("services"); idx != 4 { 2001 t.Fatalf("bad index: %d", idx) 2002 } 2003 if idx := s.maxIndex("checks"); idx != 4 { 2004 t.Fatalf("bad index: %d", idx) 2005 } 2006 2007 // Deleting a nonexistent service should be idempotent and not return an 2008 // error, nor fire a watch. 2009 if err := s.DeleteService(5, "node1", "service1"); err != nil { 2010 t.Fatalf("err: %s", err) 2011 } 2012 if idx := s.maxIndex("services"); idx != 4 { 2013 t.Fatalf("bad index: %d", idx) 2014 } 2015 if watchFired(ws) { 2016 t.Fatalf("bad") 2017 } 2018 } 2019 2020 func TestStateStore_ConnectServiceNodes(t *testing.T) { 2021 assert := assert.New(t) 2022 s := testStateStore(t) 2023 2024 // Listing with no results returns an empty list. 2025 ws := memdb.NewWatchSet() 2026 idx, nodes, err := s.ConnectServiceNodes(ws, "db") 2027 assert.Nil(err) 2028 assert.Equal(idx, uint64(0)) 2029 assert.Len(nodes, 0) 2030 2031 // Create some nodes and services. 2032 assert.Nil(s.EnsureNode(10, &structs.Node{Node: "foo", Address: "127.0.0.1"})) 2033 assert.Nil(s.EnsureNode(11, &structs.Node{Node: "bar", Address: "127.0.0.2"})) 2034 assert.Nil(s.EnsureService(12, "foo", &structs.NodeService{ID: "db", Service: "db", Tags: nil, Address: "", Port: 5000})) 2035 assert.Nil(s.EnsureService(13, "bar", &structs.NodeService{ID: "api", Service: "api", Tags: nil, Address: "", Port: 5000})) 2036 assert.Nil(s.EnsureService(14, "foo", &structs.NodeService{Kind: structs.ServiceKindConnectProxy, ID: "proxy", Service: "proxy", Proxy: structs.ConnectProxyConfig{DestinationServiceName: "db"}, Port: 8000})) 2037 assert.Nil(s.EnsureService(15, "bar", &structs.NodeService{Kind: structs.ServiceKindConnectProxy, ID: "proxy", Service: "proxy", Proxy: structs.ConnectProxyConfig{DestinationServiceName: "db"}, Port: 8000})) 2038 assert.Nil(s.EnsureService(16, "bar", &structs.NodeService{ID: "native-db", Service: "db", Connect: structs.ServiceConnect{Native: true}})) 2039 assert.Nil(s.EnsureService(17, "bar", &structs.NodeService{ID: "db2", Service: "db", Tags: []string{"slave"}, Address: "", Port: 8001})) 2040 assert.True(watchFired(ws)) 2041 2042 // Read everything back. 2043 ws = memdb.NewWatchSet() 2044 idx, nodes, err = s.ConnectServiceNodes(ws, "db") 2045 assert.Nil(err) 2046 assert.Equal(idx, uint64(idx)) 2047 assert.Len(nodes, 3) 2048 2049 for _, n := range nodes { 2050 assert.True( 2051 n.ServiceKind == structs.ServiceKindConnectProxy || 2052 n.ServiceConnect.Native, 2053 "either proxy or connect native") 2054 } 2055 2056 // Registering some unrelated node should not fire the watch. 2057 testRegisterNode(t, s, 17, "nope") 2058 assert.False(watchFired(ws)) 2059 2060 // But removing a node with the "db" service should fire the watch. 2061 assert.Nil(s.DeleteNode(18, "bar")) 2062 assert.True(watchFired(ws)) 2063 } 2064 2065 func TestStateStore_Service_Snapshot(t *testing.T) { 2066 s := testStateStore(t) 2067 2068 // Register a node with two services. 2069 testRegisterNode(t, s, 0, "node1") 2070 ns := []*structs.NodeService{ 2071 &structs.NodeService{ 2072 ID: "service1", 2073 Service: "redis", 2074 Tags: []string{"prod"}, 2075 Address: "1.1.1.1", 2076 Port: 1111, 2077 Weights: &structs.Weights{Passing: 1, Warning: 0}, 2078 }, 2079 &structs.NodeService{ 2080 ID: "service2", 2081 Service: "nomad", 2082 Tags: []string{"dev"}, 2083 Address: "1.1.1.2", 2084 Port: 1112, 2085 Weights: &structs.Weights{Passing: 1, Warning: 1}, 2086 }, 2087 } 2088 for i, svc := range ns { 2089 if err := s.EnsureService(uint64(i+1), "node1", svc); err != nil { 2090 t.Fatalf("err: %s", err) 2091 } 2092 } 2093 2094 // Create a second node/service to make sure node filtering works. This 2095 // will affect the index but not the dump. 2096 testRegisterNode(t, s, 3, "node2") 2097 testRegisterService(t, s, 4, "node2", "service2") 2098 2099 // Snapshot the service. 2100 snap := s.Snapshot() 2101 defer snap.Close() 2102 2103 // Alter the real state store. 2104 testRegisterService(t, s, 5, "node2", "service3") 2105 2106 // Verify the snapshot. 2107 if idx := snap.LastIndex(); idx != 4 { 2108 t.Fatalf("bad index: %d", idx) 2109 } 2110 services, err := snap.Services("node1") 2111 if err != nil { 2112 t.Fatalf("err: %s", err) 2113 } 2114 for i := 0; i < len(ns); i++ { 2115 svc := services.Next().(*structs.ServiceNode) 2116 if svc == nil { 2117 t.Fatalf("unexpected end of services") 2118 } 2119 2120 ns[i].CreateIndex, ns[i].ModifyIndex = uint64(i+1), uint64(i+1) 2121 if !reflect.DeepEqual(ns[i], svc.ToNodeService()) { 2122 t.Fatalf("bad: %#v != %#v", svc, ns[i]) 2123 } 2124 } 2125 if services.Next() != nil { 2126 t.Fatalf("unexpected extra services") 2127 } 2128 } 2129 2130 func TestStateStore_EnsureCheck(t *testing.T) { 2131 s := testStateStore(t) 2132 2133 // Create a check associated with the node 2134 check := &structs.HealthCheck{ 2135 Node: "node1", 2136 CheckID: "check1", 2137 Name: "redis check", 2138 Status: api.HealthPassing, 2139 Notes: "test check", 2140 Output: "aaa", 2141 ServiceID: "service1", 2142 ServiceName: "redis", 2143 } 2144 2145 // Creating a check without a node returns error 2146 if err := s.EnsureCheck(1, check); err != ErrMissingNode { 2147 t.Fatalf("expected %#v, got: %#v", ErrMissingNode, err) 2148 } 2149 2150 // Register the node 2151 testRegisterNode(t, s, 1, "node1") 2152 2153 // Creating a check with a bad services returns error 2154 if err := s.EnsureCheck(1, check); err != ErrMissingService { 2155 t.Fatalf("expected: %#v, got: %#v", ErrMissingService, err) 2156 } 2157 2158 // Register the service 2159 testRegisterService(t, s, 2, "node1", "service1") 2160 2161 // Inserting the check with the prerequisites succeeds 2162 if err := s.EnsureCheck(3, check); err != nil { 2163 t.Fatalf("err: %s", err) 2164 } 2165 2166 // Retrieve the check and make sure it matches 2167 idx, checks, err := s.NodeChecks(nil, "node1") 2168 if err != nil { 2169 t.Fatalf("err: %s", err) 2170 } 2171 if idx != 3 { 2172 t.Fatalf("bad index: %d", idx) 2173 } 2174 if len(checks) != 1 { 2175 t.Fatalf("wrong number of checks: %d", len(checks)) 2176 } 2177 if !reflect.DeepEqual(checks[0], check) { 2178 t.Fatalf("bad: %#v", checks[0]) 2179 } 2180 2181 testCheckOutput := func(expectedNodeIndex, expectedIndexForCheck uint64, outputTxt string) { 2182 // Check that we successfully updated 2183 idx, checks, err = s.NodeChecks(nil, "node1") 2184 if err != nil { 2185 t.Fatalf("err: %s", err) 2186 } 2187 if idx != expectedNodeIndex { 2188 t.Fatalf("bad index: %d", idx) 2189 } 2190 2191 if len(checks) != 1 { 2192 t.Fatalf("wrong number of checks: %d", len(checks)) 2193 } 2194 if checks[0].Output != outputTxt { 2195 t.Fatalf("wrong check output: %#v", checks[0]) 2196 } 2197 if checks[0].CreateIndex != 3 || checks[0].ModifyIndex != expectedIndexForCheck { 2198 t.Fatalf("bad index: %#v, expectedIndexForCheck:=%v ", checks[0], expectedIndexForCheck) 2199 } 2200 } 2201 // Do not really modify the health check content the health check 2202 check = &structs.HealthCheck{ 2203 Node: "node1", 2204 CheckID: "check1", 2205 Name: "redis check", 2206 Status: api.HealthPassing, 2207 Notes: "test check", 2208 Output: "aaa", 2209 ServiceID: "service1", 2210 ServiceName: "redis", 2211 } 2212 if err := s.EnsureCheck(4, check); err != nil { 2213 t.Fatalf("err: %s", err) 2214 } 2215 testCheckOutput(4, 3, check.Output) 2216 2217 // Do modify the heathcheck 2218 check = &structs.HealthCheck{ 2219 Node: "node1", 2220 CheckID: "check1", 2221 Name: "redis check", 2222 Status: api.HealthPassing, 2223 Notes: "test check", 2224 Output: "bbbmodified", 2225 ServiceID: "service1", 2226 ServiceName: "redis", 2227 } 2228 if err := s.EnsureCheck(5, check); err != nil { 2229 t.Fatalf("err: %s", err) 2230 } 2231 testCheckOutput(5, 5, "bbbmodified") 2232 2233 // Index tables were updated 2234 if idx := s.maxIndex("checks"); idx != 5 { 2235 t.Fatalf("bad index: %d", idx) 2236 } 2237 } 2238 2239 func TestStateStore_EnsureCheck_defaultStatus(t *testing.T) { 2240 s := testStateStore(t) 2241 2242 // Register a node 2243 testRegisterNode(t, s, 1, "node1") 2244 2245 // Create and register a check with no health status 2246 check := &structs.HealthCheck{ 2247 Node: "node1", 2248 CheckID: "check1", 2249 Status: "", 2250 } 2251 if err := s.EnsureCheck(2, check); err != nil { 2252 t.Fatalf("err: %s", err) 2253 } 2254 2255 // Get the check again 2256 _, result, err := s.NodeChecks(nil, "node1") 2257 if err != nil { 2258 t.Fatalf("err: %s", err) 2259 } 2260 2261 // Check that the status was set to the proper default 2262 if len(result) != 1 || result[0].Status != api.HealthCritical { 2263 t.Fatalf("bad: %#v", result) 2264 } 2265 } 2266 2267 func TestStateStore_NodeChecks(t *testing.T) { 2268 s := testStateStore(t) 2269 2270 // Do an initial query for a node that doesn't exist. 2271 ws := memdb.NewWatchSet() 2272 idx, checks, err := s.NodeChecks(ws, "node1") 2273 if err != nil { 2274 t.Fatalf("err: %s", err) 2275 } 2276 if idx != 0 { 2277 t.Fatalf("bad: %d", idx) 2278 } 2279 if len(checks) != 0 { 2280 t.Fatalf("bad: %#v", checks) 2281 } 2282 2283 // Create some nodes and checks. 2284 testRegisterNode(t, s, 0, "node1") 2285 testRegisterService(t, s, 1, "node1", "service1") 2286 testRegisterCheck(t, s, 2, "node1", "service1", "check1", api.HealthPassing) 2287 testRegisterCheck(t, s, 3, "node1", "service1", "check2", api.HealthPassing) 2288 testRegisterNode(t, s, 4, "node2") 2289 testRegisterService(t, s, 5, "node2", "service2") 2290 testRegisterCheck(t, s, 6, "node2", "service2", "check3", api.HealthPassing) 2291 if !watchFired(ws) { 2292 t.Fatalf("bad") 2293 } 2294 2295 // Try querying for all checks associated with node1 2296 ws = memdb.NewWatchSet() 2297 idx, checks, err = s.NodeChecks(ws, "node1") 2298 if err != nil { 2299 t.Fatalf("err: %s", err) 2300 } 2301 if idx != 6 { 2302 t.Fatalf("bad index: %d", idx) 2303 } 2304 if len(checks) != 2 || checks[0].CheckID != "check1" || checks[1].CheckID != "check2" { 2305 t.Fatalf("bad checks: %#v", checks) 2306 } 2307 2308 // Creating some unrelated node should not fire the watch. 2309 testRegisterNode(t, s, 7, "node3") 2310 testRegisterCheck(t, s, 8, "node3", "", "check1", api.HealthPassing) 2311 if watchFired(ws) { 2312 t.Fatalf("bad") 2313 } 2314 2315 // Try querying for all checks associated with node2 2316 ws = memdb.NewWatchSet() 2317 idx, checks, err = s.NodeChecks(ws, "node2") 2318 if err != nil { 2319 t.Fatalf("err: %s", err) 2320 } 2321 if idx != 8 { 2322 t.Fatalf("bad index: %d", idx) 2323 } 2324 if len(checks) != 1 || checks[0].CheckID != "check3" { 2325 t.Fatalf("bad checks: %#v", checks) 2326 } 2327 2328 // Changing node2 should fire the watch. 2329 testRegisterCheck(t, s, 9, "node2", "service2", "check3", api.HealthCritical) 2330 if !watchFired(ws) { 2331 t.Fatalf("bad") 2332 } 2333 } 2334 2335 func TestStateStore_ServiceChecks(t *testing.T) { 2336 s := testStateStore(t) 2337 2338 // Do an initial query for a service that doesn't exist. 2339 ws := memdb.NewWatchSet() 2340 idx, checks, err := s.ServiceChecks(ws, "service1") 2341 if err != nil { 2342 t.Fatalf("err: %s", err) 2343 } 2344 if idx != 0 { 2345 t.Fatalf("bad: %d", idx) 2346 } 2347 if len(checks) != 0 { 2348 t.Fatalf("bad: %#v", checks) 2349 } 2350 2351 // Create some nodes and checks. 2352 testRegisterNode(t, s, 0, "node1") 2353 testRegisterService(t, s, 1, "node1", "service1") 2354 testRegisterCheck(t, s, 2, "node1", "service1", "check1", api.HealthPassing) 2355 testRegisterCheck(t, s, 3, "node1", "service1", "check2", api.HealthPassing) 2356 testRegisterNode(t, s, 4, "node2") 2357 testRegisterService(t, s, 5, "node2", "service2") 2358 testRegisterCheck(t, s, 6, "node2", "service2", "check3", api.HealthPassing) 2359 if !watchFired(ws) { 2360 t.Fatalf("bad") 2361 } 2362 2363 // Try querying for all checks associated with service1. 2364 ws = memdb.NewWatchSet() 2365 idx, checks, err = s.ServiceChecks(ws, "service1") 2366 if err != nil { 2367 t.Fatalf("err: %s", err) 2368 } 2369 if idx != 6 { 2370 t.Fatalf("bad index: %d", idx) 2371 } 2372 if len(checks) != 2 || checks[0].CheckID != "check1" || checks[1].CheckID != "check2" { 2373 t.Fatalf("bad checks: %#v", checks) 2374 } 2375 2376 // Adding some unrelated service + check should not fire the watch. 2377 testRegisterService(t, s, 7, "node1", "service3") 2378 testRegisterCheck(t, s, 8, "node1", "service3", "check3", api.HealthPassing) 2379 if watchFired(ws) { 2380 t.Fatalf("bad") 2381 } 2382 2383 // Updating a related check should fire the watch. 2384 testRegisterCheck(t, s, 9, "node1", "service1", "check2", api.HealthCritical) 2385 if !watchFired(ws) { 2386 t.Fatalf("bad") 2387 } 2388 } 2389 2390 func TestStateStore_ServiceChecksByNodeMeta(t *testing.T) { 2391 s := testStateStore(t) 2392 2393 // Querying with no results returns nil. 2394 ws := memdb.NewWatchSet() 2395 idx, checks, err := s.ServiceChecksByNodeMeta(ws, "service1", nil) 2396 if err != nil { 2397 t.Fatalf("err: %s", err) 2398 } 2399 if idx != 0 { 2400 t.Fatalf("bad: %d", idx) 2401 } 2402 if len(checks) != 0 { 2403 t.Fatalf("bad: %#v", checks) 2404 } 2405 2406 // Create some nodes and checks. 2407 testRegisterNodeWithMeta(t, s, 0, "node1", map[string]string{"somekey": "somevalue", "common": "1"}) 2408 testRegisterService(t, s, 1, "node1", "service1") 2409 testRegisterCheck(t, s, 2, "node1", "service1", "check1", api.HealthPassing) 2410 testRegisterCheck(t, s, 3, "node1", "service1", "check2", api.HealthPassing) 2411 testRegisterNodeWithMeta(t, s, 4, "node2", map[string]string{"common": "1"}) 2412 testRegisterService(t, s, 5, "node2", "service1") 2413 testRegisterCheck(t, s, 6, "node2", "service1", "check3", api.HealthPassing) 2414 if !watchFired(ws) { 2415 t.Fatalf("bad") 2416 } 2417 2418 cases := []struct { 2419 filters map[string]string 2420 checks []string 2421 }{ 2422 // Basic meta filter 2423 { 2424 filters: map[string]string{"somekey": "somevalue"}, 2425 checks: []string{"check1", "check2"}, 2426 }, 2427 // Common meta field 2428 { 2429 filters: map[string]string{"common": "1"}, 2430 checks: []string{"check1", "check2", "check3"}, 2431 }, 2432 // Invalid meta filter 2433 { 2434 filters: map[string]string{"invalid": "nope"}, 2435 checks: []string{}, 2436 }, 2437 // Multiple filters 2438 { 2439 filters: map[string]string{"somekey": "somevalue", "common": "1"}, 2440 checks: []string{"check1", "check2"}, 2441 }, 2442 } 2443 2444 // Try querying for all checks associated with service1. 2445 idx = 7 2446 for _, tc := range cases { 2447 ws = memdb.NewWatchSet() 2448 _, checks, err := s.ServiceChecksByNodeMeta(ws, "service1", tc.filters) 2449 if err != nil { 2450 t.Fatalf("err: %s", err) 2451 } 2452 if len(checks) != len(tc.checks) { 2453 t.Fatalf("bad checks: %#v", checks) 2454 } 2455 for i, check := range checks { 2456 if check.CheckID != types.CheckID(tc.checks[i]) { 2457 t.Fatalf("bad checks: %#v", checks) 2458 } 2459 } 2460 2461 // Registering some unrelated node should not fire the watch. 2462 testRegisterNode(t, s, idx, fmt.Sprintf("nope%d", idx)) 2463 idx++ 2464 if watchFired(ws) { 2465 t.Fatalf("bad") 2466 } 2467 } 2468 2469 // Overwhelm the node tracking. 2470 for i := 0; i < 2*watchLimit; i++ { 2471 node := fmt.Sprintf("many%d", idx) 2472 testRegisterNodeWithMeta(t, s, idx, node, map[string]string{"common": "1"}) 2473 idx++ 2474 testRegisterService(t, s, idx, node, "service1") 2475 idx++ 2476 testRegisterCheck(t, s, idx, node, "service1", "check1", api.HealthPassing) 2477 idx++ 2478 } 2479 2480 // Now get a fresh watch, which will be forced to watch the whole 2481 // node table. 2482 ws = memdb.NewWatchSet() 2483 _, _, err = s.ServiceChecksByNodeMeta(ws, "service1", 2484 map[string]string{"common": "1"}) 2485 if err != nil { 2486 t.Fatalf("err: %s", err) 2487 } 2488 2489 // Registering some unrelated node should now fire the watch. 2490 testRegisterNode(t, s, idx, "nope") 2491 if !watchFired(ws) { 2492 t.Fatalf("bad") 2493 } 2494 } 2495 2496 func TestStateStore_ChecksInState(t *testing.T) { 2497 s := testStateStore(t) 2498 2499 // Querying with no results returns nil 2500 ws := memdb.NewWatchSet() 2501 idx, res, err := s.ChecksInState(ws, api.HealthPassing) 2502 if idx != 0 || res != nil || err != nil { 2503 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 2504 } 2505 2506 // Register a node with checks in varied states 2507 testRegisterNode(t, s, 0, "node1") 2508 testRegisterCheck(t, s, 1, "node1", "", "check1", api.HealthPassing) 2509 testRegisterCheck(t, s, 2, "node1", "", "check2", api.HealthCritical) 2510 testRegisterCheck(t, s, 3, "node1", "", "check3", api.HealthPassing) 2511 if !watchFired(ws) { 2512 t.Fatalf("bad") 2513 } 2514 2515 // Query the state store for passing checks. 2516 ws = memdb.NewWatchSet() 2517 _, checks, err := s.ChecksInState(ws, api.HealthPassing) 2518 if err != nil { 2519 t.Fatalf("err: %s", err) 2520 } 2521 2522 // Make sure we only get the checks which match the state 2523 if n := len(checks); n != 2 { 2524 t.Fatalf("expected 2 checks, got: %d", n) 2525 } 2526 if checks[0].CheckID != "check1" || checks[1].CheckID != "check3" { 2527 t.Fatalf("bad: %#v", checks) 2528 } 2529 if watchFired(ws) { 2530 t.Fatalf("bad") 2531 } 2532 2533 // Changing the state of a check should fire the watch. 2534 testRegisterCheck(t, s, 4, "node1", "", "check1", api.HealthCritical) 2535 if !watchFired(ws) { 2536 t.Fatalf("bad") 2537 } 2538 2539 // HealthAny just returns everything. 2540 ws = memdb.NewWatchSet() 2541 _, checks, err = s.ChecksInState(ws, api.HealthAny) 2542 if err != nil { 2543 t.Fatalf("err: %s", err) 2544 } 2545 if n := len(checks); n != 3 { 2546 t.Fatalf("expected 3 checks, got: %d", n) 2547 } 2548 if watchFired(ws) { 2549 t.Fatalf("bad") 2550 } 2551 2552 // Adding a new check should fire the watch. 2553 testRegisterCheck(t, s, 5, "node1", "", "check4", api.HealthCritical) 2554 if !watchFired(ws) { 2555 t.Fatalf("bad") 2556 } 2557 } 2558 2559 func TestStateStore_ChecksInStateByNodeMeta(t *testing.T) { 2560 s := testStateStore(t) 2561 2562 // Querying with no results returns nil. 2563 ws := memdb.NewWatchSet() 2564 idx, res, err := s.ChecksInStateByNodeMeta(ws, api.HealthPassing, nil) 2565 if idx != 0 || res != nil || err != nil { 2566 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 2567 } 2568 2569 // Register a node with checks in varied states. 2570 testRegisterNodeWithMeta(t, s, 0, "node1", map[string]string{"somekey": "somevalue", "common": "1"}) 2571 testRegisterCheck(t, s, 1, "node1", "", "check1", api.HealthPassing) 2572 testRegisterCheck(t, s, 2, "node1", "", "check2", api.HealthCritical) 2573 testRegisterNodeWithMeta(t, s, 3, "node2", map[string]string{"common": "1"}) 2574 testRegisterCheck(t, s, 4, "node2", "", "check3", api.HealthPassing) 2575 if !watchFired(ws) { 2576 t.Fatalf("bad") 2577 } 2578 2579 cases := []struct { 2580 filters map[string]string 2581 state string 2582 checks []string 2583 }{ 2584 // Basic meta filter, any status 2585 { 2586 filters: map[string]string{"somekey": "somevalue"}, 2587 state: api.HealthAny, 2588 checks: []string{"check2", "check1"}, 2589 }, 2590 // Basic meta filter, only passing 2591 { 2592 filters: map[string]string{"somekey": "somevalue"}, 2593 state: api.HealthPassing, 2594 checks: []string{"check1"}, 2595 }, 2596 // Common meta filter, any status 2597 { 2598 filters: map[string]string{"common": "1"}, 2599 state: api.HealthAny, 2600 checks: []string{"check2", "check1", "check3"}, 2601 }, 2602 // Common meta filter, only passing 2603 { 2604 filters: map[string]string{"common": "1"}, 2605 state: api.HealthPassing, 2606 checks: []string{"check1", "check3"}, 2607 }, 2608 // Invalid meta filter 2609 { 2610 filters: map[string]string{"invalid": "nope"}, 2611 checks: []string{}, 2612 }, 2613 // Multiple filters, any status 2614 { 2615 filters: map[string]string{"somekey": "somevalue", "common": "1"}, 2616 state: api.HealthAny, 2617 checks: []string{"check2", "check1"}, 2618 }, 2619 // Multiple filters, only passing 2620 { 2621 filters: map[string]string{"somekey": "somevalue", "common": "1"}, 2622 state: api.HealthPassing, 2623 checks: []string{"check1"}, 2624 }, 2625 } 2626 2627 // Try querying for all checks associated with service1. 2628 idx = 5 2629 for _, tc := range cases { 2630 ws = memdb.NewWatchSet() 2631 _, checks, err := s.ChecksInStateByNodeMeta(ws, tc.state, tc.filters) 2632 if err != nil { 2633 t.Fatalf("err: %s", err) 2634 } 2635 if len(checks) != len(tc.checks) { 2636 t.Fatalf("bad checks: %#v", checks) 2637 } 2638 for i, check := range checks { 2639 if check.CheckID != types.CheckID(tc.checks[i]) { 2640 t.Fatalf("bad checks: %#v, %v", checks, tc.checks) 2641 } 2642 } 2643 2644 // Registering some unrelated node should not fire the watch. 2645 testRegisterNode(t, s, idx, fmt.Sprintf("nope%d", idx)) 2646 idx++ 2647 if watchFired(ws) { 2648 t.Fatalf("bad") 2649 } 2650 } 2651 2652 // Overwhelm the node tracking. 2653 for i := 0; i < 2*watchLimit; i++ { 2654 node := fmt.Sprintf("many%d", idx) 2655 testRegisterNodeWithMeta(t, s, idx, node, map[string]string{"common": "1"}) 2656 idx++ 2657 testRegisterService(t, s, idx, node, "service1") 2658 idx++ 2659 testRegisterCheck(t, s, idx, node, "service1", "check1", api.HealthPassing) 2660 idx++ 2661 } 2662 2663 // Now get a fresh watch, which will be forced to watch the whole 2664 // node table. 2665 ws = memdb.NewWatchSet() 2666 _, _, err = s.ChecksInStateByNodeMeta(ws, api.HealthPassing, 2667 map[string]string{"common": "1"}) 2668 if err != nil { 2669 t.Fatalf("err: %s", err) 2670 } 2671 2672 // Registering some unrelated node should now fire the watch. 2673 testRegisterNode(t, s, idx, "nope") 2674 if !watchFired(ws) { 2675 t.Fatalf("bad") 2676 } 2677 } 2678 2679 func TestStateStore_DeleteCheck(t *testing.T) { 2680 s := testStateStore(t) 2681 2682 // Register a node and a node-level health check. 2683 testRegisterNode(t, s, 1, "node1") 2684 testRegisterCheck(t, s, 2, "node1", "", "check1", api.HealthPassing) 2685 testRegisterService(t, s, 2, "node1", "service1") 2686 2687 // Make sure the check is there. 2688 ws := memdb.NewWatchSet() 2689 _, checks, err := s.NodeChecks(ws, "node1") 2690 if err != nil { 2691 t.Fatalf("err: %s", err) 2692 } 2693 if len(checks) != 1 { 2694 t.Fatalf("bad: %#v", checks) 2695 } 2696 2697 ensureServiceVersion(t, s, ws, "service1", 2, 1) 2698 2699 // Delete the check. 2700 if err := s.DeleteCheck(3, "node1", "check1"); err != nil { 2701 t.Fatalf("err: %s", err) 2702 } 2703 if idx, check, err := s.NodeCheck("node1", "check1"); idx != 3 || err != nil || check != nil { 2704 t.Fatalf("Node check should have been deleted idx=%d, node=%v, err=%s", idx, check, err) 2705 } 2706 if idx := s.maxIndex("checks"); idx != 3 { 2707 t.Fatalf("bad index for checks: %d", idx) 2708 } 2709 if !watchFired(ws) { 2710 t.Fatalf("bad") 2711 } 2712 // All services linked to this node should have their index updated 2713 ensureServiceVersion(t, s, ws, "service1", 3, 1) 2714 2715 // Check is gone 2716 ws = memdb.NewWatchSet() 2717 _, checks, err = s.NodeChecks(ws, "node1") 2718 if err != nil { 2719 t.Fatalf("err: %s", err) 2720 } 2721 if len(checks) != 0 { 2722 t.Fatalf("bad: %#v", checks) 2723 } 2724 2725 // Index tables were updated. 2726 if idx := s.maxIndex("checks"); idx != 3 { 2727 t.Fatalf("bad index: %d", idx) 2728 } 2729 2730 // Deleting a nonexistent check should be idempotent and not return an 2731 // error. 2732 if err := s.DeleteCheck(4, "node1", "check1"); err != nil { 2733 t.Fatalf("err: %s", err) 2734 } 2735 if idx := s.maxIndex("checks"); idx != 3 { 2736 t.Fatalf("bad index: %d", idx) 2737 } 2738 if watchFired(ws) { 2739 t.Fatalf("bad") 2740 } 2741 } 2742 2743 func ensureServiceVersion(t *testing.T, s *Store, ws memdb.WatchSet, serviceID string, expectedIdx uint64, expectedSize int) { 2744 idx, services, err := s.ServiceNodes(ws, serviceID) 2745 t.Helper() 2746 if err != nil { 2747 t.Fatalf("err: %s", err) 2748 } 2749 if idx != expectedIdx { 2750 t.Fatalf("bad: %d, expected %d", idx, expectedIdx) 2751 } 2752 if len(services) != expectedSize { 2753 t.Fatalf("expected size: %d, but was %d", expectedSize, len(services)) 2754 } 2755 } 2756 2757 // Ensure index exist, if expectedIndex = -1, ensure the index does not exists 2758 func ensureIndexForService(t *testing.T, s *Store, ws memdb.WatchSet, serviceName string, expectedIndex uint64) { 2759 t.Helper() 2760 tx := s.db.Txn(false) 2761 defer tx.Abort() 2762 transaction, err := tx.First("index", "id", fmt.Sprintf("service.%s", serviceName)) 2763 if err == nil { 2764 if idx, ok := transaction.(*IndexEntry); ok { 2765 if expectedIndex != idx.Value { 2766 t.Fatalf("Expected index %d, but had %d for %s", expectedIndex, idx.Value, serviceName) 2767 } 2768 return 2769 } 2770 } 2771 if expectedIndex != 0 { 2772 t.Fatalf("Index for %s was expected but not found", serviceName) 2773 } 2774 } 2775 2776 // TestStateStore_IndexIndependence test that changes on a given service does not impact the 2777 // index of other services. It allows to have huge benefits for watches since 2778 // watchers are notified ONLY when there are changes in the given service 2779 func TestStateStore_IndexIndependence(t *testing.T) { 2780 s := testStateStore(t) 2781 2782 // Querying with no matches gives an empty response 2783 ws := memdb.NewWatchSet() 2784 idx, res, err := s.CheckServiceNodes(ws, "service1") 2785 if idx != 0 || res != nil || err != nil { 2786 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 2787 } 2788 2789 // Register some nodes. 2790 testRegisterNode(t, s, 0, "node1") 2791 testRegisterNode(t, s, 1, "node2") 2792 2793 // Register node-level checks. These should be the final result. 2794 testRegisterCheck(t, s, 2, "node1", "", "check1", api.HealthPassing) 2795 testRegisterCheck(t, s, 3, "node2", "", "check2", api.HealthPassing) 2796 2797 // Register a service against the nodes. 2798 testRegisterService(t, s, 4, "node1", "service1") 2799 testRegisterService(t, s, 5, "node2", "service2") 2800 ensureServiceVersion(t, s, ws, "service2", 5, 1) 2801 2802 // Register checks against the services. 2803 testRegisterCheck(t, s, 6, "node1", "service1", "check3", api.HealthPassing) 2804 testRegisterCheck(t, s, 7, "node2", "service2", "check4", api.HealthPassing) 2805 // Index must be updated when checks are updated 2806 ensureServiceVersion(t, s, ws, "service1", 6, 1) 2807 ensureServiceVersion(t, s, ws, "service2", 7, 1) 2808 2809 if !watchFired(ws) { 2810 t.Fatalf("bad") 2811 } 2812 // We ensure the idx for service2 has not been changed 2813 testRegisterCheck(t, s, 8, "node2", "service2", "check4", api.HealthWarning) 2814 ensureServiceVersion(t, s, ws, "service2", 8, 1) 2815 testRegisterCheck(t, s, 9, "node2", "service2", "check4", api.HealthPassing) 2816 ensureServiceVersion(t, s, ws, "service2", 9, 1) 2817 2818 // Add a new check on node1, while not on service, it should impact 2819 // indexes of all services running on node1, aka service1 2820 testRegisterCheck(t, s, 10, "node1", "", "check_node", api.HealthPassing) 2821 2822 // Service2 should not be modified 2823 ensureServiceVersion(t, s, ws, "service2", 9, 1) 2824 // Service1 should be modified 2825 ensureServiceVersion(t, s, ws, "service1", 10, 1) 2826 2827 if !watchFired(ws) { 2828 t.Fatalf("bad") 2829 } 2830 2831 testRegisterService(t, s, 11, "node1", "service_shared") 2832 ensureServiceVersion(t, s, ws, "service_shared", 11, 1) 2833 testRegisterService(t, s, 12, "node2", "service_shared") 2834 ensureServiceVersion(t, s, ws, "service_shared", 12, 2) 2835 2836 testRegisterCheck(t, s, 13, "node2", "service_shared", "check_service_shared", api.HealthCritical) 2837 ensureServiceVersion(t, s, ws, "service_shared", 13, 2) 2838 testRegisterCheck(t, s, 14, "node2", "service_shared", "check_service_shared", api.HealthPassing) 2839 ensureServiceVersion(t, s, ws, "service_shared", 14, 2) 2840 2841 s.DeleteCheck(15, "node2", types.CheckID("check_service_shared")) 2842 ensureServiceVersion(t, s, ws, "service_shared", 15, 2) 2843 ensureIndexForService(t, s, ws, "service_shared", 15) 2844 s.DeleteService(16, "node2", "service_shared") 2845 ensureServiceVersion(t, s, ws, "service_shared", 16, 1) 2846 ensureIndexForService(t, s, ws, "service_shared", 16) 2847 s.DeleteService(17, "node1", "service_shared") 2848 ensureServiceVersion(t, s, ws, "service_shared", 17, 0) 2849 2850 testRegisterService(t, s, 18, "node1", "service_new") 2851 2852 // Since service does not exists anymore, its index should be that of 2853 // the last deleted service 2854 ensureServiceVersion(t, s, ws, "service_shared", 17, 0) 2855 2856 // No index should exist anymore, it must have been garbage collected 2857 ensureIndexForService(t, s, ws, "service_shared", 0) 2858 if !watchFired(ws) { 2859 t.Fatalf("bad") 2860 } 2861 } 2862 2863 func TestStateStore_ConnectQueryBlocking(t *testing.T) { 2864 tests := []struct { 2865 name string 2866 setupFn func(s *Store) 2867 svc string 2868 wantBeforeResLen int 2869 wantBeforeWatchSetSize int 2870 updateFn func(s *Store) 2871 shouldFire bool 2872 wantAfterIndex uint64 2873 wantAfterResLen int 2874 wantAfterWatchSetSize int 2875 }{ 2876 { 2877 name: "not affected by non-connect-enabled target service registration", 2878 setupFn: nil, 2879 svc: "test", 2880 wantBeforeResLen: 0, 2881 // Only the connect index iterator is watched 2882 wantBeforeWatchSetSize: 1, 2883 updateFn: func(s *Store) { 2884 testRegisterService(t, s, 4, "node1", "test") 2885 }, 2886 shouldFire: false, 2887 wantAfterIndex: 4, // No results falls back to global service index 2888 wantAfterResLen: 0, 2889 // Only the connect index iterator is watched 2890 wantAfterWatchSetSize: 1, 2891 }, 2892 { 2893 name: "not affected by non-connect-enabled target service de-registration", 2894 setupFn: func(s *Store) { 2895 testRegisterService(t, s, 4, "node1", "test") 2896 }, 2897 svc: "test", 2898 wantBeforeResLen: 0, 2899 // Only the connect index iterator is watched 2900 wantBeforeWatchSetSize: 1, 2901 updateFn: func(s *Store) { 2902 require.NoError(t, s.DeleteService(5, "node1", "test")) 2903 }, 2904 // Note that the old implementation would unblock in this case since it 2905 // always watched the target service's index even though some updates 2906 // there don't affect Connect result output. This doesn't matter much for 2907 // correctness but it causes pointless work. 2908 shouldFire: false, 2909 wantAfterIndex: 5, // No results falls back to global service index 2910 wantAfterResLen: 0, 2911 // Only the connect index iterator is watched 2912 wantAfterWatchSetSize: 1, 2913 }, 2914 { 2915 name: "unblocks on first connect-native service registration", 2916 setupFn: nil, 2917 svc: "test", 2918 wantBeforeResLen: 0, 2919 // Only the connect index iterator is watched 2920 wantBeforeWatchSetSize: 1, 2921 updateFn: func(s *Store) { 2922 testRegisterConnectNativeService(t, s, 4, "node1", "test") 2923 }, 2924 shouldFire: true, 2925 wantAfterIndex: 4, 2926 wantAfterResLen: 1, 2927 // Should take the optimized path where we only watch the service index 2928 // and the connect index iterator. 2929 wantAfterWatchSetSize: 2, 2930 }, 2931 { 2932 name: "unblocks on subsequent connect-native service registration", 2933 setupFn: func(s *Store) { 2934 testRegisterConnectNativeService(t, s, 4, "node1", "test") 2935 }, 2936 svc: "test", 2937 wantBeforeResLen: 1, 2938 // Should take the optimized path where we only watch the service index 2939 // and the connect index iterator. 2940 wantBeforeWatchSetSize: 2, 2941 updateFn: func(s *Store) { 2942 testRegisterConnectNativeService(t, s, 5, "node2", "test") 2943 }, 2944 shouldFire: true, 2945 wantAfterIndex: 5, 2946 wantAfterResLen: 2, 2947 // Should take the optimized path where we only watch the service index 2948 // and the connect index iterator. 2949 wantAfterWatchSetSize: 2, 2950 }, 2951 { 2952 name: "unblocks on connect-native service de-registration", 2953 setupFn: func(s *Store) { 2954 testRegisterConnectNativeService(t, s, 4, "node1", "test") 2955 testRegisterConnectNativeService(t, s, 5, "node2", "test") 2956 }, 2957 svc: "test", 2958 wantBeforeResLen: 2, 2959 // Should take the optimized path where we only watch the service index 2960 // and the connect index iterator. 2961 wantBeforeWatchSetSize: 2, 2962 updateFn: func(s *Store) { 2963 require.NoError(t, s.DeleteService(6, "node2", "test")) 2964 }, 2965 shouldFire: true, 2966 wantAfterIndex: 6, 2967 wantAfterResLen: 1, 2968 // Should take the optimized path where we only watch the service index 2969 // and the connect index iterator. 2970 wantAfterWatchSetSize: 2, 2971 }, 2972 { 2973 name: "unblocks on last connect-native service de-registration", 2974 setupFn: func(s *Store) { 2975 testRegisterConnectNativeService(t, s, 4, "node1", "test") 2976 }, 2977 svc: "test", 2978 wantBeforeResLen: 1, 2979 // Should take the optimized path where we only watch the service index 2980 // and the connect index iterator. 2981 wantBeforeWatchSetSize: 2, 2982 updateFn: func(s *Store) { 2983 require.NoError(t, s.DeleteService(6, "node1", "test")) 2984 }, 2985 shouldFire: true, 2986 wantAfterIndex: 6, 2987 wantAfterResLen: 0, 2988 // Only the connect index iterator is watched 2989 wantAfterWatchSetSize: 1, 2990 }, 2991 { 2992 name: "unblocks on first proxy service registration", 2993 setupFn: nil, 2994 svc: "test", 2995 wantBeforeResLen: 0, 2996 // Only the connect index iterator is watched 2997 wantBeforeWatchSetSize: 1, 2998 updateFn: func(s *Store) { 2999 testRegisterSidecarProxy(t, s, 4, "node1", "test") 3000 }, 3001 shouldFire: true, 3002 wantAfterIndex: 4, 3003 wantAfterResLen: 1, 3004 // Should take the optimized path where we only watch the service index 3005 // and the connect index iterator. 3006 wantAfterWatchSetSize: 2, 3007 }, 3008 { 3009 name: "unblocks on subsequent proxy service registration", 3010 setupFn: func(s *Store) { 3011 testRegisterSidecarProxy(t, s, 4, "node1", "test") 3012 }, 3013 svc: "test", 3014 wantBeforeResLen: 1, 3015 // Should take the optimized path where we only watch the service index 3016 // and the connect index iterator. 3017 wantBeforeWatchSetSize: 2, 3018 updateFn: func(s *Store) { 3019 testRegisterSidecarProxy(t, s, 5, "node2", "test") 3020 }, 3021 shouldFire: true, 3022 wantAfterIndex: 5, 3023 wantAfterResLen: 2, 3024 // Should take the optimized path where we only watch the service index 3025 // and the connect index iterator. 3026 wantAfterWatchSetSize: 2, 3027 }, 3028 { 3029 name: "unblocks on proxy service de-registration", 3030 setupFn: func(s *Store) { 3031 testRegisterSidecarProxy(t, s, 4, "node1", "test") 3032 testRegisterSidecarProxy(t, s, 5, "node2", "test") 3033 }, 3034 svc: "test", 3035 wantBeforeResLen: 2, 3036 // Should take the optimized path where we only watch the service index 3037 // and the connect index iterator. 3038 wantBeforeWatchSetSize: 2, 3039 updateFn: func(s *Store) { 3040 require.NoError(t, s.DeleteService(6, "node2", "test-sidecar-proxy")) 3041 }, 3042 shouldFire: true, 3043 wantAfterIndex: 6, 3044 wantAfterResLen: 1, 3045 // Should take the optimized path where we only watch the service index 3046 // and the connect index iterator. 3047 wantAfterWatchSetSize: 2, 3048 }, 3049 { 3050 name: "unblocks on last proxy service de-registration", 3051 setupFn: func(s *Store) { 3052 testRegisterSidecarProxy(t, s, 4, "node1", "test") 3053 }, 3054 svc: "test", 3055 wantBeforeResLen: 1, 3056 // Should take the optimized path where we only watch the service index 3057 // and the connect index iterator. 3058 wantBeforeWatchSetSize: 2, 3059 updateFn: func(s *Store) { 3060 require.NoError(t, s.DeleteService(6, "node1", "test-sidecar-proxy")) 3061 }, 3062 shouldFire: true, 3063 wantAfterIndex: 6, 3064 wantAfterResLen: 0, 3065 // Only the connect index iterator is watched 3066 wantAfterWatchSetSize: 1, 3067 }, 3068 { 3069 name: "unblocks on connect-native service health check change", 3070 setupFn: func(s *Store) { 3071 testRegisterConnectNativeService(t, s, 4, "node1", "test") 3072 testRegisterCheck(t, s, 6, "node1", "test", "check1", "passing") 3073 }, 3074 svc: "test", 3075 wantBeforeResLen: 1, 3076 // Should take the optimized path where we only watch the service index 3077 // and the connect index iterator. 3078 wantBeforeWatchSetSize: 2, 3079 updateFn: func(s *Store) { 3080 testRegisterCheck(t, s, 7, "node1", "test", "check1", "critical") 3081 }, 3082 shouldFire: true, 3083 wantAfterIndex: 7, 3084 wantAfterResLen: 1, // critical filtering doesn't happen in the state store method. 3085 // Should take the optimized path where we only watch the service index 3086 // and the connect index iterator. 3087 wantAfterWatchSetSize: 2, 3088 }, 3089 { 3090 name: "unblocks on proxy service health check change", 3091 setupFn: func(s *Store) { 3092 testRegisterSidecarProxy(t, s, 4, "node1", "test") 3093 testRegisterCheck(t, s, 6, "node1", "test-sidecar-proxy", "check1", "passing") 3094 }, 3095 svc: "test", 3096 wantBeforeResLen: 1, 3097 // Should take the optimized path where we only watch the service index 3098 // and the connect index iterator. 3099 wantBeforeWatchSetSize: 2, 3100 updateFn: func(s *Store) { 3101 testRegisterCheck(t, s, 7, "node1", "test-sidecar-proxy", "check1", "critical") 3102 }, 3103 shouldFire: true, 3104 wantAfterIndex: 7, 3105 wantAfterResLen: 1, // critical filtering doesn't happen in the state store method. 3106 // Should take the optimized path where we only watch the service index 3107 // and the connect index iterator. 3108 wantAfterWatchSetSize: 2, 3109 }, 3110 { 3111 name: "unblocks on connect-native node health check change", 3112 setupFn: func(s *Store) { 3113 testRegisterConnectNativeService(t, s, 4, "node1", "test") 3114 testRegisterCheck(t, s, 6, "node1", "", "check1", "passing") 3115 }, 3116 svc: "test", 3117 wantBeforeResLen: 1, 3118 // Should take the optimized path where we only watch the service index 3119 // and the connect index iterator. 3120 wantBeforeWatchSetSize: 2, 3121 updateFn: func(s *Store) { 3122 testRegisterCheck(t, s, 7, "node1", "", "check1", "critical") 3123 }, 3124 shouldFire: true, 3125 wantAfterIndex: 7, 3126 wantAfterResLen: 1, // critical filtering doesn't happen in the state store method. 3127 // Should take the optimized path where we only watch the service index 3128 // and the connect index iterator. 3129 wantAfterWatchSetSize: 2, 3130 }, 3131 { 3132 name: "unblocks on proxy service health check change", 3133 setupFn: func(s *Store) { 3134 testRegisterSidecarProxy(t, s, 4, "node1", "test") 3135 testRegisterCheck(t, s, 6, "node1", "", "check1", "passing") 3136 }, 3137 svc: "test", 3138 wantBeforeResLen: 1, 3139 // Should take the optimized path where we only watch the service index 3140 // and the connect index iterator. 3141 wantBeforeWatchSetSize: 2, 3142 updateFn: func(s *Store) { 3143 testRegisterCheck(t, s, 7, "node1", "", "check1", "critical") 3144 }, 3145 shouldFire: true, 3146 wantAfterIndex: 7, 3147 wantAfterResLen: 1, // critical filtering doesn't happen in the state store method. 3148 // Should take the optimized path where we only watch the service index 3149 // and the connect index iterator. 3150 wantAfterWatchSetSize: 2, 3151 }, 3152 { 3153 // See https://github.com/hashicorp/consul/issues/5506. The issue is cause 3154 // if the target service exists and is registered meaning it has a 3155 // service-specific index. This index is then used for the connect query 3156 // even though it is not updated by changes to the actual proxy or it's 3157 // checks. If the target service was never registered then it all appears 3158 // to work because the code would not find a service index and so fall 3159 // back to using the global service index which does change on any update 3160 // to proxies. 3161 name: "unblocks on proxy service health check change with target service present", 3162 setupFn: func(s *Store) { 3163 testRegisterService(t, s, 4, "node1", "test") // normal service 3164 testRegisterSidecarProxy(t, s, 5, "node1", "test") 3165 testRegisterCheck(t, s, 6, "node1", "test-sidecar-proxy", "check1", "passing") 3166 }, 3167 svc: "test", 3168 wantBeforeResLen: 1, 3169 // Should take the optimized path where we only watch the service index 3170 // and the connect index iterator. 3171 wantBeforeWatchSetSize: 2, 3172 updateFn: func(s *Store) { 3173 testRegisterCheck(t, s, 7, "node1", "test-sidecar-proxy", "check1", "critical") 3174 }, 3175 shouldFire: true, 3176 wantAfterIndex: 7, 3177 wantAfterResLen: 1, // critical filtering doesn't happen in the state store method. 3178 // Should take the optimized path where we only watch the service index 3179 // and the connect index iterator. 3180 wantAfterWatchSetSize: 2, 3181 }, 3182 { 3183 // See https://github.com/hashicorp/consul/issues/5506. This is the edge 3184 // case that the simple solution wouldn't catch. 3185 name: "unblocks on different service name proxy-service registration when service is present", 3186 setupFn: func(s *Store) { 3187 testRegisterSidecarProxy(t, s, 4, "node1", "test") 3188 }, 3189 svc: "test", 3190 wantBeforeResLen: 1, 3191 // Should take the optimized path where we only watch the service index 3192 // and the connect index iterator. 3193 wantBeforeWatchSetSize: 2, 3194 updateFn: func(s *Store) { 3195 // Register a new result with a different service name could be another 3196 // proxy with a different name, but a native instance works too. 3197 testRegisterConnectNativeService(t, s, 5, "node2", "test") 3198 }, 3199 shouldFire: true, 3200 wantAfterIndex: 5, 3201 wantAfterResLen: 2, 3202 // Should take the optimized path where we only watch the teo service 3203 // indexes and the connect index iterator. 3204 wantAfterWatchSetSize: 3, 3205 }, 3206 } 3207 3208 for _, tt := range tests { 3209 t.Run(tt.name, func(t *testing.T) { 3210 s := testStateStore(t) 3211 3212 // Always create 3 nodes 3213 testRegisterNode(t, s, 1, "node1") 3214 testRegisterNode(t, s, 2, "node2") 3215 testRegisterNode(t, s, 3, "node3") 3216 3217 // Setup 3218 if tt.setupFn != nil { 3219 tt.setupFn(s) 3220 } 3221 3222 require := require.New(t) 3223 3224 // Run the query 3225 ws := memdb.NewWatchSet() 3226 idx, res, err := s.CheckConnectServiceNodes(ws, tt.svc) 3227 require.NoError(err) 3228 require.Len(res, tt.wantBeforeResLen) 3229 require.Len(ws, tt.wantBeforeWatchSetSize) 3230 3231 // Mutate the state store 3232 if tt.updateFn != nil { 3233 tt.updateFn(s) 3234 } 3235 3236 fired := watchFired(ws) 3237 if tt.shouldFire { 3238 require.True(fired, "WatchSet should have fired") 3239 } else { 3240 require.False(fired, "WatchSet should not have fired") 3241 } 3242 3243 // Re-query the same result. Should return the desired index and len 3244 ws = memdb.NewWatchSet() 3245 idx, res, err = s.CheckConnectServiceNodes(ws, tt.svc) 3246 require.NoError(err) 3247 require.Len(res, tt.wantAfterResLen) 3248 require.Equal(tt.wantAfterIndex, idx) 3249 require.Len(ws, tt.wantAfterWatchSetSize) 3250 }) 3251 } 3252 } 3253 3254 func TestStateStore_CheckServiceNodes(t *testing.T) { 3255 s := testStateStore(t) 3256 3257 // Querying with no matches gives an empty response 3258 ws := memdb.NewWatchSet() 3259 idx, res, err := s.CheckServiceNodes(ws, "service1") 3260 if idx != 0 || res != nil || err != nil { 3261 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, res, err) 3262 } 3263 3264 // Register some nodes. 3265 testRegisterNode(t, s, 0, "node1") 3266 testRegisterNode(t, s, 1, "node2") 3267 3268 // Register node-level checks. These should be the final result. 3269 testRegisterCheck(t, s, 2, "node1", "", "check1", api.HealthPassing) 3270 testRegisterCheck(t, s, 3, "node2", "", "check2", api.HealthPassing) 3271 3272 // Register a service against the nodes. 3273 testRegisterService(t, s, 4, "node1", "service1") 3274 testRegisterService(t, s, 5, "node2", "service2") 3275 3276 // Register checks against the services. 3277 testRegisterCheck(t, s, 6, "node1", "service1", "check3", api.HealthPassing) 3278 testRegisterCheck(t, s, 7, "node2", "service2", "check4", api.HealthPassing) 3279 3280 // At this point all the changes should have fired the watch. 3281 if !watchFired(ws) { 3282 t.Fatalf("bad") 3283 } 3284 3285 // We ensure the idx for service2 has not been changed 3286 ensureServiceVersion(t, s, ws, "service2", 7, 1) 3287 3288 // Query the state store for nodes and checks which have been registered 3289 // with a specific service. 3290 ws = memdb.NewWatchSet() 3291 ensureServiceVersion(t, s, ws, "service1", 6, 1) 3292 idx, results, err := s.CheckServiceNodes(ws, "service1") 3293 if err != nil { 3294 t.Fatalf("err: %s", err) 3295 } 3296 // registered with ensureServiceVersion(t, s, ws, "service1", 6, 1) 3297 if idx != 6 { 3298 t.Fatalf("bad index: %d", idx) 3299 } 3300 3301 // Make sure we get the expected result (service check + node check). 3302 if n := len(results); n != 1 { 3303 t.Fatalf("expected 1 result, got: %d", n) 3304 } 3305 csn := results[0] 3306 if csn.Node == nil || csn.Service == nil || len(csn.Checks) != 2 || 3307 csn.Checks[0].ServiceID != "" || csn.Checks[0].CheckID != "check1" || 3308 csn.Checks[1].ServiceID != "service1" || csn.Checks[1].CheckID != "check3" { 3309 t.Fatalf("bad output: %#v", csn) 3310 } 3311 3312 // Node updates alter the returned index and fire the watch. 3313 testRegisterNodeWithChange(t, s, 8, "node1") 3314 if !watchFired(ws) { 3315 t.Fatalf("bad") 3316 } 3317 ws = memdb.NewWatchSet() 3318 idx, results, err = s.CheckServiceNodes(ws, "service1") 3319 if err != nil { 3320 t.Fatalf("err: %s", err) 3321 } 3322 // service1 has been updated by node on idx 8 3323 if idx != 8 { 3324 t.Fatalf("bad index: %d", idx) 3325 } 3326 3327 // Service updates alter the returned index and fire the watch. 3328 3329 testRegisterServiceWithChange(t, s, 9, "node1", "service1", true) 3330 if !watchFired(ws) { 3331 t.Fatalf("bad") 3332 } 3333 ws = memdb.NewWatchSet() 3334 idx, results, err = s.CheckServiceNodes(ws, "service1") 3335 if err != nil { 3336 t.Fatalf("err: %s", err) 3337 } 3338 if idx != 9 { 3339 t.Fatalf("bad index: %d", idx) 3340 } 3341 3342 // Check updates alter the returned index and fire the watch. 3343 testRegisterCheck(t, s, 10, "node1", "service1", "check1", api.HealthCritical) 3344 if !watchFired(ws) { 3345 t.Fatalf("bad") 3346 } 3347 ws = memdb.NewWatchSet() 3348 idx, results, err = s.CheckServiceNodes(ws, "service1") 3349 if err != nil { 3350 t.Fatalf("err: %s", err) 3351 } 3352 if idx != 10 { 3353 t.Fatalf("bad index: %d", idx) 3354 } 3355 3356 // Registering some unrelated node + service should not fire the watch. 3357 testRegisterNode(t, s, 11, "nope") 3358 testRegisterService(t, s, 12, "nope", "nope") 3359 if watchFired(ws) { 3360 t.Fatalf("bad") 3361 } 3362 3363 // Note that we can't overwhelm chan tracking any more since we optimized it 3364 // to only need to watch one chan in the happy path. The only path that does 3365 // bees to watch more stuff is where there are no service instances which also 3366 // means fewer than watchLimit chans too so effectively no way to trigger 3367 // Fallback watch any more. 3368 } 3369 3370 func TestStateStore_CheckConnectServiceNodes(t *testing.T) { 3371 assert := assert.New(t) 3372 s := testStateStore(t) 3373 3374 // Listing with no results returns an empty list. 3375 ws := memdb.NewWatchSet() 3376 idx, nodes, err := s.CheckConnectServiceNodes(ws, "db") 3377 assert.Nil(err) 3378 assert.Equal(idx, uint64(0)) 3379 assert.Len(nodes, 0) 3380 3381 // Create some nodes and services. 3382 assert.Nil(s.EnsureNode(10, &structs.Node{Node: "foo", Address: "127.0.0.1"})) 3383 assert.Nil(s.EnsureNode(11, &structs.Node{Node: "bar", Address: "127.0.0.2"})) 3384 assert.Nil(s.EnsureService(12, "foo", &structs.NodeService{ID: "db", Service: "db", Tags: nil, Address: "", Port: 5000})) 3385 assert.Nil(s.EnsureService(13, "bar", &structs.NodeService{ID: "api", Service: "api", Tags: nil, Address: "", Port: 5000})) 3386 assert.Nil(s.EnsureService(14, "foo", &structs.NodeService{Kind: structs.ServiceKindConnectProxy, ID: "proxy", Service: "proxy", Proxy: structs.ConnectProxyConfig{DestinationServiceName: "db"}, Port: 8000})) 3387 assert.Nil(s.EnsureService(15, "bar", &structs.NodeService{Kind: structs.ServiceKindConnectProxy, ID: "proxy", Service: "proxy", Proxy: structs.ConnectProxyConfig{DestinationServiceName: "db"}, Port: 8000})) 3388 assert.Nil(s.EnsureService(16, "bar", &structs.NodeService{ID: "db2", Service: "db", Tags: []string{"slave"}, Address: "", Port: 8001})) 3389 assert.True(watchFired(ws)) 3390 3391 // Register node checks 3392 testRegisterCheck(t, s, 17, "foo", "", "check1", api.HealthPassing) 3393 testRegisterCheck(t, s, 18, "bar", "", "check2", api.HealthPassing) 3394 3395 // Register checks against the services. 3396 testRegisterCheck(t, s, 19, "foo", "db", "check3", api.HealthPassing) 3397 testRegisterCheck(t, s, 20, "bar", "proxy", "check4", api.HealthPassing) 3398 3399 // Read everything back. 3400 ws = memdb.NewWatchSet() 3401 idx, nodes, err = s.CheckConnectServiceNodes(ws, "db") 3402 assert.Nil(err) 3403 assert.Equal(idx, uint64(idx)) 3404 assert.Len(nodes, 2) 3405 3406 for _, n := range nodes { 3407 assert.Equal(structs.ServiceKindConnectProxy, n.Service.Kind) 3408 assert.Equal("db", n.Service.Proxy.DestinationServiceName) 3409 } 3410 } 3411 3412 func BenchmarkCheckServiceNodes(b *testing.B) { 3413 s, err := NewStateStore(nil) 3414 if err != nil { 3415 b.Fatalf("err: %s", err) 3416 } 3417 3418 if err := s.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil { 3419 b.Fatalf("err: %v", err) 3420 } 3421 if err := s.EnsureService(2, "foo", &structs.NodeService{ID: "db1", Service: "db", Tags: []string{"master"}, Address: "", Port: 8000}); err != nil { 3422 b.Fatalf("err: %v", err) 3423 } 3424 check := &structs.HealthCheck{ 3425 Node: "foo", 3426 CheckID: "db", 3427 Name: "can connect", 3428 Status: api.HealthPassing, 3429 ServiceID: "db1", 3430 } 3431 if err := s.EnsureCheck(3, check); err != nil { 3432 b.Fatalf("err: %v", err) 3433 } 3434 check = &structs.HealthCheck{ 3435 Node: "foo", 3436 CheckID: "check1", 3437 Name: "check1", 3438 Status: api.HealthPassing, 3439 } 3440 if err := s.EnsureCheck(4, check); err != nil { 3441 b.Fatalf("err: %v", err) 3442 } 3443 3444 ws := memdb.NewWatchSet() 3445 for i := 0; i < b.N; i++ { 3446 s.CheckServiceNodes(ws, "db") 3447 } 3448 } 3449 3450 func TestStateStore_CheckServiceTagNodes(t *testing.T) { 3451 s := testStateStore(t) 3452 3453 if err := s.EnsureNode(1, &structs.Node{Node: "foo", Address: "127.0.0.1"}); err != nil { 3454 t.Fatalf("err: %v", err) 3455 } 3456 if err := s.EnsureService(2, "foo", &structs.NodeService{ID: "db1", Service: "db", Tags: []string{"master"}, Address: "", Port: 8000}); err != nil { 3457 t.Fatalf("err: %v", err) 3458 } 3459 check := &structs.HealthCheck{ 3460 Node: "foo", 3461 CheckID: "db", 3462 Name: "can connect", 3463 Status: api.HealthPassing, 3464 ServiceID: "db1", 3465 } 3466 if err := s.EnsureCheck(3, check); err != nil { 3467 t.Fatalf("err: %v", err) 3468 } 3469 check = &structs.HealthCheck{ 3470 Node: "foo", 3471 CheckID: "check1", 3472 Name: "another check", 3473 Status: api.HealthPassing, 3474 } 3475 if err := s.EnsureCheck(4, check); err != nil { 3476 t.Fatalf("err: %v", err) 3477 } 3478 3479 ws := memdb.NewWatchSet() 3480 idx, nodes, err := s.CheckServiceTagNodes(ws, "db", []string{"master"}) 3481 if err != nil { 3482 t.Fatalf("err: %s", err) 3483 } 3484 if idx != 4 { 3485 t.Fatalf("bad: %v", idx) 3486 } 3487 if len(nodes) != 1 { 3488 t.Fatalf("Bad: %v", nodes) 3489 } 3490 if nodes[0].Node.Node != "foo" { 3491 t.Fatalf("Bad: %v", nodes[0]) 3492 } 3493 if nodes[0].Service.ID != "db1" { 3494 t.Fatalf("Bad: %v", nodes[0]) 3495 } 3496 if len(nodes[0].Checks) != 2 { 3497 t.Fatalf("Bad: %v", nodes[0]) 3498 } 3499 if nodes[0].Checks[0].CheckID != "check1" { 3500 t.Fatalf("Bad: %v", nodes[0]) 3501 } 3502 if nodes[0].Checks[1].CheckID != "db" { 3503 t.Fatalf("Bad: %v", nodes[0]) 3504 } 3505 3506 // Changing a tag should fire the watch. 3507 if err := s.EnsureService(4, "foo", &structs.NodeService{ID: "db1", Service: "db", Tags: []string{"nope"}, Address: "", Port: 8000}); err != nil { 3508 t.Fatalf("err: %v", err) 3509 } 3510 if !watchFired(ws) { 3511 t.Fatalf("bad") 3512 } 3513 } 3514 3515 func TestStateStore_Check_Snapshot(t *testing.T) { 3516 s := testStateStore(t) 3517 3518 // Create a node, a service, and a service check as well as a node check. 3519 testRegisterNode(t, s, 0, "node1") 3520 testRegisterService(t, s, 1, "node1", "service1") 3521 checks := structs.HealthChecks{ 3522 &structs.HealthCheck{ 3523 Node: "node1", 3524 CheckID: "check1", 3525 Name: "node check", 3526 Status: api.HealthPassing, 3527 }, 3528 &structs.HealthCheck{ 3529 Node: "node1", 3530 CheckID: "check2", 3531 Name: "service check", 3532 Status: api.HealthCritical, 3533 ServiceID: "service1", 3534 }, 3535 } 3536 for i, hc := range checks { 3537 if err := s.EnsureCheck(uint64(i+1), hc); err != nil { 3538 t.Fatalf("err: %s", err) 3539 } 3540 } 3541 3542 // Create a second node/service to make sure node filtering works. This 3543 // will affect the index but not the dump. 3544 testRegisterNode(t, s, 3, "node2") 3545 testRegisterService(t, s, 4, "node2", "service2") 3546 testRegisterCheck(t, s, 5, "node2", "service2", "check3", api.HealthPassing) 3547 3548 // Snapshot the checks. 3549 snap := s.Snapshot() 3550 defer snap.Close() 3551 3552 // Alter the real state store. 3553 testRegisterCheck(t, s, 6, "node2", "service2", "check4", api.HealthPassing) 3554 3555 // Verify the snapshot. 3556 if idx := snap.LastIndex(); idx != 5 { 3557 t.Fatalf("bad index: %d", idx) 3558 } 3559 iter, err := snap.Checks("node1") 3560 if err != nil { 3561 t.Fatalf("err: %s", err) 3562 } 3563 for i := 0; i < len(checks); i++ { 3564 check := iter.Next().(*structs.HealthCheck) 3565 if check == nil { 3566 t.Fatalf("unexpected end of checks") 3567 } 3568 3569 checks[i].CreateIndex, checks[i].ModifyIndex = uint64(i+1), uint64(i+1) 3570 if !reflect.DeepEqual(check, checks[i]) { 3571 t.Fatalf("bad: %#v != %#v", check, checks[i]) 3572 } 3573 } 3574 if iter.Next() != nil { 3575 t.Fatalf("unexpected extra checks") 3576 } 3577 } 3578 3579 func TestStateStore_NodeInfo_NodeDump(t *testing.T) { 3580 s := testStateStore(t) 3581 3582 // Generating a node dump that matches nothing returns empty 3583 wsInfo := memdb.NewWatchSet() 3584 idx, dump, err := s.NodeInfo(wsInfo, "node1") 3585 if idx != 0 || dump != nil || err != nil { 3586 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, dump, err) 3587 } 3588 wsDump := memdb.NewWatchSet() 3589 idx, dump, err = s.NodeDump(wsDump) 3590 if idx != 0 || dump != nil || err != nil { 3591 t.Fatalf("expected (0, nil, nil), got: (%d, %#v, %#v)", idx, dump, err) 3592 } 3593 3594 // Register some nodes 3595 testRegisterNode(t, s, 0, "node1") 3596 testRegisterNode(t, s, 1, "node2") 3597 3598 // Register services against them 3599 testRegisterService(t, s, 2, "node1", "service1") 3600 testRegisterService(t, s, 3, "node1", "service2") 3601 testRegisterService(t, s, 4, "node2", "service1") 3602 testRegisterService(t, s, 5, "node2", "service2") 3603 3604 // Register service-level checks 3605 testRegisterCheck(t, s, 6, "node1", "service1", "check1", api.HealthPassing) 3606 testRegisterCheck(t, s, 7, "node2", "service1", "check1", api.HealthPassing) 3607 3608 // Register node-level checks 3609 testRegisterCheck(t, s, 8, "node1", "", "check2", api.HealthPassing) 3610 testRegisterCheck(t, s, 9, "node2", "", "check2", api.HealthPassing) 3611 3612 // Both watches should have fired due to the changes above. 3613 if !watchFired(wsInfo) { 3614 t.Fatalf("bad") 3615 } 3616 if !watchFired(wsDump) { 3617 t.Fatalf("bad") 3618 } 3619 3620 // Check that our result matches what we expect. 3621 expect := structs.NodeDump{ 3622 &structs.NodeInfo{ 3623 Node: "node1", 3624 Checks: structs.HealthChecks{ 3625 &structs.HealthCheck{ 3626 Node: "node1", 3627 CheckID: "check1", 3628 ServiceID: "service1", 3629 ServiceName: "service1", 3630 Status: api.HealthPassing, 3631 RaftIndex: structs.RaftIndex{ 3632 CreateIndex: 6, 3633 ModifyIndex: 6, 3634 }, 3635 }, 3636 &structs.HealthCheck{ 3637 Node: "node1", 3638 CheckID: "check2", 3639 ServiceID: "", 3640 ServiceName: "", 3641 Status: api.HealthPassing, 3642 RaftIndex: structs.RaftIndex{ 3643 CreateIndex: 8, 3644 ModifyIndex: 8, 3645 }, 3646 }, 3647 }, 3648 Services: []*structs.NodeService{ 3649 &structs.NodeService{ 3650 ID: "service1", 3651 Service: "service1", 3652 Address: "1.1.1.1", 3653 Meta: make(map[string]string), 3654 Port: 1111, 3655 Weights: &structs.Weights{Passing: 1, Warning: 1}, 3656 RaftIndex: structs.RaftIndex{ 3657 CreateIndex: 2, 3658 ModifyIndex: 2, 3659 }, 3660 }, 3661 &structs.NodeService{ 3662 ID: "service2", 3663 Service: "service2", 3664 Address: "1.1.1.1", 3665 Meta: make(map[string]string), 3666 Port: 1111, 3667 Weights: &structs.Weights{Passing: 1, Warning: 1}, 3668 RaftIndex: structs.RaftIndex{ 3669 CreateIndex: 3, 3670 ModifyIndex: 3, 3671 }, 3672 }, 3673 }, 3674 }, 3675 &structs.NodeInfo{ 3676 Node: "node2", 3677 Checks: structs.HealthChecks{ 3678 &structs.HealthCheck{ 3679 Node: "node2", 3680 CheckID: "check1", 3681 ServiceID: "service1", 3682 ServiceName: "service1", 3683 Status: api.HealthPassing, 3684 RaftIndex: structs.RaftIndex{ 3685 CreateIndex: 7, 3686 ModifyIndex: 7, 3687 }, 3688 }, 3689 &structs.HealthCheck{ 3690 Node: "node2", 3691 CheckID: "check2", 3692 ServiceID: "", 3693 ServiceName: "", 3694 Status: api.HealthPassing, 3695 RaftIndex: structs.RaftIndex{ 3696 CreateIndex: 9, 3697 ModifyIndex: 9, 3698 }, 3699 }, 3700 }, 3701 Services: []*structs.NodeService{ 3702 &structs.NodeService{ 3703 ID: "service1", 3704 Service: "service1", 3705 Address: "1.1.1.1", 3706 Port: 1111, 3707 Meta: make(map[string]string), 3708 Weights: &structs.Weights{Passing: 1, Warning: 1}, 3709 RaftIndex: structs.RaftIndex{ 3710 CreateIndex: 4, 3711 ModifyIndex: 4, 3712 }, 3713 }, 3714 &structs.NodeService{ 3715 ID: "service2", 3716 Service: "service2", 3717 Address: "1.1.1.1", 3718 Port: 1111, 3719 Meta: make(map[string]string), 3720 Weights: &structs.Weights{Passing: 1, Warning: 1}, 3721 RaftIndex: structs.RaftIndex{ 3722 CreateIndex: 5, 3723 ModifyIndex: 5, 3724 }, 3725 }, 3726 }, 3727 }, 3728 } 3729 3730 // Get a dump of just a single node 3731 ws := memdb.NewWatchSet() 3732 idx, dump, err = s.NodeInfo(ws, "node1") 3733 if err != nil { 3734 t.Fatalf("err: %s", err) 3735 } 3736 if idx != 9 { 3737 t.Fatalf("bad index: %d", idx) 3738 } 3739 if len(dump) != 1 || !reflect.DeepEqual(dump[0], expect[0]) { 3740 t.Fatalf("bad: len=%#v dump=%#v expect=%#v", len(dump), dump[0], expect[0]) 3741 } 3742 3743 // Generate a dump of all the nodes 3744 idx, dump, err = s.NodeDump(nil) 3745 if err != nil { 3746 t.Fatalf("err: %s", err) 3747 } 3748 if idx != 9 { 3749 t.Fatalf("bad index: %d", 9) 3750 } 3751 if !reflect.DeepEqual(dump, expect) { 3752 t.Fatalf("bad: %#v", dump[0].Services[0]) 3753 } 3754 3755 // Registering some unrelated node + service + check should not fire the 3756 // watch. 3757 testRegisterNode(t, s, 10, "nope") 3758 testRegisterService(t, s, 11, "nope", "nope") 3759 if watchFired(ws) { 3760 t.Fatalf("bad") 3761 } 3762 } 3763 3764 func TestStateStore_ServiceIdxUpdateOnNodeUpdate(t *testing.T) { 3765 s := testStateStore(t) 3766 3767 // Create a service on a node 3768 err := s.EnsureNode(10, &structs.Node{Node: "node", Address: "127.0.0.1"}) 3769 require.Nil(t, err) 3770 err = s.EnsureService(12, "node", &structs.NodeService{ID: "srv", Service: "srv", Tags: nil, Address: "", Port: 5000}) 3771 require.Nil(t, err) 3772 3773 // Store the current service index 3774 ws := memdb.NewWatchSet() 3775 lastIdx, _, err := s.ServiceNodes(ws, "srv") 3776 require.Nil(t, err) 3777 3778 // Update the node with some meta 3779 err = s.EnsureNode(14, &structs.Node{Node: "node", Address: "127.0.0.1", Meta: map[string]string{"foo": "bar"}}) 3780 require.Nil(t, err) 3781 3782 // Read the new service index 3783 ws = memdb.NewWatchSet() 3784 newIdx, _, err := s.ServiceNodes(ws, "srv") 3785 require.Nil(t, err) 3786 3787 require.True(t, newIdx > lastIdx) 3788 }