github.com/outbrain/consul@v1.4.5/agent/catalog_endpoint_test.go (about) 1 package agent 2 3 import ( 4 "fmt" 5 "net/http" 6 "net/http/httptest" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/consul/agent/structs" 11 "github.com/hashicorp/consul/testrpc" 12 "github.com/hashicorp/consul/testutil/retry" 13 "github.com/hashicorp/serf/coordinate" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 ) 17 18 func TestCatalogRegister_Service_InvalidAddress(t *testing.T) { 19 t.Parallel() 20 a := NewTestAgent(t, t.Name(), "") 21 defer a.Shutdown() 22 23 for _, addr := range []string{"0.0.0.0", "::", "[::]"} { 24 t.Run("addr "+addr, func(t *testing.T) { 25 args := &structs.RegisterRequest{ 26 Node: "foo", 27 Address: "127.0.0.1", 28 Service: &structs.NodeService{ 29 Service: "test", 30 Address: addr, 31 Port: 8080, 32 }, 33 } 34 req, _ := http.NewRequest("PUT", "/v1/catalog/register", jsonReader(args)) 35 _, err := a.srv.CatalogRegister(nil, req) 36 if err == nil || err.Error() != "Invalid service address" { 37 t.Fatalf("err: %v", err) 38 } 39 }) 40 } 41 } 42 43 func TestCatalogDeregister(t *testing.T) { 44 t.Parallel() 45 a := NewTestAgent(t, t.Name(), "") 46 defer a.Shutdown() 47 48 // Register node 49 args := &structs.DeregisterRequest{Node: "foo"} 50 req, _ := http.NewRequest("PUT", "/v1/catalog/deregister", jsonReader(args)) 51 obj, err := a.srv.CatalogDeregister(nil, req) 52 if err != nil { 53 t.Fatalf("err: %v", err) 54 } 55 56 res := obj.(bool) 57 if res != true { 58 t.Fatalf("bad: %v", res) 59 } 60 } 61 62 func TestCatalogDatacenters(t *testing.T) { 63 t.Parallel() 64 a := NewTestAgent(t, t.Name(), "") 65 defer a.Shutdown() 66 67 retry.Run(t, func(r *retry.R) { 68 req, _ := http.NewRequest("GET", "/v1/catalog/datacenters", nil) 69 obj, err := a.srv.CatalogDatacenters(nil, req) 70 if err != nil { 71 r.Fatal(err) 72 } 73 74 dcs := obj.([]string) 75 if got, want := len(dcs), 1; got != want { 76 r.Fatalf("got %d data centers want %d", got, want) 77 } 78 }) 79 } 80 81 func TestCatalogNodes(t *testing.T) { 82 t.Parallel() 83 a := NewTestAgent(t, t.Name(), "") 84 defer a.Shutdown() 85 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 86 87 // Register node 88 args := &structs.RegisterRequest{ 89 Datacenter: "dc1", 90 Node: "foo", 91 Address: "127.0.0.1", 92 } 93 94 var out struct{} 95 if err := a.RPC("Catalog.Register", args, &out); err != nil { 96 t.Fatalf("err: %v", err) 97 } 98 99 req, _ := http.NewRequest("GET", "/v1/catalog/nodes?dc=dc1", nil) 100 resp := httptest.NewRecorder() 101 obj, err := a.srv.CatalogNodes(resp, req) 102 if err != nil { 103 t.Fatalf("err: %v", err) 104 } 105 106 // Verify an index is set 107 assertIndex(t, resp) 108 109 nodes := obj.(structs.Nodes) 110 if len(nodes) != 2 { 111 t.Fatalf("bad: %v ; nodes:=%v", obj, nodes) 112 } 113 } 114 115 func TestCatalogNodes_MetaFilter(t *testing.T) { 116 t.Parallel() 117 a := NewTestAgent(t, t.Name(), "") 118 defer a.Shutdown() 119 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 120 121 // Register a node with a meta field 122 args := &structs.RegisterRequest{ 123 Datacenter: "dc1", 124 Node: "foo", 125 Address: "127.0.0.1", 126 NodeMeta: map[string]string{ 127 "somekey": "somevalue", 128 }, 129 } 130 131 var out struct{} 132 if err := a.RPC("Catalog.Register", args, &out); err != nil { 133 t.Fatalf("err: %v", err) 134 } 135 136 req, _ := http.NewRequest("GET", "/v1/catalog/nodes?node-meta=somekey:somevalue", nil) 137 resp := httptest.NewRecorder() 138 obj, err := a.srv.CatalogNodes(resp, req) 139 if err != nil { 140 t.Fatalf("err: %v", err) 141 } 142 143 // Verify an index is set 144 assertIndex(t, resp) 145 146 // Verify we only get the node with the correct meta field back 147 nodes := obj.(structs.Nodes) 148 if len(nodes) != 1 { 149 t.Fatalf("bad: %v", obj) 150 } 151 if v, ok := nodes[0].Meta["somekey"]; !ok || v != "somevalue" { 152 t.Fatalf("bad: %v", nodes[0].Meta) 153 } 154 } 155 156 func TestCatalogNodes_WanTranslation(t *testing.T) { 157 t.Parallel() 158 a1 := NewTestAgent(t, t.Name(), ` 159 datacenter = "dc1" 160 translate_wan_addrs = true 161 acl_datacenter = "" 162 `) 163 defer a1.Shutdown() 164 testrpc.WaitForTestAgent(t, a1.RPC, "dc1") 165 166 a2 := NewTestAgent(t, t.Name(), ` 167 datacenter = "dc2" 168 translate_wan_addrs = true 169 acl_datacenter = "" 170 `) 171 defer a2.Shutdown() 172 testrpc.WaitForTestAgent(t, a2.RPC, "dc2") 173 174 // Wait for the WAN join. 175 addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN) 176 if _, err := a2.JoinWAN([]string{addr}); err != nil { 177 t.Fatalf("err: %v", err) 178 } 179 testrpc.WaitForLeader(t, a1.RPC, "dc1") 180 testrpc.WaitForLeader(t, a2.RPC, "dc2") 181 retry.Run(t, func(r *retry.R) { 182 if got, want := len(a1.WANMembers()), 2; got < want { 183 r.Fatalf("got %d WAN members want at least %d", got, want) 184 } 185 }) 186 187 // Register a node with DC2. 188 { 189 args := &structs.RegisterRequest{ 190 Datacenter: "dc2", 191 Node: "wan_translation_test", 192 Address: "127.0.0.1", 193 TaggedAddresses: map[string]string{ 194 "wan": "127.0.0.2", 195 }, 196 Service: &structs.NodeService{ 197 Service: "http_wan_translation_test", 198 }, 199 } 200 201 var out struct{} 202 if err := a2.RPC("Catalog.Register", args, &out); err != nil { 203 t.Fatalf("err: %v", err) 204 } 205 } 206 207 // Query nodes in DC2 from DC1. 208 req, _ := http.NewRequest("GET", "/v1/catalog/nodes?dc=dc2", nil) 209 resp1 := httptest.NewRecorder() 210 obj1, err1 := a1.srv.CatalogNodes(resp1, req) 211 if err1 != nil { 212 t.Fatalf("err: %v", err1) 213 } 214 assertIndex(t, resp1) 215 216 // Expect that DC1 gives us a WAN address (since the node is in DC2). 217 nodes1 := obj1.(structs.Nodes) 218 if len(nodes1) != 2 { 219 t.Fatalf("bad: %v, nodes:=%v", obj1, nodes1) 220 } 221 var address string 222 for _, node := range nodes1 { 223 if node.Node == "wan_translation_test" { 224 address = node.Address 225 } 226 } 227 if address != "127.0.0.2" { 228 t.Fatalf("bad: %s", address) 229 } 230 231 // Query DC2 from DC2. 232 resp2 := httptest.NewRecorder() 233 obj2, err2 := a2.srv.CatalogNodes(resp2, req) 234 if err2 != nil { 235 t.Fatalf("err: %v", err2) 236 } 237 assertIndex(t, resp2) 238 239 // Expect that DC2 gives us a private address (since the node is in DC2). 240 nodes2 := obj2.(structs.Nodes) 241 if len(nodes2) != 2 { 242 t.Fatalf("bad: %v", obj2) 243 } 244 for _, node := range nodes2 { 245 if node.Node == "wan_translation_test" { 246 address = node.Address 247 } 248 } 249 if address != "127.0.0.1" { 250 t.Fatalf("bad: %s", address) 251 } 252 } 253 254 func TestCatalogNodes_Blocking(t *testing.T) { 255 t.Parallel() 256 a := NewTestAgent(t, t.Name(), "") 257 defer a.Shutdown() 258 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 259 260 // Register node 261 args := &structs.DCSpecificRequest{ 262 Datacenter: "dc1", 263 } 264 265 var out structs.IndexedNodes 266 if err := a.RPC("Catalog.ListNodes", *args, &out); err != nil { 267 t.Fatalf("err: %v", err) 268 } 269 270 // t.Fatal must be called from the main go routine 271 // of the test. Because of this we cannot call 272 // t.Fatal from within the go routines and use 273 // an error channel instead. 274 errch := make(chan error, 2) 275 go func() { 276 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 277 start := time.Now() 278 279 // register a service after the blocking call 280 // in order to unblock it. 281 time.AfterFunc(100*time.Millisecond, func() { 282 args := &structs.RegisterRequest{ 283 Datacenter: "dc1", 284 Node: "foo", 285 Address: "127.0.0.1", 286 } 287 var out struct{} 288 errch <- a.RPC("Catalog.Register", args, &out) 289 }) 290 291 // now block 292 req, _ := http.NewRequest("GET", fmt.Sprintf("/v1/catalog/nodes?wait=3s&index=%d", out.Index+1), nil) 293 resp := httptest.NewRecorder() 294 obj, err := a.srv.CatalogNodes(resp, req) 295 if err != nil { 296 errch <- err 297 } 298 299 // Should block for a while 300 if d := time.Since(start); d < 50*time.Millisecond { 301 errch <- fmt.Errorf("too fast: %v", d) 302 } 303 304 if idx := getIndex(t, resp); idx <= out.Index { 305 errch <- fmt.Errorf("bad: %v", idx) 306 } 307 308 nodes := obj.(structs.Nodes) 309 if len(nodes) != 2 { 310 errch <- fmt.Errorf("bad: %v", obj) 311 } 312 errch <- nil 313 }() 314 315 // wait for both go routines to return 316 if err := <-errch; err != nil { 317 t.Fatal(err) 318 } 319 if err := <-errch; err != nil { 320 t.Fatal(err) 321 } 322 } 323 324 func TestCatalogNodes_DistanceSort(t *testing.T) { 325 t.Parallel() 326 a := NewTestAgent(t, t.Name(), "") 327 defer a.Shutdown() 328 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 329 330 // Register nodes. 331 args := &structs.RegisterRequest{ 332 Datacenter: "dc1", 333 Node: "foo", 334 Address: "127.0.0.1", 335 } 336 var out struct{} 337 if err := a.RPC("Catalog.Register", args, &out); err != nil { 338 t.Fatalf("err: %v", err) 339 } 340 341 args = &structs.RegisterRequest{ 342 Datacenter: "dc1", 343 Node: "bar", 344 Address: "127.0.0.2", 345 } 346 if err := a.RPC("Catalog.Register", args, &out); err != nil { 347 t.Fatalf("err: %v", err) 348 } 349 350 // Nobody has coordinates set so this will still return them in the 351 // order they are indexed. 352 req, _ := http.NewRequest("GET", "/v1/catalog/nodes?dc=dc1&near=foo", nil) 353 resp := httptest.NewRecorder() 354 obj, err := a.srv.CatalogNodes(resp, req) 355 if err != nil { 356 t.Fatalf("err: %v", err) 357 } 358 359 assertIndex(t, resp) 360 nodes := obj.(structs.Nodes) 361 if len(nodes) != 3 { 362 t.Fatalf("bad: %v", obj) 363 } 364 if nodes[0].Node != "bar" { 365 t.Fatalf("bad: %v", nodes) 366 } 367 if nodes[1].Node != "foo" { 368 t.Fatalf("bad: %v", nodes) 369 } 370 if nodes[2].Node != a.Config.NodeName { 371 t.Fatalf("bad: %v", nodes) 372 } 373 374 // Send an update for the node and wait for it to get applied. 375 arg := structs.CoordinateUpdateRequest{ 376 Datacenter: "dc1", 377 Node: "foo", 378 Coord: coordinate.NewCoordinate(coordinate.DefaultConfig()), 379 } 380 if err := a.RPC("Coordinate.Update", &arg, &out); err != nil { 381 t.Fatalf("err: %v", err) 382 } 383 time.Sleep(300 * time.Millisecond) 384 385 // Query again and now foo should have moved to the front of the line. 386 req, _ = http.NewRequest("GET", "/v1/catalog/nodes?dc=dc1&near=foo", nil) 387 resp = httptest.NewRecorder() 388 obj, err = a.srv.CatalogNodes(resp, req) 389 if err != nil { 390 t.Fatalf("err: %v", err) 391 } 392 393 assertIndex(t, resp) 394 nodes = obj.(structs.Nodes) 395 if len(nodes) != 3 { 396 t.Fatalf("bad: %v", obj) 397 } 398 if nodes[0].Node != "foo" { 399 t.Fatalf("bad: %v", nodes) 400 } 401 if nodes[1].Node != "bar" { 402 t.Fatalf("bad: %v", nodes) 403 } 404 if nodes[2].Node != a.Config.NodeName { 405 t.Fatalf("bad: %v", nodes) 406 } 407 } 408 409 func TestCatalogServices(t *testing.T) { 410 t.Parallel() 411 a := NewTestAgent(t, t.Name(), "") 412 defer a.Shutdown() 413 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 414 415 // Register node 416 args := &structs.RegisterRequest{ 417 Datacenter: "dc1", 418 Node: "foo", 419 Address: "127.0.0.1", 420 Service: &structs.NodeService{ 421 Service: "api", 422 }, 423 } 424 425 var out struct{} 426 if err := a.RPC("Catalog.Register", args, &out); err != nil { 427 t.Fatalf("err: %v", err) 428 } 429 430 req, _ := http.NewRequest("GET", "/v1/catalog/services?dc=dc1", nil) 431 resp := httptest.NewRecorder() 432 obj, err := a.srv.CatalogServices(resp, req) 433 if err != nil { 434 t.Fatalf("err: %v", err) 435 } 436 437 assertIndex(t, resp) 438 439 services := obj.(structs.Services) 440 if len(services) != 2 { 441 t.Fatalf("bad: %v", obj) 442 } 443 } 444 445 func TestCatalogServices_NodeMetaFilter(t *testing.T) { 446 t.Parallel() 447 a := NewTestAgent(t, t.Name(), "") 448 defer a.Shutdown() 449 450 // Register node 451 args := &structs.RegisterRequest{ 452 Datacenter: "dc1", 453 Node: "foo", 454 Address: "127.0.0.1", 455 NodeMeta: map[string]string{ 456 "somekey": "somevalue", 457 }, 458 Service: &structs.NodeService{ 459 Service: "api", 460 }, 461 } 462 463 var out struct{} 464 if err := a.RPC("Catalog.Register", args, &out); err != nil { 465 t.Fatalf("err: %v", err) 466 } 467 468 req, _ := http.NewRequest("GET", "/v1/catalog/services?node-meta=somekey:somevalue", nil) 469 resp := httptest.NewRecorder() 470 obj, err := a.srv.CatalogServices(resp, req) 471 if err != nil { 472 t.Fatalf("err: %v", err) 473 } 474 475 assertIndex(t, resp) 476 477 services := obj.(structs.Services) 478 if len(services) != 1 { 479 t.Fatalf("bad: %v", obj) 480 } 481 if _, ok := services[args.Service.Service]; !ok { 482 t.Fatalf("bad: %v", services) 483 } 484 } 485 486 func TestCatalogServiceNodes(t *testing.T) { 487 t.Parallel() 488 a := NewTestAgent(t, t.Name(), "") 489 defer a.Shutdown() 490 491 assert := assert.New(t) 492 require := require.New(t) 493 494 // Make sure an empty list is returned, not a nil 495 { 496 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?tag=a", nil) 497 resp := httptest.NewRecorder() 498 obj, err := a.srv.CatalogServiceNodes(resp, req) 499 if err != nil { 500 t.Fatalf("err: %v", err) 501 } 502 503 assertIndex(t, resp) 504 505 nodes := obj.(structs.ServiceNodes) 506 if nodes == nil || len(nodes) != 0 { 507 t.Fatalf("bad: %v", obj) 508 } 509 } 510 511 // Register node 512 args := &structs.RegisterRequest{ 513 Datacenter: "dc1", 514 Node: "foo", 515 Address: "127.0.0.1", 516 Service: &structs.NodeService{ 517 Service: "api", 518 Tags: []string{"a"}, 519 }, 520 } 521 522 var out struct{} 523 if err := a.RPC("Catalog.Register", args, &out); err != nil { 524 t.Fatalf("err: %v", err) 525 } 526 527 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?tag=a", nil) 528 resp := httptest.NewRecorder() 529 obj, err := a.srv.CatalogServiceNodes(resp, req) 530 if err != nil { 531 t.Fatalf("err: %v", err) 532 } 533 534 assertIndex(t, resp) 535 536 nodes := obj.(structs.ServiceNodes) 537 if len(nodes) != 1 { 538 t.Fatalf("bad: %v", obj) 539 } 540 541 // Test caching 542 { 543 // List instances with cache enabled 544 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?cached", nil) 545 resp := httptest.NewRecorder() 546 obj, err := a.srv.CatalogServiceNodes(resp, req) 547 require.NoError(err) 548 nodes := obj.(structs.ServiceNodes) 549 assert.Len(nodes, 1) 550 551 // Should be a cache miss 552 assert.Equal("MISS", resp.Header().Get("X-Cache")) 553 } 554 555 { 556 // List instances with cache enabled 557 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?cached", nil) 558 resp := httptest.NewRecorder() 559 obj, err := a.srv.CatalogServiceNodes(resp, req) 560 require.NoError(err) 561 nodes := obj.(structs.ServiceNodes) 562 assert.Len(nodes, 1) 563 564 // Should be a cache HIT now! 565 assert.Equal("HIT", resp.Header().Get("X-Cache")) 566 assert.Equal("0", resp.Header().Get("Age")) 567 } 568 569 // Ensure background refresh works 570 { 571 // Register a new instance of the service 572 args2 := args 573 args2.Node = "bar" 574 args2.Address = "127.0.0.2" 575 require.NoError(a.RPC("Catalog.Register", args, &out)) 576 577 retry.Run(t, func(r *retry.R) { 578 // List it again 579 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?cached", nil) 580 resp := httptest.NewRecorder() 581 obj, err := a.srv.CatalogServiceNodes(resp, req) 582 r.Check(err) 583 584 nodes := obj.(structs.ServiceNodes) 585 if len(nodes) != 2 { 586 r.Fatalf("Want 2 nodes") 587 } 588 589 // Should be a cache hit! The data should've updated in the cache 590 // in the background so this should've been fetched directly from 591 // the cache. 592 if resp.Header().Get("X-Cache") != "HIT" { 593 r.Fatalf("should be a cache hit") 594 } 595 }) 596 } 597 } 598 599 func TestCatalogServiceNodes_NodeMetaFilter(t *testing.T) { 600 t.Parallel() 601 a := NewTestAgent(t, t.Name(), "") 602 defer a.Shutdown() 603 604 // Make sure an empty list is returned, not a nil 605 { 606 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?node-meta=somekey:somevalue", nil) 607 resp := httptest.NewRecorder() 608 obj, err := a.srv.CatalogServiceNodes(resp, req) 609 if err != nil { 610 t.Fatalf("err: %v", err) 611 } 612 613 assertIndex(t, resp) 614 615 nodes := obj.(structs.ServiceNodes) 616 if nodes == nil || len(nodes) != 0 { 617 t.Fatalf("bad: %v", obj) 618 } 619 } 620 621 // Register node 622 args := &structs.RegisterRequest{ 623 Datacenter: "dc1", 624 Node: "foo", 625 Address: "127.0.0.1", 626 NodeMeta: map[string]string{ 627 "somekey": "somevalue", 628 }, 629 Service: &structs.NodeService{ 630 Service: "api", 631 }, 632 } 633 634 var out struct{} 635 if err := a.RPC("Catalog.Register", args, &out); err != nil { 636 t.Fatalf("err: %v", err) 637 } 638 639 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?node-meta=somekey:somevalue", nil) 640 resp := httptest.NewRecorder() 641 obj, err := a.srv.CatalogServiceNodes(resp, req) 642 if err != nil { 643 t.Fatalf("err: %v", err) 644 } 645 646 assertIndex(t, resp) 647 648 nodes := obj.(structs.ServiceNodes) 649 if len(nodes) != 1 { 650 t.Fatalf("bad: %v", obj) 651 } 652 } 653 654 func TestCatalogServiceNodes_WanTranslation(t *testing.T) { 655 t.Parallel() 656 a1 := NewTestAgent(t, t.Name(), ` 657 datacenter = "dc1" 658 translate_wan_addrs = true 659 acl_datacenter = "" 660 `) 661 defer a1.Shutdown() 662 663 a2 := NewTestAgent(t, t.Name(), ` 664 datacenter = "dc2" 665 translate_wan_addrs = true 666 acl_datacenter = "" 667 `) 668 defer a2.Shutdown() 669 670 // Wait for the WAN join. 671 addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN) 672 if _, err := a2.srv.agent.JoinWAN([]string{addr}); err != nil { 673 t.Fatalf("err: %v", err) 674 } 675 retry.Run(t, func(r *retry.R) { 676 if got, want := len(a1.WANMembers()), 2; got < want { 677 r.Fatalf("got %d WAN members want at least %d", got, want) 678 } 679 }) 680 681 // Register a node with DC2. 682 { 683 args := &structs.RegisterRequest{ 684 Datacenter: "dc2", 685 Node: "foo", 686 Address: "127.0.0.1", 687 TaggedAddresses: map[string]string{ 688 "wan": "127.0.0.2", 689 }, 690 Service: &structs.NodeService{ 691 Service: "http_wan_translation_test", 692 }, 693 } 694 695 var out struct{} 696 if err := a2.RPC("Catalog.Register", args, &out); err != nil { 697 t.Fatalf("err: %v", err) 698 } 699 } 700 701 // Query for the node in DC2 from DC1. 702 req, _ := http.NewRequest("GET", "/v1/catalog/service/http_wan_translation_test?dc=dc2", nil) 703 resp1 := httptest.NewRecorder() 704 obj1, err1 := a1.srv.CatalogServiceNodes(resp1, req) 705 if err1 != nil { 706 t.Fatalf("err: %v", err1) 707 } 708 assertIndex(t, resp1) 709 710 // Expect that DC1 gives us a WAN address (since the node is in DC2). 711 nodes1 := obj1.(structs.ServiceNodes) 712 if len(nodes1) != 1 { 713 t.Fatalf("bad: %v", obj1) 714 } 715 node1 := nodes1[0] 716 if node1.Address != "127.0.0.2" { 717 t.Fatalf("bad: %v", node1) 718 } 719 720 // Query DC2 from DC2. 721 resp2 := httptest.NewRecorder() 722 obj2, err2 := a2.srv.CatalogServiceNodes(resp2, req) 723 if err2 != nil { 724 t.Fatalf("err: %v", err2) 725 } 726 assertIndex(t, resp2) 727 728 // Expect that DC2 gives us a local address (since the node is in DC2). 729 nodes2 := obj2.(structs.ServiceNodes) 730 if len(nodes2) != 1 { 731 t.Fatalf("bad: %v", obj2) 732 } 733 node2 := nodes2[0] 734 if node2.Address != "127.0.0.1" { 735 t.Fatalf("bad: %v", node2) 736 } 737 } 738 739 func TestCatalogServiceNodes_DistanceSort(t *testing.T) { 740 t.Parallel() 741 a := NewTestAgent(t, t.Name(), "") 742 defer a.Shutdown() 743 testrpc.WaitForLeader(t, a.RPC, "dc1") 744 745 // Register nodes. 746 args := &structs.RegisterRequest{ 747 Datacenter: "dc1", 748 Node: "bar", 749 Address: "127.0.0.1", 750 Service: &structs.NodeService{ 751 Service: "api", 752 Tags: []string{"a"}, 753 }, 754 } 755 var out struct{} 756 if err := a.RPC("Catalog.Register", args, &out); err != nil { 757 t.Fatalf("err: %v", err) 758 } 759 760 req, _ := http.NewRequest("GET", "/v1/catalog/service/api?tag=a", nil) 761 args = &structs.RegisterRequest{ 762 Datacenter: "dc1", 763 Node: "foo", 764 Address: "127.0.0.2", 765 Service: &structs.NodeService{ 766 Service: "api", 767 Tags: []string{"a"}, 768 }, 769 } 770 if err := a.RPC("Catalog.Register", args, &out); err != nil { 771 t.Fatalf("err: %v", err) 772 } 773 774 // Nobody has coordinates set so this will still return them in the 775 // order they are indexed. 776 req, _ = http.NewRequest("GET", "/v1/catalog/service/api?tag=a&near=foo", nil) 777 resp := httptest.NewRecorder() 778 obj, err := a.srv.CatalogServiceNodes(resp, req) 779 if err != nil { 780 t.Fatalf("err: %v", err) 781 } 782 783 assertIndex(t, resp) 784 nodes := obj.(structs.ServiceNodes) 785 if len(nodes) != 2 { 786 t.Fatalf("bad: %v", obj) 787 } 788 if nodes[0].Node != "bar" { 789 t.Fatalf("bad: %v", nodes) 790 } 791 if nodes[1].Node != "foo" { 792 t.Fatalf("bad: %v", nodes) 793 } 794 795 // Send an update for the node and wait for it to get applied. 796 arg := structs.CoordinateUpdateRequest{ 797 Datacenter: "dc1", 798 Node: "foo", 799 Coord: coordinate.NewCoordinate(coordinate.DefaultConfig()), 800 } 801 if err := a.RPC("Coordinate.Update", &arg, &out); err != nil { 802 t.Fatalf("err: %v", err) 803 } 804 time.Sleep(300 * time.Millisecond) 805 806 // Query again and now foo should have moved to the front of the line. 807 req, _ = http.NewRequest("GET", "/v1/catalog/service/api?tag=a&near=foo", nil) 808 resp = httptest.NewRecorder() 809 obj, err = a.srv.CatalogServiceNodes(resp, req) 810 if err != nil { 811 t.Fatalf("err: %v", err) 812 } 813 814 assertIndex(t, resp) 815 nodes = obj.(structs.ServiceNodes) 816 if len(nodes) != 2 { 817 t.Fatalf("bad: %v", obj) 818 } 819 if nodes[0].Node != "foo" { 820 t.Fatalf("bad: %v", nodes) 821 } 822 if nodes[1].Node != "bar" { 823 t.Fatalf("bad: %v", nodes) 824 } 825 } 826 827 // Test that connect proxies can be queried via /v1/catalog/service/:service 828 // directly and that their results contain the proxy fields. 829 func TestCatalogServiceNodes_ConnectProxy(t *testing.T) { 830 t.Parallel() 831 832 assert := assert.New(t) 833 a := NewTestAgent(t, t.Name(), "") 834 defer a.Shutdown() 835 testrpc.WaitForLeader(t, a.RPC, "dc1") 836 837 // Register 838 args := structs.TestRegisterRequestProxy(t) 839 var out struct{} 840 assert.Nil(a.RPC("Catalog.Register", args, &out)) 841 842 req, _ := http.NewRequest("GET", fmt.Sprintf( 843 "/v1/catalog/service/%s", args.Service.Service), nil) 844 resp := httptest.NewRecorder() 845 obj, err := a.srv.CatalogServiceNodes(resp, req) 846 assert.Nil(err) 847 assertIndex(t, resp) 848 849 nodes := obj.(structs.ServiceNodes) 850 assert.Len(nodes, 1) 851 assert.Equal(structs.ServiceKindConnectProxy, nodes[0].ServiceKind) 852 assert.Equal(args.Service.Proxy, nodes[0].ServiceProxy) 853 // DEPRECATED (ProxyDestination) - remove this when removing ProxyDestination 854 assert.Equal(args.Service.Proxy.DestinationServiceName, nodes[0].ServiceProxyDestination) 855 } 856 857 // Test that the Connect-compatible endpoints can be queried for a 858 // service via /v1/catalog/connect/:service. 859 func TestCatalogConnectServiceNodes_good(t *testing.T) { 860 t.Parallel() 861 862 assert := assert.New(t) 863 a := NewTestAgent(t, t.Name(), "") 864 defer a.Shutdown() 865 testrpc.WaitForLeader(t, a.RPC, "dc1") 866 867 // Register 868 args := structs.TestRegisterRequestProxy(t) 869 args.Service.Address = "127.0.0.55" 870 var out struct{} 871 assert.Nil(a.RPC("Catalog.Register", args, &out)) 872 873 req, _ := http.NewRequest("GET", fmt.Sprintf( 874 "/v1/catalog/connect/%s", args.Service.Proxy.DestinationServiceName), nil) 875 resp := httptest.NewRecorder() 876 obj, err := a.srv.CatalogConnectServiceNodes(resp, req) 877 assert.Nil(err) 878 assertIndex(t, resp) 879 880 nodes := obj.(structs.ServiceNodes) 881 assert.Len(nodes, 1) 882 assert.Equal(structs.ServiceKindConnectProxy, nodes[0].ServiceKind) 883 assert.Equal(args.Service.Address, nodes[0].ServiceAddress) 884 assert.Equal(args.Service.Proxy, nodes[0].ServiceProxy) 885 } 886 887 func TestCatalogNodeServices(t *testing.T) { 888 t.Parallel() 889 a := NewTestAgent(t, t.Name(), "") 890 defer a.Shutdown() 891 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 892 893 // Register node with a regular service and connect proxy 894 args := &structs.RegisterRequest{ 895 Datacenter: "dc1", 896 Node: "foo", 897 Address: "127.0.0.1", 898 Service: &structs.NodeService{ 899 Service: "api", 900 Tags: []string{"a"}, 901 }, 902 } 903 904 var out struct{} 905 if err := a.RPC("Catalog.Register", args, &out); err != nil { 906 t.Fatalf("err: %v", err) 907 } 908 909 // Register a connect proxy 910 args.Service = structs.TestNodeServiceProxy(t) 911 require.NoError(t, a.RPC("Catalog.Register", args, &out)) 912 913 req, _ := http.NewRequest("GET", "/v1/catalog/node/foo?dc=dc1", nil) 914 resp := httptest.NewRecorder() 915 obj, err := a.srv.CatalogNodeServices(resp, req) 916 if err != nil { 917 t.Fatalf("err: %v", err) 918 } 919 assertIndex(t, resp) 920 921 services := obj.(*structs.NodeServices) 922 if len(services.Services) != 2 { 923 t.Fatalf("bad: %v", obj) 924 } 925 926 // Proxy service should have it's config intact 927 require.Equal(t, args.Service.Proxy, services.Services["web-proxy"].Proxy) 928 } 929 930 // Test that the services on a node contain all the Connect proxies on 931 // the node as well with their fields properly populated. 932 func TestCatalogNodeServices_ConnectProxy(t *testing.T) { 933 t.Parallel() 934 935 assert := assert.New(t) 936 a := NewTestAgent(t, t.Name(), "") 937 defer a.Shutdown() 938 testrpc.WaitForTestAgent(t, a.RPC, "dc1") 939 940 // Register 941 args := structs.TestRegisterRequestProxy(t) 942 var out struct{} 943 assert.Nil(a.RPC("Catalog.Register", args, &out)) 944 945 req, _ := http.NewRequest("GET", fmt.Sprintf( 946 "/v1/catalog/node/%s", args.Node), nil) 947 resp := httptest.NewRecorder() 948 obj, err := a.srv.CatalogNodeServices(resp, req) 949 assert.Nil(err) 950 assertIndex(t, resp) 951 952 ns := obj.(*structs.NodeServices) 953 assert.Len(ns.Services, 1) 954 v := ns.Services[args.Service.Service] 955 assert.Equal(structs.ServiceKindConnectProxy, v.Kind) 956 } 957 958 func TestCatalogNodeServices_WanTranslation(t *testing.T) { 959 t.Parallel() 960 a1 := NewTestAgent(t, t.Name(), ` 961 datacenter = "dc1" 962 translate_wan_addrs = true 963 acl_datacenter = "" 964 `) 965 defer a1.Shutdown() 966 testrpc.WaitForTestAgent(t, a1.RPC, "dc1") 967 968 a2 := NewTestAgent(t, t.Name(), ` 969 datacenter = "dc2" 970 translate_wan_addrs = true 971 acl_datacenter = "" 972 `) 973 defer a2.Shutdown() 974 testrpc.WaitForTestAgent(t, a2.RPC, "dc2") 975 976 // Wait for the WAN join. 977 addr := fmt.Sprintf("127.0.0.1:%d", a1.Config.SerfPortWAN) 978 if _, err := a2.srv.agent.JoinWAN([]string{addr}); err != nil { 979 t.Fatalf("err: %v", err) 980 } 981 retry.Run(t, func(r *retry.R) { 982 if got, want := len(a1.WANMembers()), 2; got < want { 983 r.Fatalf("got %d WAN members want at least %d", got, want) 984 } 985 }) 986 987 // Register a node with DC2. 988 { 989 args := &structs.RegisterRequest{ 990 Datacenter: "dc2", 991 Node: "foo", 992 Address: "127.0.0.1", 993 TaggedAddresses: map[string]string{ 994 "wan": "127.0.0.2", 995 }, 996 Service: &structs.NodeService{ 997 Service: "http_wan_translation_test", 998 }, 999 } 1000 1001 var out struct{} 1002 if err := a2.RPC("Catalog.Register", args, &out); err != nil { 1003 t.Fatalf("err: %v", err) 1004 } 1005 } 1006 1007 // Query for the node in DC2 from DC1. 1008 req, _ := http.NewRequest("GET", "/v1/catalog/node/foo?dc=dc2", nil) 1009 resp1 := httptest.NewRecorder() 1010 obj1, err1 := a1.srv.CatalogNodeServices(resp1, req) 1011 if err1 != nil { 1012 t.Fatalf("err: %v", err1) 1013 } 1014 assertIndex(t, resp1) 1015 1016 // Expect that DC1 gives us a WAN address (since the node is in DC2). 1017 services1 := obj1.(*structs.NodeServices) 1018 if len(services1.Services) != 1 { 1019 t.Fatalf("bad: %v", obj1) 1020 } 1021 service1 := services1.Node 1022 if service1.Address != "127.0.0.2" { 1023 t.Fatalf("bad: %v", service1) 1024 } 1025 1026 // Query DC2 from DC2. 1027 resp2 := httptest.NewRecorder() 1028 obj2, err2 := a2.srv.CatalogNodeServices(resp2, req) 1029 if err2 != nil { 1030 t.Fatalf("err: %v", err2) 1031 } 1032 assertIndex(t, resp2) 1033 1034 // Expect that DC2 gives us a private address (since the node is in DC2). 1035 services2 := obj2.(*structs.NodeServices) 1036 if len(services2.Services) != 1 { 1037 t.Fatalf("bad: %v", obj2) 1038 } 1039 service2 := services2.Node 1040 if service2.Address != "127.0.0.1" { 1041 t.Fatalf("bad: %v", service2) 1042 } 1043 }