istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/sidecar_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package model 16 17 import ( 18 "encoding/json" 19 "reflect" 20 "strconv" 21 "strings" 22 "testing" 23 "time" 24 25 "github.com/google/go-cmp/cmp" 26 "github.com/google/go-cmp/cmp/cmpopts" 27 "google.golang.org/protobuf/types/known/durationpb" 28 "google.golang.org/protobuf/types/known/wrapperspb" 29 "k8s.io/apimachinery/pkg/types" 30 31 "istio.io/api/mesh/v1alpha1" 32 networking "istio.io/api/networking/v1alpha3" 33 "istio.io/api/type/v1beta1" 34 "istio.io/istio/pilot/pkg/features" 35 "istio.io/istio/pilot/pkg/serviceregistry/provider" 36 "istio.io/istio/pkg/config" 37 "istio.io/istio/pkg/config/constants" 38 "istio.io/istio/pkg/config/host" 39 "istio.io/istio/pkg/config/mesh" 40 "istio.io/istio/pkg/config/schema/gvk" 41 "istio.io/istio/pkg/config/schema/kind" 42 "istio.io/istio/pkg/config/visibility" 43 "istio.io/istio/pkg/test" 44 "istio.io/istio/pkg/test/util/assert" 45 "istio.io/istio/pkg/util/sets" 46 ) 47 48 var ( 49 port9999 = []*Port{ 50 { 51 Name: "uds", 52 Port: 9999, 53 Protocol: "HTTP", 54 }, 55 } 56 57 port7000 = []*Port{ 58 { 59 Name: "uds", 60 Port: 7000, 61 Protocol: "HTTP", 62 }, 63 } 64 65 port7443 = []*Port{ 66 { 67 Port: 7443, 68 Protocol: "GRPC", 69 Name: "service-grpc-tls", 70 }, 71 } 72 73 port7442 = []*Port{ 74 { 75 Port: 7442, 76 Protocol: "HTTP", 77 Name: "http-tls", 78 }, 79 } 80 81 port744x = []*Port{ 82 { 83 Port: 7443, 84 Protocol: "GRPC", 85 Name: "service-grpc-tls", 86 }, 87 { 88 Port: 7442, 89 Protocol: "HTTP", 90 Name: "http-tls", 91 }, 92 } 93 94 port803x = []*Port{ 95 { 96 Port: 8031, 97 Protocol: "TCP", 98 Name: "tcp-1", 99 }, 100 { 101 Port: 8032, 102 Protocol: "TCP", 103 Name: "tcp-2", 104 }, 105 { 106 Port: 8033, 107 Protocol: "TCP", 108 Name: "tcp-3", 109 }, 110 { 111 Port: 8034, 112 Protocol: "TCP", 113 Name: "tcp-4", 114 }, 115 { 116 Port: 8035, 117 Protocol: "TCP", 118 Name: "tcp-5", 119 }, 120 } 121 122 twoMatchingPorts = []*Port{ 123 { 124 Port: 7443, 125 Protocol: "GRPC", 126 Name: "service-grpc-tls", 127 }, 128 { 129 Port: 7442, 130 Protocol: "HTTP", 131 Name: "http-tls", 132 }, 133 } 134 135 port8000 = []*Port{ 136 { 137 Name: "uds", 138 Port: 8000, 139 Protocol: "HTTP", 140 }, 141 } 142 143 port9000 = []*Port{ 144 { 145 Name: "port1", 146 Port: 9000, 147 }, 148 } 149 150 twoPorts = []*Port{ 151 { 152 Name: "uds", 153 Port: 8000, 154 Protocol: "HTTP", 155 }, 156 { 157 Name: "uds", 158 Port: 7000, 159 Protocol: "HTTP", 160 }, 161 } 162 163 allPorts = []*Port{ 164 { 165 Name: "uds", 166 Port: 8000, 167 Protocol: "HTTP", 168 }, 169 { 170 Name: "uds", 171 Port: 7000, 172 Protocol: "HTTP", 173 }, 174 { 175 Name: "port1", 176 Port: 9000, 177 }, 178 } 179 180 configs1 = &config.Config{ 181 Meta: config.Meta{ 182 Name: "foo", 183 Namespace: "not-default", 184 }, 185 Spec: &networking.Sidecar{ 186 Egress: []*networking.IstioEgressListener{ 187 { 188 Port: &networking.SidecarPort{ 189 Number: 9000, 190 Protocol: "HTTP", 191 Name: "uds", 192 }, 193 Bind: "1.1.1.1", 194 Hosts: []string{"*/*"}, 195 }, 196 { 197 Hosts: []string{"*/*"}, 198 }, 199 }, 200 }, 201 } 202 configs2 = &config.Config{ 203 Meta: config.Meta{ 204 Name: "foo", 205 Namespace: "not-default", 206 }, 207 Spec: &networking.Sidecar{}, 208 } 209 210 configs3 = &config.Config{ 211 Meta: config.Meta{ 212 Name: "foo", 213 Namespace: "not-default", 214 }, 215 Spec: &networking.Sidecar{ 216 Egress: []*networking.IstioEgressListener{ 217 { 218 Hosts: []string{"foo/bar", "*/*"}, 219 }, 220 }, 221 }, 222 } 223 224 configs4 = &config.Config{ 225 Meta: config.Meta{ 226 Name: "foo", 227 Namespace: "not-default", 228 }, 229 Spec: &networking.Sidecar{ 230 Egress: []*networking.IstioEgressListener{ 231 { 232 Port: &networking.SidecarPort{ 233 Number: 8000, 234 Protocol: "HTTP", 235 Name: "uds", 236 }, 237 Hosts: []string{"foo/*"}, 238 }, 239 }, 240 }, 241 } 242 243 configs5 = &config.Config{ 244 Meta: config.Meta{ 245 Name: "foo", 246 Namespace: "not-default", 247 }, 248 Spec: &networking.Sidecar{ 249 Egress: []*networking.IstioEgressListener{ 250 { 251 Port: &networking.SidecarPort{ 252 Number: 8000, 253 Protocol: "HTTP", 254 Name: "uds", 255 }, 256 Hosts: []string{"foo/*"}, 257 }, 258 }, 259 }, 260 } 261 262 configs6 = &config.Config{ 263 Meta: config.Meta{ 264 Name: "foo", 265 Namespace: "not-default", 266 }, 267 Spec: &networking.Sidecar{ 268 Egress: []*networking.IstioEgressListener{ 269 { 270 Port: &networking.SidecarPort{ 271 Number: 8000, 272 Protocol: "HTTP", 273 Name: "uds", 274 }, 275 Hosts: []string{"foo/*"}, 276 }, 277 { 278 Port: &networking.SidecarPort{ 279 Number: 7000, 280 Protocol: "HTTP", 281 Name: "uds", 282 }, 283 Hosts: []string{"foo/*"}, 284 }, 285 }, 286 }, 287 } 288 289 configs7 = &config.Config{ 290 Meta: config.Meta{ 291 Name: "sidecar-scope-ns1-ns2", 292 }, 293 Spec: &networking.Sidecar{ 294 Egress: []*networking.IstioEgressListener{ 295 { 296 Port: &networking.SidecarPort{ 297 Number: 23145, 298 Protocol: "TCP", 299 Name: "outbound-tcp", 300 }, 301 Bind: "7.7.7.7", 302 Hosts: []string{ 303 "*/bookinginfo.com", 304 "*/private.com", 305 }, 306 }, 307 { 308 Hosts: []string{ 309 "ns1/*", 310 "*/*.tcp.com", 311 }, 312 }, 313 }, 314 }, 315 } 316 317 configs8 = &config.Config{ 318 Meta: config.Meta{ 319 Name: "different-port-name", 320 }, 321 Spec: &networking.Sidecar{ 322 Egress: []*networking.IstioEgressListener{ 323 { 324 Port: &networking.SidecarPort{ 325 Number: 7443, 326 Protocol: "GRPC", 327 Name: "listener-grpc-tls", 328 }, 329 Hosts: []string{"mesh/*"}, 330 }, 331 }, 332 }, 333 } 334 335 configs9 = &config.Config{ 336 Meta: config.Meta{ 337 Name: "sidecar-scope-wildcards", 338 }, 339 Spec: &networking.Sidecar{ 340 Egress: []*networking.IstioEgressListener{ 341 { 342 Port: &networking.SidecarPort{ 343 Number: 7443, 344 Protocol: "GRPC", 345 Name: "grpc-tls", 346 }, 347 Hosts: []string{"*/*"}, 348 }, 349 { 350 Port: &networking.SidecarPort{ 351 Number: 7442, 352 Protocol: "HTTP", 353 Name: "http-tls", 354 }, 355 Hosts: []string{"ns2/*"}, 356 }, 357 }, 358 }, 359 } 360 361 configs10 = &config.Config{ 362 Meta: config.Meta{ 363 Name: "sidecar-scope-with-http-proxy", 364 }, 365 Spec: &networking.Sidecar{ 366 Egress: []*networking.IstioEgressListener{ 367 { 368 Port: &networking.SidecarPort{ 369 Number: 7443, 370 Protocol: "http_proxy", 371 Name: "grpc-tls", 372 }, 373 Hosts: []string{"*/*"}, 374 }, 375 }, 376 }, 377 } 378 379 configs11 = &config.Config{ 380 Meta: config.Meta{ 381 Name: "sidecar-scope-with-http-proxy-match-virtual-service", 382 }, 383 Spec: &networking.Sidecar{ 384 Egress: []*networking.IstioEgressListener{ 385 { 386 Port: &networking.SidecarPort{ 387 Number: 7443, 388 Protocol: "http_proxy", 389 Name: "grpc-tls", 390 }, 391 Hosts: []string{"foo/virtualbar"}, 392 }, 393 }, 394 }, 395 } 396 397 configs12 = &config.Config{ 398 Meta: config.Meta{ 399 Name: "sidecar-scope-with-http-proxy-match-virtual-service-and-service", 400 }, 401 Spec: &networking.Sidecar{ 402 Egress: []*networking.IstioEgressListener{ 403 { 404 Port: &networking.SidecarPort{ 405 Number: 7443, 406 Protocol: "http_proxy", 407 Name: "grpc-tls", 408 }, 409 Hosts: []string{"foo/virtualbar", "ns2/foo.svc.cluster.local"}, 410 }, 411 }, 412 }, 413 } 414 415 configs13 = &config.Config{ 416 Meta: config.Meta{ 417 Name: "sidecar-scope-with-illegal-host", 418 }, 419 Spec: &networking.Sidecar{ 420 Egress: []*networking.IstioEgressListener{ 421 { 422 Port: &networking.SidecarPort{ 423 Number: 7443, 424 Protocol: "http_proxy", 425 Name: "grpc-tls", 426 }, 427 Hosts: []string{"foo", "foo/bar"}, 428 }, 429 }, 430 }, 431 } 432 433 configs14 = &config.Config{ 434 Meta: config.Meta{ 435 Name: "sidecar-scope-wildcards", 436 }, 437 Spec: &networking.Sidecar{ 438 Egress: []*networking.IstioEgressListener{ 439 { 440 Port: &networking.SidecarPort{ 441 Number: 7443, 442 Protocol: "GRPC", 443 Name: "grpc-tls", 444 }, 445 Hosts: []string{"*/*"}, 446 }, 447 { 448 Port: &networking.SidecarPort{ 449 Number: 7442, 450 Protocol: "HTTP", 451 Name: "http-tls", 452 }, 453 Hosts: []string{"ns2/*"}, 454 }, 455 { 456 Hosts: []string{"*/*"}, 457 }, 458 }, 459 }, 460 } 461 462 configs15 = &config.Config{ 463 Meta: config.Meta{ 464 Name: "sidecar-scope-with-virtual-service", 465 }, 466 Spec: &networking.Sidecar{ 467 Egress: []*networking.IstioEgressListener{ 468 { 469 Port: &networking.SidecarPort{ 470 Number: 7443, 471 Protocol: "http", 472 Name: "grpc-tls", 473 }, 474 Hosts: []string{"*/*"}, 475 }, 476 }, 477 }, 478 } 479 480 configs16 = &config.Config{ 481 Meta: config.Meta{ 482 Name: "sidecar-scope-with-specific-host", 483 Namespace: "ns1", 484 }, 485 Spec: &networking.Sidecar{ 486 Egress: []*networking.IstioEgressListener{ 487 { 488 Hosts: []string{"*/en.wikipedia.org"}, 489 }, 490 }, 491 }, 492 } 493 494 configs17 = &config.Config{ 495 Meta: config.Meta{ 496 Name: "sidecar-scope-with-wildcard-host", 497 Namespace: "ns1", 498 }, 499 Spec: &networking.Sidecar{ 500 Egress: []*networking.IstioEgressListener{ 501 { 502 Hosts: []string{"*/*.wikipedia.org"}, 503 }, 504 }, 505 }, 506 } 507 508 configs18 = &config.Config{ 509 Meta: config.Meta{ 510 Name: "sidecar-scope-with-workloadselector-specific-dr-match", 511 Namespace: "mynamespace", 512 Labels: map[string]string{"app": "app2"}, 513 }, 514 Spec: &networking.Sidecar{}, 515 } 516 517 configs19 = &config.Config{ 518 Meta: config.Meta{ 519 Name: "sidecar-scope-with-workloadselector-specific-dr-no-match", 520 Namespace: "mynamespace", 521 Labels: map[string]string{"app": "app5"}, 522 }, 523 Spec: &networking.Sidecar{}, 524 } 525 526 configs20 = &config.Config{ 527 Meta: config.Meta{ 528 Name: "sidecar-scope-with-same-workloadselector-label-drs-merged", 529 Namespace: "mynamespace", 530 Labels: map[string]string{"app": "app1"}, 531 }, 532 Spec: &networking.Sidecar{}, 533 } 534 535 configs21 = &config.Config{ 536 Meta: config.Meta{ 537 Name: "virtual-service-destinations-matching-http-virtual-service-ports", 538 }, 539 Spec: &networking.Sidecar{ 540 Egress: []*networking.IstioEgressListener{ 541 { 542 Hosts: []string{"foo/virtualbar"}, 543 }, 544 }, 545 }, 546 } 547 548 configs22 = &config.Config{ 549 Meta: config.Meta{ 550 Name: "sidecar-scope-with-multiple-ports", 551 }, 552 Spec: &networking.Sidecar{ 553 Egress: []*networking.IstioEgressListener{ 554 { 555 Port: &networking.SidecarPort{ 556 Number: 8031, 557 Protocol: "TCP", 558 Name: "tcp-ipc1", 559 }, 560 Hosts: []string{"*/foobar.svc.cluster.local"}, 561 }, 562 { 563 Port: &networking.SidecarPort{ 564 Number: 8032, 565 Protocol: "TCP", 566 Name: "tcp-ipc2", 567 }, 568 Hosts: []string{"*/foobar.svc.cluster.local"}, 569 }, 570 { 571 Port: &networking.SidecarPort{ 572 Number: 8033, 573 Protocol: "TCP", 574 Name: "tcp-ipc3", 575 }, 576 Hosts: []string{"*/foobar.svc.cluster.local"}, 577 }, 578 { 579 Port: &networking.SidecarPort{ 580 Number: 8034, 581 Protocol: "TCP", 582 Name: "tcp-ipc4", 583 }, 584 Hosts: []string{"*/foobar.svc.cluster.local"}, 585 }, 586 { 587 Port: &networking.SidecarPort{ 588 Number: 8035, 589 Protocol: "TCP", 590 Name: "tcp-ipc5", 591 }, 592 Hosts: []string{"*/foobar.svc.cluster.local"}, 593 }, 594 }, 595 }, 596 } 597 598 configs23 = &config.Config{ 599 Meta: config.Meta{ 600 Name: "sidecar-scope-with-multiple-ports", 601 }, 602 Spec: &networking.Sidecar{ 603 Egress: []*networking.IstioEgressListener{ 604 { 605 Port: &networking.SidecarPort{ 606 Number: 8031, 607 Protocol: "TCP", 608 Name: "tcp-ipc1", 609 }, 610 Hosts: []string{"ns1/foobar.svc.cluster.local"}, 611 }, 612 { 613 Port: &networking.SidecarPort{ 614 Number: 8032, 615 Protocol: "TCP", 616 Name: "tcp-ipc2", 617 }, 618 Hosts: []string{"ns1/foobar.svc.cluster.local"}, 619 }, 620 { 621 Port: &networking.SidecarPort{ 622 Number: 8033, 623 Protocol: "TCP", 624 Name: "tcp-ipc3", 625 }, 626 Hosts: []string{"ns1/foobar.svc.cluster.local"}, 627 }, 628 { 629 Port: &networking.SidecarPort{ 630 Number: 8034, 631 Protocol: "TCP", 632 Name: "tcp-ipc4", 633 }, 634 Hosts: []string{"ns1/foobar.svc.cluster.local"}, 635 }, 636 { 637 Port: &networking.SidecarPort{ 638 Number: 8035, 639 Protocol: "TCP", 640 Name: "tcp-ipc5", 641 }, 642 Hosts: []string{"ns1/foobar.svc.cluster.local"}, 643 }, 644 }, 645 }, 646 } 647 648 services1 = []*Service{ 649 { 650 Hostname: "bar", 651 }, 652 } 653 654 services2 = []*Service{ 655 { 656 Hostname: "bar", 657 Ports: port8000, 658 }, 659 { 660 Hostname: "barprime", 661 }, 662 } 663 664 services3 = []*Service{ 665 { 666 Hostname: "bar", 667 Ports: port9000, 668 }, 669 { 670 Hostname: "barprime", 671 }, 672 } 673 674 services4 = []*Service{ 675 { 676 Hostname: "bar", 677 }, 678 { 679 Hostname: "barprime", 680 }, 681 } 682 683 services5 = []*Service{ 684 { 685 Hostname: "bar", 686 Ports: port8000, 687 Attributes: ServiceAttributes{ 688 Name: "bar", 689 Namespace: "foo", 690 }, 691 }, 692 { 693 Hostname: "barprime", 694 Attributes: ServiceAttributes{ 695 Name: "barprime", 696 Namespace: "foo", 697 }, 698 }, 699 } 700 701 services6 = []*Service{ 702 { 703 Hostname: "bar", 704 Ports: twoPorts, 705 Attributes: ServiceAttributes{ 706 Name: "bar", 707 Namespace: "foo", 708 }, 709 }, 710 } 711 712 services7 = []*Service{ 713 { 714 Hostname: "bar", 715 Ports: twoPorts, 716 Attributes: ServiceAttributes{ 717 Name: "bar", 718 Namespace: "foo", 719 }, 720 }, 721 { 722 Hostname: "barprime", 723 Ports: port8000, 724 Attributes: ServiceAttributes{ 725 Name: "barprime", 726 Namespace: "foo", 727 }, 728 }, 729 { 730 Hostname: "foo", 731 Ports: allPorts, 732 Attributes: ServiceAttributes{ 733 Name: "foo", 734 Namespace: "foo", 735 }, 736 }, 737 } 738 739 services8 = []*Service{ 740 { 741 Hostname: "bookinginfo.com", 742 Ports: port9999, 743 Attributes: ServiceAttributes{ 744 Name: "bookinginfo.com", 745 Namespace: "ns1", 746 }, 747 }, 748 { 749 Hostname: "private.com", 750 Attributes: ServiceAttributes{ 751 Name: "private.com", 752 Namespace: "ns1", 753 }, 754 }, 755 } 756 757 services9 = []*Service{ 758 { 759 Hostname: "foo.svc.cluster.local", 760 Ports: port7443, 761 Attributes: ServiceAttributes{ 762 Name: "foo", 763 Namespace: "mesh", 764 }, 765 }, 766 } 767 768 services10 = []*Service{ 769 { 770 Hostname: "foo.svc.cluster.local", 771 Ports: port7443, 772 Attributes: ServiceAttributes{ 773 Name: "foo", 774 Namespace: "ns1", 775 }, 776 }, 777 { 778 Hostname: "baz.svc.cluster.local", 779 Ports: port7443, 780 Attributes: ServiceAttributes{ 781 Name: "baz", 782 Namespace: "ns3", 783 }, 784 }, 785 { 786 Hostname: "bar.svc.cluster.local", 787 Ports: port7442, 788 Attributes: ServiceAttributes{ 789 Name: "bar", 790 Namespace: "ns2", 791 }, 792 }, 793 { 794 Hostname: "barprime.svc.cluster.local", 795 Ports: port7442, 796 Attributes: ServiceAttributes{ 797 Name: "barprime", 798 Namespace: "ns3", 799 }, 800 }, 801 } 802 803 services11 = []*Service{ 804 { 805 Hostname: "foo.svc.cluster.local", 806 Ports: port7443, 807 Attributes: ServiceAttributes{ 808 Name: "foo", 809 Namespace: "ns1", 810 }, 811 }, 812 { 813 Hostname: "baz.svc.cluster.local", 814 Ports: port7443, 815 Attributes: ServiceAttributes{ 816 Name: "baz", 817 Namespace: "ns3", 818 }, 819 }, 820 { 821 Hostname: "bar.svc.cluster.local", 822 Ports: twoMatchingPorts, 823 Attributes: ServiceAttributes{ 824 Name: "bar", 825 Namespace: "ns2", 826 }, 827 }, 828 { 829 Hostname: "barprime.svc.cluster.local", 830 Ports: port7442, 831 Attributes: ServiceAttributes{ 832 Name: "barprime", 833 Namespace: "ns3", 834 }, 835 }, 836 } 837 838 services12 = []*Service{ 839 { 840 Hostname: "foo.svc.cluster.local", 841 Ports: port7443, 842 Attributes: ServiceAttributes{ 843 Name: "foo", 844 Namespace: "ns1", 845 }, 846 }, 847 { 848 Hostname: "foo.svc.cluster.local", 849 Ports: port8000, 850 Attributes: ServiceAttributes{ 851 Name: "foo", 852 Namespace: "ns2", 853 }, 854 }, 855 { 856 Hostname: "baz.svc.cluster.local", 857 Ports: port7443, 858 Attributes: ServiceAttributes{ 859 Name: "baz", 860 Namespace: "ns3", 861 }, 862 }, 863 } 864 865 services13 = []*Service{ 866 { 867 Hostname: "foo.svc.cluster.local", 868 Ports: port7443, 869 Attributes: ServiceAttributes{ 870 Name: "foo", 871 Namespace: "ns1", 872 }, 873 }, 874 { 875 Hostname: "foo.svc.cluster.local", 876 Ports: port8000, 877 Attributes: ServiceAttributes{ 878 Name: "foo", 879 Namespace: "mynamespace", 880 }, 881 }, 882 { 883 Hostname: "baz.svc.cluster.local", 884 Ports: port7443, 885 Attributes: ServiceAttributes{ 886 Name: "baz", 887 Namespace: "ns3", 888 }, 889 }, 890 } 891 892 services14 = []*Service{ 893 { 894 Hostname: "bar", 895 Ports: port7443, 896 Attributes: ServiceAttributes{ 897 Name: "bar", 898 Namespace: "foo", 899 }, 900 }, 901 } 902 903 services15 = []*Service{ 904 { 905 Hostname: "foo.svc.cluster.local", 906 Ports: port7443, 907 Attributes: ServiceAttributes{ 908 Name: "foo", 909 Namespace: "ns1", 910 ExportTo: sets.New(visibility.Private), 911 }, 912 }, 913 { 914 Hostname: "foo.svc.cluster.local", 915 Ports: port8000, 916 Attributes: ServiceAttributes{ 917 Name: "foo", 918 Namespace: "ns2", 919 }, 920 }, 921 { 922 Hostname: "baz.svc.cluster.local", 923 Ports: port7443, 924 Attributes: ServiceAttributes{ 925 Name: "baz", 926 Namespace: "ns3", 927 }, 928 }, 929 } 930 931 services16 = []*Service{ 932 { 933 Hostname: "foo.svc.cluster.local", 934 Ports: port7443, 935 Attributes: ServiceAttributes{ 936 Name: "foo", 937 Namespace: "ns1", 938 }, 939 }, 940 { 941 Hostname: "baz.svc.cluster.local", 942 Ports: port7443, 943 Attributes: ServiceAttributes{ 944 Name: "baz", 945 Namespace: "ns3", 946 }, 947 }, 948 { 949 Hostname: "bar.svc.cluster.local", 950 Ports: port7442, 951 Attributes: ServiceAttributes{ 952 Name: "bar", 953 Namespace: "ns2", 954 }, 955 }, 956 { 957 Hostname: "barprime.svc.cluster.local", 958 Ports: port7442, 959 Attributes: ServiceAttributes{ 960 Name: "barprime", 961 Namespace: "ns3", 962 }, 963 }, 964 { 965 Hostname: "barprime.svc.cluster.local", 966 Ports: port7442, 967 Attributes: ServiceAttributes{ 968 Name: "barprime", 969 Namespace: "ns3", 970 }, 971 }, 972 { 973 Hostname: "random.svc.cluster.local", 974 Ports: port9999, 975 Attributes: ServiceAttributes{ 976 Name: "random", 977 Namespace: "randomns", // nolint 978 }, 979 }, 980 } 981 982 services17 = []*Service{ 983 { 984 Hostname: "foo.svc.cluster.local", 985 Ports: port7443, 986 Attributes: ServiceAttributes{ 987 Name: "foo", 988 Namespace: "ns1", 989 }, 990 }, 991 { 992 Hostname: "baz.svc.cluster.local", 993 Ports: port7442, 994 Attributes: ServiceAttributes{ 995 Name: "baz", 996 Namespace: "ns3", 997 }, 998 }, 999 } 1000 1001 services18 = []*Service{ 1002 { 1003 Hostname: "foo.svc.cluster.local", 1004 Ports: port7443, 1005 Attributes: ServiceAttributes{ 1006 Name: "foo", 1007 Namespace: "*", 1008 }, 1009 }, 1010 { 1011 Hostname: "baz.svc.cluster.local", 1012 Ports: port7443, 1013 Attributes: ServiceAttributes{ 1014 Name: "baz", 1015 Namespace: "*", 1016 }, 1017 }, 1018 } 1019 1020 services19 = []*Service{ 1021 { 1022 Hostname: "en.wikipedia.org", 1023 Attributes: ServiceAttributes{ 1024 Name: "en.wikipedia.org", 1025 Namespace: "ns1", 1026 }, 1027 }, 1028 { 1029 Hostname: "*.wikipedia.org", 1030 Attributes: ServiceAttributes{ 1031 Name: "*.wikipedia.org", 1032 Namespace: "ns1", 1033 }, 1034 }, 1035 } 1036 1037 services20 = []*Service{ 1038 { 1039 Hostname: "httpbin.org", 1040 Attributes: ServiceAttributes{ 1041 Namespace: "mynamespace", 1042 }, 1043 }, 1044 } 1045 1046 services21 = []*Service{ 1047 { 1048 Hostname: "foo.svc.cluster.local", 1049 Ports: twoPorts, 1050 Attributes: ServiceAttributes{ 1051 Name: "foo", 1052 Namespace: "ns1", 1053 }, 1054 }, 1055 { 1056 Hostname: "baz.svc.cluster.local", 1057 Ports: twoPorts, 1058 Attributes: ServiceAttributes{ 1059 Name: "baz", 1060 Namespace: "ns3", 1061 }, 1062 }, 1063 } 1064 1065 services22 = []*Service{ 1066 { 1067 Hostname: "baz.svc.cluster.local", 1068 Ports: port7443, 1069 Attributes: ServiceAttributes{ 1070 Name: "baz", 1071 Namespace: "ns3", 1072 }, 1073 }, 1074 } 1075 1076 services23 = []*Service{ 1077 { 1078 Hostname: "foobar.svc.cluster.local", 1079 Ports: port803x, 1080 Attributes: ServiceAttributes{ 1081 Name: "foo", 1082 Namespace: "ns1", 1083 ServiceRegistry: provider.Kubernetes, 1084 }, 1085 }, 1086 { 1087 Hostname: "foobar.svc.cluster.local", 1088 Ports: port8000, 1089 Attributes: ServiceAttributes{ 1090 Name: "foo", 1091 Namespace: "ns2", 1092 ServiceRegistry: provider.Kubernetes, 1093 }, 1094 }, 1095 { 1096 Hostname: "foobar.svc.cluster.local", 1097 Ports: port7443, 1098 Attributes: ServiceAttributes{ 1099 Name: "baz", 1100 Namespace: "ns3", 1101 ServiceRegistry: provider.Kubernetes, 1102 }, 1103 }, 1104 } 1105 services24 = []*Service{ 1106 { 1107 Hostname: "foobar.svc.cluster.local", 1108 Ports: port803x, 1109 Attributes: ServiceAttributes{ 1110 Name: "foo", 1111 Namespace: "ns1", 1112 }, 1113 }, 1114 { 1115 Hostname: "foobar.svc.cluster.local", 1116 Ports: port8000, 1117 Attributes: ServiceAttributes{ 1118 Name: "foo", 1119 Namespace: "ns2", 1120 }, 1121 }, 1122 { 1123 Hostname: "foobar.svc.cluster.local", 1124 Ports: port7443, 1125 Attributes: ServiceAttributes{ 1126 Name: "baz", 1127 Namespace: "ns1", // same ns as foo 1128 }, 1129 }, 1130 } 1131 services25 = []*Service{ 1132 { 1133 Hostname: "foobar.svc.cluster.local", 1134 Ports: port803x, 1135 Attributes: ServiceAttributes{ 1136 Name: "foo", 1137 Namespace: "ns1", 1138 }, 1139 }, 1140 { 1141 Hostname: "foobar.svc.cluster.local", 1142 Ports: port8000, 1143 Attributes: ServiceAttributes{ 1144 Name: "bar", 1145 Namespace: "ns2", 1146 }, 1147 }, 1148 { 1149 Hostname: "foobar.svc.cluster.local", 1150 Ports: port7443, 1151 Attributes: ServiceAttributes{ 1152 Name: "baz", 1153 Namespace: "ns3", 1154 ServiceRegistry: provider.Kubernetes, 1155 }, 1156 }, 1157 } 1158 1159 services26 = []*Service{ 1160 { 1161 Hostname: "foobar.svc.cluster.local", 1162 Ports: port803x, 1163 Attributes: ServiceAttributes{ 1164 Name: "foo", 1165 Namespace: "ns1", 1166 ServiceRegistry: provider.Kubernetes, 1167 }, 1168 }, 1169 } 1170 1171 virtualServices1 = []config.Config{ 1172 { 1173 Meta: config.Meta{ 1174 GroupVersionKind: gvk.VirtualService, 1175 Name: "virtualbar", 1176 Namespace: "foo", 1177 }, 1178 Spec: &networking.VirtualService{ 1179 Hosts: []string{"virtualbar"}, 1180 Http: []*networking.HTTPRoute{ 1181 { 1182 Mirror: &networking.Destination{Host: "foo.svc.cluster.local"}, 1183 Route: []*networking.HTTPRouteDestination{{Destination: &networking.Destination{Host: "baz.svc.cluster.local"}}}, 1184 }, 1185 }, 1186 }, 1187 }, 1188 } 1189 1190 virtualServices2 = []config.Config{ 1191 { 1192 Meta: config.Meta{ 1193 GroupVersionKind: gvk.VirtualService, 1194 Name: "virtualbar", 1195 Namespace: "foo", 1196 }, 1197 Spec: &networking.VirtualService{ 1198 Hosts: []string{"virtualbar", "*"}, 1199 Http: []*networking.HTTPRoute{ 1200 { 1201 Mirror: &networking.Destination{Host: "foo.svc.cluster.local"}, 1202 Route: []*networking.HTTPRouteDestination{{Destination: &networking.Destination{Host: "baz.svc.cluster.local"}}}, 1203 }, 1204 }, 1205 }, 1206 }, 1207 } 1208 1209 virtualServices3 = []config.Config{ 1210 { 1211 Meta: config.Meta{ 1212 GroupVersionKind: gvk.VirtualService, 1213 Name: "virtualbar", 1214 Namespace: "foo", 1215 }, 1216 Spec: &networking.VirtualService{ 1217 Hosts: []string{"virtualbar"}, 1218 Http: []*networking.HTTPRoute{ 1219 { 1220 Route: []*networking.HTTPRouteDestination{ 1221 { 1222 Destination: &networking.Destination{ 1223 Host: "baz.svc.cluster.local", Port: &networking.PortSelector{Number: 7000}, 1224 }, 1225 }, 1226 }, 1227 Mirror: &networking.Destination{Host: "foo.svc.cluster.local", Port: &networking.PortSelector{Number: 7000}}, 1228 }, 1229 }, 1230 }, 1231 }, 1232 } 1233 1234 virtualServices4 = []config.Config{ 1235 { 1236 Meta: config.Meta{ 1237 GroupVersionKind: gvk.VirtualService, 1238 Name: "virtualbar", 1239 Namespace: "foo", 1240 }, 1241 Spec: &networking.VirtualService{ 1242 Hosts: []string{"virtualbar"}, 1243 Tcp: []*networking.TCPRoute{ 1244 { 1245 Route: []*networking.RouteDestination{ 1246 { 1247 Destination: &networking.Destination{ 1248 Host: "baz.svc.cluster.local", Port: &networking.PortSelector{Number: 7000}, 1249 }, 1250 }, 1251 }, 1252 }, 1253 }, 1254 }, 1255 }, 1256 } 1257 1258 virtualServices5 = []config.Config{ 1259 { 1260 Meta: config.Meta{ 1261 GroupVersionKind: gvk.VirtualService, 1262 Name: "virtualbar", 1263 Namespace: "foo", 1264 }, 1265 Spec: &networking.VirtualService{ 1266 Hosts: []string{"virtualbar"}, 1267 Tls: []*networking.TLSRoute{ 1268 { 1269 Route: []*networking.RouteDestination{ 1270 { 1271 Destination: &networking.Destination{ 1272 Host: "baz.svc.cluster.local", Port: &networking.PortSelector{Number: 7000}, 1273 }, 1274 }, 1275 }, 1276 }, 1277 }, 1278 }, 1279 }, 1280 } 1281 destinationRule1 = config.Config{ 1282 Meta: config.Meta{ 1283 Name: "drRule1", 1284 Namespace: "mynamespace", 1285 }, 1286 Spec: &networking.DestinationRule{ 1287 Host: "httpbin.org", 1288 WorkloadSelector: &v1beta1.WorkloadSelector{ 1289 MatchLabels: map[string]string{"app": "app1"}, 1290 }, 1291 TrafficPolicy: &networking.TrafficPolicy{ 1292 ConnectionPool: &networking.ConnectionPoolSettings{ 1293 Http: &networking.ConnectionPoolSettings_HTTPSettings{ 1294 MaxRetries: 33, 1295 }, 1296 Tcp: &networking.ConnectionPoolSettings_TCPSettings{ 1297 ConnectTimeout: &durationpb.Duration{Seconds: 33}, 1298 }, 1299 }, 1300 }, 1301 }, 1302 } 1303 destinationRule2 = config.Config{ 1304 Meta: config.Meta{ 1305 Name: "drRule2", 1306 Namespace: "mynamespace", 1307 }, 1308 Spec: &networking.DestinationRule{ 1309 Host: "httpbin.org", 1310 WorkloadSelector: &v1beta1.WorkloadSelector{ 1311 MatchLabels: map[string]string{"app": "app2"}, 1312 }, 1313 TrafficPolicy: &networking.TrafficPolicy{ 1314 ConnectionPool: &networking.ConnectionPoolSettings{ 1315 Http: &networking.ConnectionPoolSettings_HTTPSettings{ 1316 MaxRetries: 33, 1317 }, 1318 Tcp: &networking.ConnectionPoolSettings_TCPSettings{ 1319 ConnectTimeout: &durationpb.Duration{Seconds: 33}, 1320 }, 1321 }, 1322 OutlierDetection: &networking.OutlierDetection{ 1323 Consecutive_5XxErrors: &wrapperspb.UInt32Value{Value: 3}, 1324 }, 1325 }, 1326 }, 1327 } 1328 mergedDr1and3 = config.Config{ 1329 Meta: config.Meta{ 1330 Name: "drRule1", 1331 Namespace: "mynamespace", 1332 }, 1333 Spec: &networking.DestinationRule{ 1334 Host: "httpbin.org", 1335 WorkloadSelector: &v1beta1.WorkloadSelector{ 1336 MatchLabels: map[string]string{"app": "app1"}, 1337 }, 1338 TrafficPolicy: &networking.TrafficPolicy{ 1339 ConnectionPool: &networking.ConnectionPoolSettings{ 1340 Http: &networking.ConnectionPoolSettings_HTTPSettings{ 1341 MaxRetries: 33, 1342 }, 1343 Tcp: &networking.ConnectionPoolSettings_TCPSettings{ 1344 ConnectTimeout: &durationpb.Duration{Seconds: 33}, 1345 }, 1346 }, 1347 }, 1348 Subsets: []*networking.Subset{ 1349 { 1350 Name: "subset1", 1351 }, 1352 { 1353 Name: "subset2", 1354 }, 1355 }, 1356 }, 1357 } 1358 destinationRule3 = config.Config{ 1359 Meta: config.Meta{ 1360 Name: "drRule3", 1361 Namespace: "mynamespace", 1362 }, 1363 Spec: &networking.DestinationRule{ 1364 Host: "httpbin.org", 1365 WorkloadSelector: &v1beta1.WorkloadSelector{ 1366 MatchLabels: map[string]string{"app": "app1"}, 1367 }, 1368 Subsets: []*networking.Subset{ 1369 { 1370 Name: "subset1", 1371 }, 1372 { 1373 Name: "subset2", 1374 }, 1375 }, 1376 }, 1377 } 1378 nonWorkloadSelectorDr = config.Config{ 1379 Meta: config.Meta{ 1380 Name: "drRule3", 1381 Namespace: "mynamespace", 1382 }, 1383 Spec: &networking.DestinationRule{ 1384 Host: "httpbin.org", 1385 TrafficPolicy: &networking.TrafficPolicy{ 1386 ConnectionPool: &networking.ConnectionPoolSettings{ 1387 Http: &networking.ConnectionPoolSettings_HTTPSettings{ 1388 MaxRetries: 33, 1389 }, 1390 Tcp: &networking.ConnectionPoolSettings_TCPSettings{ 1391 ConnectTimeout: &durationpb.Duration{Seconds: 33}, 1392 }, 1393 }, 1394 }, 1395 }, 1396 } 1397 ) 1398 1399 func TestCreateSidecarScope(t *testing.T) { 1400 tests := []struct { 1401 name string 1402 sidecarConfig *config.Config 1403 // list of available service for a given proxy 1404 services []*Service 1405 virtualServices []config.Config 1406 // list of services expected to be in the listener 1407 expectedServices []*Service 1408 expectedDr *config.Config 1409 }{ 1410 { 1411 "no-sidecar-config", 1412 nil, 1413 nil, 1414 nil, 1415 nil, 1416 nil, 1417 }, 1418 { 1419 "no-sidecar-config-with-service", 1420 nil, 1421 services1, 1422 nil, 1423 []*Service{ 1424 { 1425 Hostname: "bar", 1426 }, 1427 }, 1428 nil, 1429 }, 1430 { 1431 "no-sidecar-config-not-merge-service-in-diff-namespaces", 1432 nil, 1433 services23, 1434 nil, 1435 []*Service{ 1436 { 1437 Hostname: "foobar.svc.cluster.local", 1438 Ports: port803x, 1439 Attributes: ServiceAttributes{ 1440 Name: "foo", 1441 Namespace: "ns1", 1442 }, 1443 }, 1444 }, 1445 nil, 1446 }, 1447 { 1448 "no-sidecar-config-merge-service-ports", 1449 nil, 1450 services24, 1451 nil, 1452 []*Service{ 1453 { 1454 Hostname: "foobar.svc.cluster.local", 1455 Ports: append(port803x, port7443...), 1456 Attributes: ServiceAttributes{ 1457 Name: "foo", 1458 Namespace: "ns", 1459 }, 1460 }, 1461 }, 1462 nil, 1463 }, 1464 { 1465 "no-sidecar-config-k8s-service-take-precedence", 1466 nil, 1467 services25, 1468 nil, 1469 []*Service{ 1470 { 1471 Hostname: "foobar.svc.cluster.local", 1472 Ports: port7443, 1473 Attributes: ServiceAttributes{ 1474 Name: "bar", 1475 Namespace: "ns2", 1476 }, 1477 }, 1478 }, 1479 nil, 1480 }, 1481 { 1482 "sidecar-with-multiple-egress", 1483 configs1, 1484 nil, 1485 nil, 1486 nil, 1487 nil, 1488 }, 1489 { 1490 "sidecar-with-multiple-egress-with-service", 1491 configs1, 1492 services1, 1493 nil, 1494 1495 []*Service{ 1496 { 1497 Hostname: "bar", 1498 }, 1499 }, 1500 nil, 1501 }, 1502 { 1503 "sidecar-with-multiple-egress-with-service-on-same-port", 1504 configs1, 1505 services3, 1506 nil, 1507 []*Service{ 1508 { 1509 Hostname: "bar", 1510 }, 1511 { 1512 Hostname: "barprime", 1513 }, 1514 }, 1515 nil, 1516 }, 1517 { 1518 "sidecar-with-multiple-egress-with-multiple-service", 1519 configs1, 1520 services4, 1521 nil, 1522 []*Service{ 1523 { 1524 Hostname: "bar", 1525 }, 1526 { 1527 Hostname: "barprime", 1528 }, 1529 }, 1530 nil, 1531 }, 1532 { 1533 "sidecar-with-zero-egress", 1534 configs2, 1535 nil, 1536 nil, 1537 nil, 1538 nil, 1539 }, 1540 { 1541 "sidecar-with-zero-egress-multiple-service", 1542 configs2, 1543 services4, 1544 nil, 1545 []*Service{ 1546 { 1547 Hostname: "bar", 1548 }, 1549 { 1550 Hostname: "barprime", 1551 }, 1552 }, 1553 nil, 1554 }, 1555 { 1556 "sidecar-with-multiple-egress-noport", 1557 configs3, 1558 nil, 1559 nil, 1560 nil, 1561 nil, 1562 }, 1563 { 1564 "sidecar-with-multiple-egress-noport-with-specific-service", 1565 configs3, 1566 services2, 1567 nil, 1568 []*Service{ 1569 { 1570 Hostname: "bar", 1571 }, 1572 { 1573 Hostname: "barprime", 1574 }, 1575 }, 1576 nil, 1577 }, 1578 { 1579 "sidecar-with-multiple-egress-noport-with-services", 1580 configs3, 1581 services4, 1582 nil, 1583 []*Service{ 1584 { 1585 Hostname: "bar", 1586 }, 1587 { 1588 Hostname: "barprime", 1589 }, 1590 }, 1591 nil, 1592 }, 1593 { 1594 "sidecar-with-egress-port-match-with-services-with-and-without-port", 1595 configs4, 1596 services5, 1597 nil, 1598 []*Service{ 1599 { 1600 Hostname: "bar", 1601 }, 1602 }, 1603 nil, 1604 }, 1605 { 1606 "sidecar-with-egress-port-trims-service-non-matching-ports", 1607 configs5, 1608 services6, 1609 nil, 1610 []*Service{ 1611 { 1612 Hostname: "bar", 1613 Ports: port8000, 1614 }, 1615 }, 1616 nil, 1617 }, 1618 { 1619 "sidecar-with-egress-port-merges-service-ports", 1620 configs6, 1621 services6, 1622 nil, 1623 []*Service{ 1624 { 1625 Hostname: "bar", 1626 Ports: twoPorts, 1627 }, 1628 }, 1629 nil, 1630 }, 1631 { 1632 "sidecar-with-egress-port-trims-and-merges-service-ports", 1633 configs6, 1634 services7, 1635 nil, 1636 []*Service{ 1637 { 1638 Hostname: "bar", 1639 Ports: twoPorts, 1640 }, 1641 { 1642 Hostname: "barprime", 1643 Ports: port8000, 1644 }, 1645 { 1646 Hostname: "foo", 1647 Ports: twoPorts, 1648 }, 1649 }, 1650 nil, 1651 }, 1652 { 1653 "two-egresslisteners-one-with-port-and-without-port", 1654 configs7, 1655 services8, 1656 nil, 1657 []*Service{ 1658 { 1659 Hostname: "bookinginfo.com", 1660 Ports: port9999, 1661 }, 1662 { 1663 Hostname: "private.com", 1664 }, 1665 }, 1666 nil, 1667 }, 1668 // Validates when service is scoped to Sidecar, it uses service port rather than listener port. 1669 { 1670 "service-port-used-while-cloning", 1671 configs8, 1672 services9, 1673 nil, 1674 []*Service{ 1675 { 1676 Hostname: "foo.svc.cluster.local", 1677 Ports: port7443, 1678 }, 1679 }, 1680 nil, 1681 }, 1682 { 1683 "wild-card-egress-listener-match", 1684 configs9, 1685 services10, 1686 nil, 1687 []*Service{ 1688 { 1689 Hostname: "foo.svc.cluster.local", 1690 Ports: port7443, 1691 }, 1692 { 1693 Hostname: "baz.svc.cluster.local", 1694 Ports: port7443, 1695 }, 1696 { 1697 Hostname: "bar.svc.cluster.local", 1698 Ports: port7442, 1699 Attributes: ServiceAttributes{ 1700 Name: "bar", 1701 Namespace: "ns2", 1702 }, 1703 }, 1704 }, 1705 nil, 1706 }, 1707 { 1708 "wild-card-egress-listener-match-and-all-hosts", 1709 configs14, 1710 services16, 1711 nil, 1712 []*Service{ 1713 { 1714 Hostname: "foo.svc.cluster.local", 1715 Ports: port7443, 1716 }, 1717 { 1718 Hostname: "baz.svc.cluster.local", 1719 Ports: port7443, 1720 }, 1721 { 1722 Hostname: "bar.svc.cluster.local", 1723 Ports: port7442, 1724 Attributes: ServiceAttributes{ 1725 Name: "bar", 1726 Namespace: "ns2", 1727 }, 1728 }, 1729 { 1730 Hostname: "barprime.svc.cluster.local", 1731 Ports: port7442, 1732 Attributes: ServiceAttributes{ 1733 Name: "barprime", 1734 Namespace: "ns3", 1735 }, 1736 }, 1737 { 1738 Hostname: "random.svc.cluster.local", 1739 Ports: port9999, 1740 Attributes: ServiceAttributes{ 1741 Name: "random", 1742 Namespace: "randomns", // nolint 1743 }, 1744 }, 1745 }, 1746 nil, 1747 }, 1748 { 1749 "wild-card-egress-listener-match-with-two-ports", 1750 configs9, 1751 services11, 1752 nil, 1753 []*Service{ 1754 { 1755 Hostname: "foo.svc.cluster.local", 1756 Ports: port7443, 1757 }, 1758 { 1759 Hostname: "baz.svc.cluster.local", 1760 Ports: port7443, 1761 }, 1762 { 1763 Hostname: "bar.svc.cluster.local", 1764 Ports: twoMatchingPorts, 1765 Attributes: ServiceAttributes{ 1766 Name: "bar", 1767 Namespace: "ns2", 1768 }, 1769 }, 1770 }, 1771 nil, 1772 }, 1773 { 1774 "http-proxy-protocol-matches-any-port", 1775 configs10, 1776 services7, 1777 nil, 1778 []*Service{ 1779 { 1780 Hostname: "bar", 1781 }, 1782 { 1783 Hostname: "barprime", 1784 }, 1785 { 1786 Hostname: "foo", 1787 }, 1788 }, 1789 nil, 1790 }, 1791 { 1792 "virtual-service", 1793 configs11, 1794 services11, 1795 virtualServices1, 1796 []*Service{ 1797 { 1798 Hostname: "foo.svc.cluster.local", 1799 Ports: port7443, 1800 }, 1801 { 1802 Hostname: "baz.svc.cluster.local", 1803 Ports: port7443, 1804 }, 1805 }, 1806 nil, 1807 }, 1808 { 1809 "virtual-service-destinations-matching-ports", 1810 configs15, 1811 services17, 1812 virtualServices1, 1813 []*Service{ 1814 { 1815 Hostname: "foo.svc.cluster.local", 1816 Ports: port7443, 1817 }, 1818 }, 1819 nil, 1820 }, 1821 { 1822 "virtual-service-destinations-matching-http-virtual-service-ports", 1823 configs21, 1824 services21, 1825 virtualServices3, 1826 []*Service{ 1827 { 1828 Hostname: "baz.svc.cluster.local", 1829 Ports: port7000, 1830 }, 1831 { 1832 Hostname: "foo.svc.cluster.local", 1833 Ports: port7000, 1834 }, 1835 }, 1836 nil, 1837 }, 1838 { 1839 "virtual-service-destinations-matching-tcp-virtual-service-ports", 1840 configs21, 1841 services21, 1842 virtualServices4, 1843 []*Service{ 1844 { 1845 Hostname: "baz.svc.cluster.local", 1846 Ports: port7000, 1847 }, 1848 }, 1849 nil, 1850 }, 1851 { 1852 "virtual-service-destinations-matching-tls-virtual-service-ports", 1853 configs21, 1854 services21, 1855 virtualServices5, 1856 []*Service{ 1857 { 1858 Hostname: "baz.svc.cluster.local", 1859 Ports: port7000, 1860 }, 1861 }, 1862 nil, 1863 }, 1864 { 1865 "virtual-service-prefer-required", 1866 configs12, 1867 services12, 1868 virtualServices1, 1869 []*Service{ 1870 { 1871 Hostname: "foo.svc.cluster.local", 1872 // Ports should not be merged even though virtual service will select the service with 7443 1873 // as ns1 comes before ns2, because 8000 was already picked explicitly and is in different namespace 1874 Ports: port8000, 1875 }, 1876 { 1877 Hostname: "baz.svc.cluster.local", 1878 Ports: port7443, 1879 }, 1880 }, 1881 nil, 1882 }, 1883 { 1884 "virtual-service-prefer-config-namespace", 1885 configs11, 1886 services13, 1887 virtualServices1, 1888 []*Service{ 1889 { 1890 Hostname: "foo.svc.cluster.local", 1891 Ports: port8000, 1892 }, 1893 { 1894 Hostname: "baz.svc.cluster.local", 1895 Ports: port7443, 1896 }, 1897 }, 1898 nil, 1899 }, 1900 { 1901 "virtual-service-pick-alphabetical", 1902 configs11, 1903 // Ambiguous; same hostname in ns1 and ns2, neither is config namespace 1904 // ns1 should always win 1905 services12, 1906 virtualServices1, 1907 []*Service{ 1908 { 1909 Hostname: "foo.svc.cluster.local", 1910 Ports: port7443, 1911 }, 1912 { 1913 Hostname: "baz.svc.cluster.local", 1914 Ports: port7443, 1915 }, 1916 }, 1917 nil, 1918 }, 1919 { 1920 "virtual-service-pick-public", 1921 configs11, 1922 // Ambiguous; same hostname in ns1 and ns2, neither is config namespace 1923 // ns1 should always win 1924 services15, 1925 virtualServices1, 1926 []*Service{ 1927 { 1928 Hostname: "foo.svc.cluster.local", 1929 Ports: port8000, 1930 }, 1931 { 1932 Hostname: "baz.svc.cluster.local", 1933 Ports: port7443, 1934 }, 1935 }, 1936 nil, 1937 }, 1938 { 1939 "virtual-service-bad-host", 1940 configs11, 1941 services9, 1942 virtualServices1, 1943 []*Service{ 1944 { 1945 Hostname: "foo.svc.cluster.local", 1946 Ports: port7443, 1947 }, 1948 }, 1949 nil, 1950 }, 1951 { 1952 "virtual-service-destination-port-missing-from-service", 1953 configs21, 1954 services22, 1955 virtualServices3, 1956 []*Service{}, 1957 nil, 1958 }, 1959 { 1960 "virtual-service-2-match-service", 1961 configs11, 1962 services18, 1963 virtualServices2, 1964 []*Service{ 1965 { 1966 Hostname: "foo.svc.cluster.local", 1967 Ports: port7443, 1968 }, 1969 { 1970 Hostname: "baz.svc.cluster.local", 1971 Ports: port7443, 1972 }, 1973 }, 1974 nil, 1975 }, 1976 { 1977 "virtual-service-2-match-service-and-domain", 1978 configs12, 1979 services18, 1980 virtualServices2, 1981 []*Service{ 1982 { 1983 Hostname: "foo.svc.cluster.local", 1984 Ports: port7443, 1985 }, 1986 { 1987 Hostname: "baz.svc.cluster.local", 1988 Ports: port7443, 1989 }, 1990 }, 1991 nil, 1992 }, 1993 { 1994 "virtual-service-2-match-all-services", 1995 configs15, 1996 services18, 1997 virtualServices2, 1998 []*Service{ 1999 { 2000 Hostname: "foo.svc.cluster.local", 2001 Ports: port7443, 2002 }, 2003 { 2004 Hostname: "baz.svc.cluster.local", 2005 Ports: port7443, 2006 }, 2007 }, 2008 nil, 2009 }, 2010 { 2011 "sidecar-scope-with-illegal-host", 2012 configs13, 2013 services14, 2014 nil, 2015 []*Service{ 2016 { 2017 Hostname: "bar", 2018 Ports: port7443, 2019 }, 2020 }, 2021 nil, 2022 }, 2023 { 2024 "sidecar-scope-with-specific-host", 2025 configs16, 2026 services19, 2027 nil, 2028 []*Service{ 2029 { 2030 Hostname: "en.wikipedia.org", 2031 }, 2032 }, 2033 nil, 2034 }, 2035 { 2036 "sidecar-scope-with-wildcard-host", 2037 configs17, 2038 services19, 2039 nil, 2040 []*Service{ 2041 { 2042 Hostname: "en.wikipedia.org", 2043 }, 2044 { 2045 Hostname: "*.wikipedia.org", 2046 }, 2047 }, 2048 nil, 2049 }, 2050 { 2051 "sidecar-scope-with-matching-workloadselector-dr", 2052 configs18, 2053 services20, 2054 nil, 2055 []*Service{ 2056 { 2057 Hostname: "httpbin.org", 2058 Attributes: ServiceAttributes{ 2059 Namespace: "mynamespace", 2060 }, 2061 }, 2062 }, 2063 &destinationRule2, 2064 }, 2065 { 2066 "sidecar-scope-with-non-matching-workloadselector-dr", 2067 configs19, 2068 services20, 2069 nil, 2070 []*Service{ 2071 { 2072 Hostname: "httpbin.org", 2073 Attributes: ServiceAttributes{ 2074 Namespace: "mynamespace", 2075 }, 2076 }, 2077 }, 2078 &nonWorkloadSelectorDr, 2079 }, 2080 { 2081 "sidecar-scope-same-workloadselector-labels-drs-should-be-merged", 2082 configs20, 2083 services20, 2084 nil, 2085 []*Service{ 2086 { 2087 Hostname: "httpbin.org", 2088 Attributes: ServiceAttributes{ 2089 Namespace: "mynamespace", 2090 }, 2091 }, 2092 }, 2093 &mergedDr1and3, 2094 }, 2095 { 2096 name: "multi-service-merge", 2097 sidecarConfig: &config.Config{ 2098 Meta: config.Meta{ 2099 Name: "default", 2100 Namespace: "default", 2101 }, 2102 Spec: &networking.Sidecar{}, 2103 }, 2104 services: []*Service{ 2105 { 2106 Hostname: "proxy", 2107 Ports: port7000, 2108 Attributes: ServiceAttributes{ 2109 Name: "s1", 2110 Namespace: "default", 2111 }, 2112 }, 2113 { 2114 Hostname: "proxy", 2115 Ports: port7443, 2116 Attributes: ServiceAttributes{ 2117 Name: "s2", 2118 Namespace: "default", 2119 }, 2120 }, 2121 { 2122 Hostname: "proxy", 2123 Ports: port7442, 2124 Attributes: ServiceAttributes{ 2125 Name: "s3", 2126 Namespace: "default", 2127 }, 2128 }, 2129 }, 2130 expectedServices: []*Service{ 2131 { 2132 Hostname: "proxy", 2133 Ports: PortList{port7000[0], port7443[0], port7442[0]}, 2134 Attributes: ServiceAttributes{ 2135 Name: "s1", 2136 Namespace: "default", 2137 }, 2138 }, 2139 }, 2140 }, 2141 { 2142 name: "k8s service take precedence over external service", 2143 sidecarConfig: &config.Config{ 2144 Meta: config.Meta{ 2145 Name: "default", 2146 Namespace: "default", 2147 }, 2148 Spec: &networking.Sidecar{}, 2149 }, 2150 services: []*Service{ 2151 { 2152 Hostname: "proxy", 2153 Ports: port7000, 2154 Attributes: ServiceAttributes{ 2155 Name: "s1", 2156 Namespace: "default", 2157 ServiceRegistry: provider.External, 2158 }, 2159 }, 2160 { 2161 Hostname: "proxy", 2162 Ports: port7443, 2163 Attributes: ServiceAttributes{ 2164 Name: "s2", 2165 Namespace: "default", 2166 ServiceRegistry: provider.External, 2167 }, 2168 }, 2169 { 2170 Hostname: "proxy", 2171 Ports: port7442, 2172 Attributes: ServiceAttributes{ 2173 Name: "s3", 2174 Namespace: "default", 2175 ServiceRegistry: provider.Kubernetes, 2176 }, 2177 }, 2178 }, 2179 expectedServices: []*Service{ 2180 { 2181 Hostname: "proxy", 2182 Ports: port7442, 2183 Attributes: ServiceAttributes{ 2184 Name: "s3", 2185 Namespace: "default", 2186 ServiceRegistry: provider.Kubernetes, 2187 }, 2188 }, 2189 }, 2190 }, 2191 { 2192 name: "k8s service take precedence over external service, but not over k8s service", 2193 sidecarConfig: &config.Config{ 2194 Meta: config.Meta{ 2195 Name: "default", 2196 Namespace: "default", 2197 }, 2198 Spec: &networking.Sidecar{}, 2199 }, 2200 services: []*Service{ 2201 { 2202 Hostname: "proxy", 2203 Ports: port7000, 2204 Attributes: ServiceAttributes{ 2205 Name: "s1", 2206 Namespace: "default", 2207 ServiceRegistry: provider.External, 2208 }, 2209 }, 2210 { 2211 Hostname: "proxy", 2212 Ports: port7443, 2213 Attributes: ServiceAttributes{ 2214 Name: "s2", 2215 Namespace: "default", 2216 ServiceRegistry: provider.Kubernetes, 2217 }, 2218 }, 2219 { 2220 Hostname: "proxy", 2221 Ports: port7442, 2222 Attributes: ServiceAttributes{ 2223 Name: "s3", 2224 Namespace: "default", 2225 ServiceRegistry: provider.Kubernetes, 2226 }, 2227 }, 2228 }, 2229 expectedServices: []*Service{ 2230 { 2231 Hostname: "proxy", 2232 Ports: port744x, 2233 Attributes: ServiceAttributes{ 2234 Name: "s2", 2235 Namespace: "default", 2236 ServiceRegistry: provider.Kubernetes, 2237 }, 2238 }, 2239 }, 2240 }, 2241 { 2242 name: "multi-port-merge", 2243 sidecarConfig: configs22, 2244 services: services23, 2245 expectedServices: []*Service{ 2246 { 2247 Hostname: "foobar.svc.cluster.local", 2248 Ports: port803x, 2249 Attributes: ServiceAttributes{ 2250 Name: "foo", 2251 Namespace: "ns1", 2252 }, 2253 }, 2254 }, 2255 }, 2256 { 2257 name: "multi-port-merge-in-same-namespace", 2258 sidecarConfig: configs23, 2259 services: services26, 2260 expectedServices: []*Service{ 2261 { 2262 Hostname: "foobar.svc.cluster.local", 2263 Ports: port803x, 2264 Attributes: ServiceAttributes{ 2265 Name: "foo", 2266 Namespace: "ns1", 2267 }, 2268 }, 2269 }, 2270 }, 2271 { 2272 name: "multi-port-merge: serviceentry not merge with another namespace", 2273 sidecarConfig: configs22, 2274 services: []*Service{ 2275 { 2276 Hostname: "foobar.svc.cluster.local", 2277 Ports: port803x[:3], 2278 Attributes: ServiceAttributes{ 2279 Name: "foo", 2280 Namespace: "ns1", 2281 }, 2282 }, 2283 { 2284 Hostname: "foobar.svc.cluster.local", 2285 Ports: port803x[3:], 2286 Attributes: ServiceAttributes{ 2287 Name: "bar", 2288 Namespace: "ns2", 2289 }, 2290 }, 2291 { 2292 Hostname: "foobar.svc.cluster.local", 2293 Ports: port7443, 2294 Attributes: ServiceAttributes{ 2295 Name: "baz", 2296 Namespace: "ns3", 2297 }, 2298 }, 2299 }, 2300 expectedServices: []*Service{ 2301 { 2302 Hostname: "foobar.svc.cluster.local", 2303 Ports: port803x[:3], 2304 Attributes: ServiceAttributes{ 2305 Name: "foo", 2306 Namespace: "ns1", 2307 }, 2308 }, 2309 }, 2310 }, 2311 { 2312 name: "multi-port-merge: k8s service take precedence", 2313 sidecarConfig: configs22, 2314 services: []*Service{ 2315 { 2316 Hostname: "foobar.svc.cluster.local", 2317 Ports: port803x, 2318 Attributes: ServiceAttributes{ 2319 Name: "foo", 2320 Namespace: "ns1", 2321 }, 2322 }, 2323 { 2324 Hostname: "foobar.svc.cluster.local", 2325 Ports: port803x, 2326 Attributes: ServiceAttributes{ 2327 Name: "bar", 2328 Namespace: "ns2", 2329 ServiceRegistry: provider.Kubernetes, 2330 }, 2331 }, 2332 { 2333 Hostname: "foobar.svc.cluster.local", 2334 Ports: port7443, 2335 Attributes: ServiceAttributes{ 2336 Name: "baz", 2337 Namespace: "ns3", 2338 }, 2339 }, 2340 }, 2341 expectedServices: []*Service{ 2342 { 2343 Hostname: "foobar.svc.cluster.local", 2344 Ports: port803x, 2345 Attributes: ServiceAttributes{ 2346 Name: "bar", 2347 Namespace: "ns2", 2348 }, 2349 }, 2350 }, 2351 }, 2352 { 2353 name: "multi-port-merge: serviceentry merge", 2354 sidecarConfig: configs22, 2355 services: []*Service{ 2356 { 2357 Hostname: "foobar.svc.cluster.local", 2358 Ports: port803x[:3], 2359 Attributes: ServiceAttributes{ 2360 Name: "foo", 2361 Namespace: "ns1", 2362 }, 2363 }, 2364 { 2365 Hostname: "foobar.svc.cluster.local", 2366 Ports: port803x[3:], 2367 Attributes: ServiceAttributes{ 2368 Name: "bar", 2369 Namespace: "ns1", 2370 }, 2371 }, 2372 { 2373 Hostname: "foobar.svc.cluster.local", 2374 Ports: port7443, 2375 Attributes: ServiceAttributes{ 2376 Name: "baz", 2377 Namespace: "ns3", 2378 }, 2379 }, 2380 }, 2381 expectedServices: []*Service{ 2382 { 2383 Hostname: "foobar.svc.cluster.local", 2384 Ports: port803x, 2385 Attributes: ServiceAttributes{ 2386 Name: "foo", 2387 Namespace: "ns1", 2388 }, 2389 }, 2390 }, 2391 }, 2392 { 2393 name: "serviceentry not merge when resolution is different", 2394 sidecarConfig: configs22, 2395 services: []*Service{ 2396 { 2397 Hostname: "foobar.svc.cluster.local", 2398 Ports: port803x[:3], 2399 Attributes: ServiceAttributes{ 2400 Name: "foo", 2401 Namespace: "ns1", 2402 }, 2403 }, 2404 { 2405 Hostname: "foobar.svc.cluster.local", 2406 Ports: port803x[3:], 2407 Resolution: DNSLB, 2408 Attributes: ServiceAttributes{ 2409 Name: "bar", 2410 Namespace: "ns1", 2411 }, 2412 }, 2413 }, 2414 expectedServices: []*Service{ 2415 { 2416 Hostname: "foobar.svc.cluster.local", 2417 Ports: port803x[:3], 2418 Attributes: ServiceAttributes{ 2419 Name: "foo", 2420 Namespace: "ns1", 2421 }, 2422 }, 2423 }, 2424 }, 2425 { 2426 name: "serviceentry not merge when label selector is different", 2427 sidecarConfig: configs22, 2428 services: []*Service{ 2429 { 2430 Hostname: "foobar.svc.cluster.local", 2431 Ports: port803x[:3], 2432 Attributes: ServiceAttributes{ 2433 Name: "foo", 2434 Namespace: "ns1", 2435 LabelSelectors: map[string]string{ 2436 "app": "foo", 2437 }, 2438 }, 2439 }, 2440 { 2441 Hostname: "foobar.svc.cluster.local", 2442 Ports: port803x[3:], 2443 Resolution: DNSLB, 2444 Attributes: ServiceAttributes{ 2445 Name: "bar", 2446 Namespace: "ns1", 2447 LabelSelectors: map[string]string{ 2448 "app": "bar", 2449 }, 2450 }, 2451 }, 2452 }, 2453 expectedServices: []*Service{ 2454 { 2455 Hostname: "foobar.svc.cluster.local", 2456 Ports: port803x[:3], 2457 Attributes: ServiceAttributes{ 2458 Name: "foo", 2459 Namespace: "ns1", 2460 LabelSelectors: map[string]string{ 2461 "app": "foo", 2462 }, 2463 }, 2464 }, 2465 }, 2466 }, 2467 { 2468 name: "serviceentry not merge when exportTo is different", 2469 sidecarConfig: configs22, 2470 services: []*Service{ 2471 { 2472 Hostname: "foobar.svc.cluster.local", 2473 Ports: port803x[:3], 2474 Attributes: ServiceAttributes{ 2475 Name: "foo", 2476 Namespace: "ns1", 2477 ExportTo: sets.New(visibility.Public), 2478 }, 2479 }, 2480 { 2481 Hostname: "foobar.svc.cluster.local", 2482 Ports: port803x[3:], 2483 Resolution: DNSLB, 2484 Attributes: ServiceAttributes{ 2485 Name: "bar", 2486 Namespace: "ns1", 2487 ExportTo: sets.New(visibility.Private), 2488 }, 2489 }, 2490 }, 2491 expectedServices: []*Service{ 2492 { 2493 Hostname: "foobar.svc.cluster.local", 2494 Ports: port803x[:3], 2495 Attributes: ServiceAttributes{ 2496 Name: "foo", 2497 Namespace: "ns1", 2498 ExportTo: sets.New(visibility.Public), 2499 }, 2500 }, 2501 }, 2502 }, 2503 } 2504 2505 for _, tt := range tests { 2506 t.Run(tt.name, func(t *testing.T) { 2507 var serviceFound bool 2508 var portsMatched bool 2509 ps := NewPushContext() 2510 meshConfig := mesh.DefaultMeshConfig() 2511 ps.Mesh = meshConfig 2512 ps.setDestinationRules([]config.Config{destinationRule1, destinationRule2, destinationRule3, nonWorkloadSelectorDr}) 2513 if tt.services != nil { 2514 ps.ServiceIndex.public = append(ps.ServiceIndex.public, tt.services...) 2515 2516 for _, s := range tt.services { 2517 if _, f := ps.ServiceIndex.HostnameAndNamespace[s.Hostname]; !f { 2518 ps.ServiceIndex.HostnameAndNamespace[s.Hostname] = map[string]*Service{} 2519 } 2520 ps.ServiceIndex.HostnameAndNamespace[s.Hostname][s.Attributes.Namespace] = s 2521 } 2522 } 2523 if tt.virtualServices != nil { 2524 // nolint lll 2525 ps.virtualServiceIndex.publicByGateway[constants.IstioMeshGateway] = append(ps.virtualServiceIndex.publicByGateway[constants.IstioMeshGateway], tt.virtualServices...) 2526 } 2527 2528 ps.exportToDefaults = exportToDefaults{ 2529 virtualService: sets.New(visibility.Public), 2530 service: sets.New(visibility.Public), 2531 destinationRule: sets.New(visibility.Public), 2532 } 2533 2534 sidecarConfig := tt.sidecarConfig 2535 configuredListeneres := 1 2536 if sidecarConfig != nil { 2537 r := sidecarConfig.Spec.(*networking.Sidecar) 2538 if len(r.Egress) > 0 { 2539 configuredListeneres = len(r.Egress) 2540 } 2541 } 2542 2543 sidecarScope := convertToSidecarScope(ps, sidecarConfig, "mynamespace") 2544 2545 numberListeners := len(sidecarScope.EgressListeners) 2546 if numberListeners != configuredListeneres { 2547 t.Errorf("Expected %d listeners, Got: %d", configuredListeneres, numberListeners) 2548 } 2549 2550 if sidecarConfig == nil { 2551 services := sidecarScope.EgressListeners[0].services 2552 if !reflect.DeepEqual(services, sidecarScope.services) { 2553 t.Errorf("services in default egress listener not equals sidecar scope services: %v", 2554 cmp.Diff(services, sidecarScope.services, cmpopts.IgnoreFields(AddressMap{}, "mutex"))) 2555 } 2556 } 2557 2558 for _, s1 := range sidecarScope.services { 2559 serviceFound = false 2560 portsMatched = false 2561 var ports PortList 2562 for _, s2 := range tt.expectedServices { 2563 if s1.Hostname == s2.Hostname { 2564 serviceFound = true 2565 if len(s2.Ports) > 0 { 2566 if reflect.DeepEqual(s2.Ports, s1.Ports) { 2567 portsMatched = true 2568 } else { 2569 ports = s2.Ports 2570 } 2571 } 2572 break 2573 } 2574 } 2575 if !serviceFound { 2576 t.Errorf("Expected service %v in SidecarScope but not found", s1.Hostname) 2577 } else if len(ports) > 0 && !portsMatched { 2578 t.Errorf("Expected service %v found in SidecarScope but ports not merged correctly. want: %v, got: %v", s1.Hostname, ports, s1.Ports) 2579 } 2580 2581 // validate service is also in sidecarScope.serviceByHostname 2582 if s2, ok := sidecarScope.servicesByHostname[s1.Hostname]; !ok { 2583 t.Errorf("Expected service %v should also in servicesByHostname", s1.Hostname) 2584 } else if s1 != s2 { 2585 t.Errorf("Expected service %v in SidecarScope.Services should equal to that in SidecarScope.servicesByHostname", s1.Hostname) 2586 } 2587 } 2588 2589 for _, s1 := range tt.expectedServices { 2590 serviceFound = false 2591 for _, s2 := range sidecarScope.services { 2592 if s1.Hostname == s2.Hostname { 2593 serviceFound = true 2594 break 2595 } 2596 } 2597 if !serviceFound { 2598 t.Errorf("UnExpected service %v in SidecarScope", s1.Hostname) 2599 } 2600 } 2601 2602 if tt.sidecarConfig != nil { 2603 dr := sidecarScope.DestinationRule(TrafficDirectionOutbound, 2604 &Proxy{ 2605 Labels: tt.sidecarConfig.Labels, 2606 Metadata: &NodeMetadata{Labels: tt.sidecarConfig.Labels}, 2607 ConfigNamespace: tt.sidecarConfig.Namespace, 2608 }, host.Name("httpbin.org")).GetRule() 2609 assert.Equal(t, dr, tt.expectedDr) 2610 } 2611 }) 2612 } 2613 } 2614 2615 func TestIstioEgressListenerWrapper(t *testing.T) { 2616 serviceA8000 := &Service{ 2617 Hostname: "host", 2618 Ports: port8000, 2619 Attributes: ServiceAttributes{Namespace: "a"}, 2620 } 2621 serviceA9000 := &Service{ 2622 Hostname: "host", 2623 Ports: port9000, 2624 Attributes: ServiceAttributes{Namespace: "a"}, 2625 } 2626 serviceAalt := &Service{ 2627 Hostname: "alt", 2628 Ports: port8000, 2629 Attributes: ServiceAttributes{Namespace: "a"}, 2630 } 2631 2632 serviceB8000 := &Service{ 2633 Hostname: "host", 2634 Ports: port8000, 2635 Attributes: ServiceAttributes{Namespace: "b"}, 2636 } 2637 serviceB9000 := &Service{ 2638 Hostname: "host", 2639 Ports: port9000, 2640 Attributes: ServiceAttributes{Namespace: "b"}, 2641 } 2642 serviceBalt := &Service{ 2643 Hostname: "alt", 2644 Ports: port8000, 2645 Attributes: ServiceAttributes{Namespace: "b"}, 2646 } 2647 2648 serviceBWildcard := &Service{ 2649 Hostname: "*.test.wildcard.com", 2650 Ports: port8000, 2651 Attributes: ServiceAttributes{Namespace: "b"}, 2652 } 2653 allServices := []*Service{serviceA8000, serviceA9000, serviceAalt, serviceB8000, serviceB9000, serviceBalt} 2654 2655 tests := []struct { 2656 name string 2657 listenerHosts map[string]hostClassification 2658 services []*Service 2659 expected []*Service 2660 namespace string 2661 }{ 2662 { 2663 name: "*/* imports only those in a", 2664 listenerHosts: map[string]hostClassification{ 2665 wildcardNamespace: {allHosts: []host.Name{wildcardService}, exactHosts: sets.New[host.Name]()}, 2666 }, 2667 services: allServices, 2668 expected: []*Service{serviceA8000, serviceA9000, serviceAalt}, 2669 namespace: "a", 2670 }, 2671 { 2672 name: "*/* will bias towards configNamespace", 2673 listenerHosts: map[string]hostClassification{ 2674 wildcardNamespace: {allHosts: []host.Name{wildcardService}, exactHosts: sets.New[host.Name]()}, 2675 }, 2676 services: []*Service{serviceB8000, serviceB9000, serviceBalt, serviceA8000, serviceA9000, serviceAalt}, 2677 expected: []*Service{serviceA8000, serviceA9000, serviceAalt}, 2678 namespace: "a", 2679 }, 2680 { 2681 name: "a/* imports only those in a", 2682 listenerHosts: map[string]hostClassification{ 2683 "a": {allHosts: []host.Name{wildcardService}, exactHosts: sets.New[host.Name]()}, 2684 }, 2685 services: allServices, 2686 expected: []*Service{serviceA8000, serviceA9000, serviceAalt}, 2687 namespace: "a", 2688 }, 2689 { 2690 name: "b/*, b/* imports only those in b", 2691 listenerHosts: map[string]hostClassification{ 2692 "b": {allHosts: []host.Name{wildcardService, wildcardService}, exactHosts: sets.New[host.Name]()}, 2693 }, 2694 services: allServices, 2695 expected: []*Service{serviceB8000, serviceB9000, serviceBalt}, 2696 namespace: "a", 2697 }, 2698 { 2699 name: "*/alt imports alt in namespace a", 2700 listenerHosts: map[string]hostClassification{ 2701 wildcardNamespace: {allHosts: []host.Name{"alt"}, exactHosts: sets.New[host.Name]("alt")}, 2702 }, 2703 services: allServices, 2704 expected: []*Service{serviceAalt}, 2705 namespace: "a", 2706 }, 2707 { 2708 name: "b/alt imports alt in a namespaces", 2709 listenerHosts: map[string]hostClassification{ 2710 "b": {allHosts: []host.Name{"alt"}, exactHosts: sets.New[host.Name]("alt")}, 2711 }, 2712 services: allServices, 2713 expected: []*Service{serviceBalt}, 2714 namespace: "a", 2715 }, 2716 { 2717 name: "b/* imports doesn't import in namespace a with proxy in a", 2718 listenerHosts: map[string]hostClassification{ 2719 "b": {allHosts: []host.Name{wildcardService}, exactHosts: sets.New[host.Name]()}, 2720 }, 2721 services: []*Service{serviceA8000}, 2722 expected: []*Service{}, 2723 namespace: "a", 2724 }, 2725 { 2726 name: "multiple hosts selected same service", 2727 listenerHosts: map[string]hostClassification{ 2728 "a": {allHosts: []host.Name{wildcardService}, exactHosts: sets.New[host.Name]()}, 2729 "*": {allHosts: []host.Name{wildcardService}, exactHosts: sets.New[host.Name]()}, 2730 }, 2731 services: []*Service{serviceA8000}, 2732 expected: []*Service{serviceA8000}, 2733 namespace: "a", 2734 }, 2735 { 2736 name: "fall back to wildcard namespace", 2737 listenerHosts: map[string]hostClassification{ 2738 wildcardNamespace: {allHosts: []host.Name{"host"}, exactHosts: sets.New[host.Name]("host")}, 2739 "a": {allHosts: []host.Name{"alt"}, exactHosts: sets.New[host.Name]("alt")}, 2740 }, 2741 services: allServices, 2742 expected: []*Service{serviceA8000, serviceA9000, serviceAalt}, 2743 namespace: "a", 2744 }, 2745 { 2746 name: "service is wildcard, but not listener's subset", 2747 listenerHosts: map[string]hostClassification{ 2748 "b": {allHosts: []host.Name{"wildcard.com"}, exactHosts: sets.New[host.Name]("wildcard.com")}, 2749 }, 2750 services: []*Service{serviceBWildcard}, 2751 expected: []*Service{}, 2752 namespace: "b", 2753 }, 2754 { 2755 name: "service is wildcard", 2756 listenerHosts: map[string]hostClassification{ 2757 "b": {allHosts: []host.Name{"*.wildcard.com"}, exactHosts: sets.New[host.Name]()}, 2758 }, 2759 services: []*Service{serviceBWildcard}, 2760 expected: []*Service{serviceBWildcard}, 2761 namespace: "b", 2762 }, 2763 } 2764 2765 for _, tt := range tests { 2766 t.Run(tt.name, func(t *testing.T) { 2767 ilw := &IstioEgressListenerWrapper{} 2768 got := ilw.selectServices(tt.services, tt.namespace, tt.listenerHosts) 2769 if !reflect.DeepEqual(got, tt.expected) { 2770 gots, _ := json.MarshalIndent(got, "", " ") 2771 expecteds, _ := json.MarshalIndent(tt.expected, "", " ") 2772 t.Errorf("Got %v, expected %v", string(gots), string(expecteds)) 2773 } 2774 }) 2775 } 2776 } 2777 2778 func TestContainsEgressDependencies(t *testing.T) { 2779 const ( 2780 svcName = "svc1.com" 2781 nsName = "ns" 2782 drName = "dr1" 2783 vsName = "vs1" 2784 ) 2785 2786 allContains := func(ns string, contains bool) map[ConfigKey]bool { 2787 return map[ConfigKey]bool{ 2788 {kind.ServiceEntry, svcName, ns}: contains, 2789 {kind.VirtualService, vsName, ns}: contains, 2790 {kind.DestinationRule, drName, ns}: contains, 2791 } 2792 } 2793 2794 cases := []struct { 2795 name string 2796 egress []string 2797 2798 contains map[ConfigKey]bool 2799 }{ 2800 {"Just wildcard", []string{"*/*"}, allContains(nsName, true)}, 2801 {"Namespace and wildcard", []string{"ns/*", "*/*"}, allContains(nsName, true)}, 2802 {"Just Namespace", []string{"ns/*"}, allContains(nsName, true)}, 2803 {"Wrong Namespace", []string{"ns/*"}, allContains("other-ns", false)}, 2804 {"No Sidecar", nil, allContains("ns", true)}, 2805 {"No Sidecar Other Namespace", nil, allContains("other-ns", false)}, 2806 {"clusterScope resource", []string{"*/*"}, map[ConfigKey]bool{ 2807 {kind.AuthorizationPolicy, "authz", "default"}: true, 2808 }}, 2809 } 2810 for _, tt := range cases { 2811 t.Run(tt.name, func(t *testing.T) { 2812 cfg := &config.Config{ 2813 Meta: config.Meta{ 2814 Name: "foo", 2815 Namespace: "default", 2816 }, 2817 Spec: &networking.Sidecar{ 2818 Egress: []*networking.IstioEgressListener{ 2819 { 2820 Hosts: tt.egress, 2821 }, 2822 }, 2823 }, 2824 } 2825 ps := NewPushContext() 2826 meshConfig := mesh.DefaultMeshConfig() 2827 ps.Mesh = meshConfig 2828 2829 services := []*Service{ 2830 { 2831 Hostname: "nomatch", 2832 Attributes: ServiceAttributes{Namespace: "nomatch"}, 2833 }, 2834 { 2835 Hostname: svcName, 2836 Attributes: ServiceAttributes{Namespace: nsName}, 2837 }, 2838 } 2839 virtualServices := []config.Config{ 2840 { 2841 Meta: config.Meta{ 2842 Name: vsName, 2843 Namespace: nsName, 2844 }, 2845 Spec: &networking.VirtualService{ 2846 Hosts: []string{svcName}, 2847 }, 2848 }, 2849 } 2850 destinationRules := []config.Config{ 2851 { 2852 Meta: config.Meta{ 2853 Name: drName, 2854 Namespace: nsName, 2855 }, 2856 Spec: &networking.DestinationRule{ 2857 Host: svcName, 2858 ExportTo: []string{"*"}, 2859 }, 2860 }, 2861 } 2862 ps.ServiceIndex.public = append(ps.ServiceIndex.public, services...) 2863 // nolint lll 2864 ps.virtualServiceIndex.publicByGateway[constants.IstioMeshGateway] = append(ps.virtualServiceIndex.publicByGateway[constants.IstioMeshGateway], virtualServices...) 2865 ps.setDestinationRules(destinationRules) 2866 sidecarScope := convertToSidecarScope(ps, cfg, "default") 2867 if len(tt.egress) == 0 { 2868 sidecarScope = DefaultSidecarScopeForNamespace(ps, "default") 2869 } 2870 2871 for k, v := range tt.contains { 2872 if ok := sidecarScope.DependsOnConfig(k, ps.Mesh.RootNamespace); ok != v { 2873 t.Fatalf("Expected contains %v-%v, but no match", k, v) 2874 } 2875 } 2876 }) 2877 } 2878 } 2879 2880 func TestRootNsSidecarDependencies(t *testing.T) { 2881 cases := []struct { 2882 name string 2883 egress []string 2884 2885 contains map[ConfigKey]bool 2886 }{ 2887 {"AuthorizationPolicy in the same ns as workload", []string{"*/*"}, map[ConfigKey]bool{ 2888 {kind.AuthorizationPolicy, "authz", "default"}: true, 2889 }}, 2890 {"AuthorizationPolicy in a different ns from workload", []string{"*/*"}, map[ConfigKey]bool{ 2891 {kind.AuthorizationPolicy, "authz", "ns1"}: false, 2892 }}, 2893 {"AuthorizationPolicy in the root namespace", []string{"*/*"}, map[ConfigKey]bool{ 2894 {kind.AuthorizationPolicy, "authz", constants.IstioSystemNamespace}: true, 2895 }}, 2896 {"WasmPlugin in same ns as workload", []string{"*/*"}, map[ConfigKey]bool{ 2897 {kind.WasmPlugin, "wasm", "default"}: true, 2898 }}, 2899 {"WasmPlugin in different ns from workload", []string{"*/*"}, map[ConfigKey]bool{ 2900 {kind.WasmPlugin, "wasm", "ns1"}: false, 2901 }}, 2902 {"WasmPlugin in the root namespace", []string{"*/*"}, map[ConfigKey]bool{ 2903 {kind.WasmPlugin, "wasm", constants.IstioSystemNamespace}: true, 2904 }}, 2905 } 2906 2907 for _, tt := range cases { 2908 t.Run(tt.name, func(t *testing.T) { 2909 cfg := &config.Config{ 2910 Meta: config.Meta{ 2911 Name: "foo", 2912 Namespace: constants.IstioSystemNamespace, 2913 }, 2914 Spec: &networking.Sidecar{ 2915 Egress: []*networking.IstioEgressListener{ 2916 { 2917 Hosts: tt.egress, 2918 }, 2919 }, 2920 }, 2921 } 2922 ps := NewPushContext() 2923 meshConfig := mesh.DefaultMeshConfig() 2924 ps.Mesh = meshConfig 2925 sidecarScope := convertToSidecarScope(ps, cfg, "default") 2926 if len(tt.egress) == 0 { 2927 sidecarScope = DefaultSidecarScopeForNamespace(ps, "default") 2928 } 2929 2930 for k, v := range tt.contains { 2931 if ok := sidecarScope.DependsOnConfig(k, ps.Mesh.RootNamespace); ok != v { 2932 t.Fatalf("Expected contains %v-%v, but no match", k, v) 2933 } 2934 } 2935 }) 2936 } 2937 } 2938 2939 func TestSidecarOutboundTrafficPolicy(t *testing.T) { 2940 configWithoutOutboundTrafficPolicy := &config.Config{ 2941 Meta: config.Meta{ 2942 Name: "foo", 2943 Namespace: "not-default", 2944 }, 2945 Spec: &networking.Sidecar{}, 2946 } 2947 configRegistryOnly := &config.Config{ 2948 Meta: config.Meta{ 2949 Name: "foo", 2950 Namespace: "not-default", 2951 }, 2952 Spec: &networking.Sidecar{ 2953 OutboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 2954 Mode: networking.OutboundTrafficPolicy_REGISTRY_ONLY, 2955 }, 2956 }, 2957 } 2958 configAllowAny := &config.Config{ 2959 Meta: config.Meta{ 2960 Name: "foo", 2961 Namespace: "not-default", 2962 }, 2963 Spec: &networking.Sidecar{ 2964 OutboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 2965 Mode: networking.OutboundTrafficPolicy_ALLOW_ANY, 2966 }, 2967 }, 2968 } 2969 2970 meshConfigWithRegistryOnly, err := mesh.ApplyMeshConfigDefaults(` 2971 outboundTrafficPolicy: 2972 mode: REGISTRY_ONLY 2973 `) 2974 if err != nil { 2975 t.Fatalf("unexpected error reading test mesh config: %v", err) 2976 } 2977 2978 tests := []struct { 2979 name string 2980 meshConfig *v1alpha1.MeshConfig 2981 sidecar *config.Config 2982 outboundTrafficPolicy *networking.OutboundTrafficPolicy 2983 }{ 2984 { 2985 name: "default MeshConfig, no Sidecar", 2986 meshConfig: mesh.DefaultMeshConfig(), 2987 sidecar: nil, 2988 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 2989 Mode: networking.OutboundTrafficPolicy_ALLOW_ANY, 2990 }, 2991 }, 2992 { 2993 name: "default MeshConfig, sidecar without OutboundTrafficPolicy", 2994 meshConfig: mesh.DefaultMeshConfig(), 2995 sidecar: configWithoutOutboundTrafficPolicy, 2996 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 2997 Mode: networking.OutboundTrafficPolicy_ALLOW_ANY, 2998 }, 2999 }, 3000 { 3001 name: "default MeshConfig, Sidecar with registry only", 3002 meshConfig: mesh.DefaultMeshConfig(), 3003 sidecar: configRegistryOnly, 3004 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 3005 Mode: networking.OutboundTrafficPolicy_REGISTRY_ONLY, 3006 }, 3007 }, 3008 { 3009 name: "default MeshConfig, Sidecar with allow any", 3010 meshConfig: mesh.DefaultMeshConfig(), 3011 sidecar: configAllowAny, 3012 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 3013 Mode: networking.OutboundTrafficPolicy_ALLOW_ANY, 3014 }, 3015 }, 3016 { 3017 name: "MeshConfig registry only, no Sidecar", 3018 meshConfig: meshConfigWithRegistryOnly, 3019 sidecar: nil, 3020 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 3021 Mode: networking.OutboundTrafficPolicy_REGISTRY_ONLY, 3022 }, 3023 }, 3024 { 3025 name: "MeshConfig registry only, sidecar without OutboundTrafficPolicy", 3026 meshConfig: meshConfigWithRegistryOnly, 3027 sidecar: configWithoutOutboundTrafficPolicy, 3028 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 3029 Mode: networking.OutboundTrafficPolicy_REGISTRY_ONLY, 3030 }, 3031 }, 3032 { 3033 name: "MeshConfig registry only, Sidecar with registry only", 3034 meshConfig: meshConfigWithRegistryOnly, 3035 sidecar: configRegistryOnly, 3036 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 3037 Mode: networking.OutboundTrafficPolicy_REGISTRY_ONLY, 3038 }, 3039 }, 3040 { 3041 name: "MeshConfig registry only, Sidecar with allow any", 3042 meshConfig: meshConfigWithRegistryOnly, 3043 sidecar: configAllowAny, 3044 outboundTrafficPolicy: &networking.OutboundTrafficPolicy{ 3045 Mode: networking.OutboundTrafficPolicy_ALLOW_ANY, 3046 }, 3047 }, 3048 } 3049 3050 for i, test := range tests { 3051 t.Run(test.name, func(t *testing.T) { 3052 ps := NewPushContext() 3053 ps.Mesh = tests[i].meshConfig 3054 3055 var sidecarScope *SidecarScope 3056 if test.sidecar == nil { 3057 sidecarScope = DefaultSidecarScopeForNamespace(ps, "not-default") 3058 } else { 3059 sidecarScope = convertToSidecarScope(ps, test.sidecar, test.sidecar.Namespace) 3060 } 3061 3062 if !reflect.DeepEqual(test.outboundTrafficPolicy, sidecarScope.OutboundTrafficPolicy) { 3063 t.Errorf("Unexpected sidecar outbound traffic, want %v, found %v", 3064 test.outboundTrafficPolicy, sidecarScope.OutboundTrafficPolicy) 3065 } 3066 }) 3067 } 3068 } 3069 3070 func TestInboundConnectionPoolForPort(t *testing.T) { 3071 connectionPoolSettings := &networking.ConnectionPoolSettings{ 3072 Http: &networking.ConnectionPoolSettings_HTTPSettings{ 3073 Http1MaxPendingRequests: 1024, 3074 Http2MaxRequests: 1024, 3075 MaxRequestsPerConnection: 1024, 3076 MaxRetries: 1024, 3077 IdleTimeout: durationpb.New(5 * time.Second), 3078 H2UpgradePolicy: networking.ConnectionPoolSettings_HTTPSettings_UPGRADE, 3079 }, 3080 Tcp: &networking.ConnectionPoolSettings_TCPSettings{ 3081 MaxConnections: 1024, 3082 ConnectTimeout: durationpb.New(6 * time.Second), 3083 TcpKeepalive: &networking.ConnectionPoolSettings_TCPSettings_TcpKeepalive{ 3084 Probes: 3, 3085 Time: durationpb.New(7 * time.Second), 3086 Interval: durationpb.New(8 * time.Second), 3087 }, 3088 MaxConnectionDuration: durationpb.New(9 * time.Second), 3089 }, 3090 } 3091 3092 overrideConnectionPool := &networking.ConnectionPoolSettings{ 3093 Http: &networking.ConnectionPoolSettings_HTTPSettings{ 3094 Http1MaxPendingRequests: 1, 3095 Http2MaxRequests: 2, 3096 MaxRequestsPerConnection: 3, 3097 MaxRetries: 4, 3098 IdleTimeout: durationpb.New(1 * time.Second), 3099 H2UpgradePolicy: networking.ConnectionPoolSettings_HTTPSettings_DO_NOT_UPGRADE, 3100 }, 3101 } 3102 3103 tests := map[string]struct { 3104 sidecar *networking.Sidecar 3105 // port to settings map 3106 want map[int]*networking.ConnectionPoolSettings 3107 }{ 3108 "no settings": { 3109 sidecar: &networking.Sidecar{}, 3110 want: map[int]*networking.ConnectionPoolSettings{ 3111 22: nil, 3112 80: nil, 3113 443: nil, 3114 }, 3115 }, 3116 "no settings multiple ports": { 3117 sidecar: &networking.Sidecar{ 3118 Ingress: []*networking.IstioIngressListener{ 3119 { 3120 Port: &networking.SidecarPort{ 3121 Number: 80, 3122 Protocol: "HTTP", 3123 Name: "http", 3124 }, 3125 }, 3126 { 3127 Port: &networking.SidecarPort{ 3128 Number: 443, 3129 Protocol: "HTTPS", 3130 Name: "https", 3131 }, 3132 }, 3133 }, 3134 }, 3135 want: map[int]*networking.ConnectionPoolSettings{ 3136 22: nil, 3137 80: nil, 3138 443: nil, 3139 }, 3140 }, 3141 "single port with settings": { 3142 sidecar: &networking.Sidecar{ 3143 Ingress: []*networking.IstioIngressListener{ 3144 { 3145 Port: &networking.SidecarPort{ 3146 Number: 80, 3147 Protocol: "HTTP", 3148 Name: "http", 3149 }, 3150 ConnectionPool: connectionPoolSettings, 3151 }, 3152 }, 3153 }, 3154 want: map[int]*networking.ConnectionPoolSettings{ 3155 22: nil, 3156 80: connectionPoolSettings, 3157 443: nil, 3158 }, 3159 }, 3160 "top level settings": { 3161 sidecar: &networking.Sidecar{ 3162 InboundConnectionPool: connectionPoolSettings, 3163 Ingress: []*networking.IstioIngressListener{ 3164 { 3165 Port: &networking.SidecarPort{ 3166 Number: 80, 3167 Protocol: "HTTP", 3168 Name: "http", 3169 }, 3170 }, 3171 }, 3172 }, 3173 want: map[int]*networking.ConnectionPoolSettings{ 3174 // with a default setting on the sidecar, we'll return it for any port we're asked about 3175 22: connectionPoolSettings, 3176 80: connectionPoolSettings, 3177 443: connectionPoolSettings, 3178 }, 3179 }, 3180 "port settings override top level": { 3181 sidecar: &networking.Sidecar{ 3182 InboundConnectionPool: connectionPoolSettings, 3183 Ingress: []*networking.IstioIngressListener{ 3184 { 3185 Port: &networking.SidecarPort{ 3186 Number: 80, 3187 Protocol: "HTTP", 3188 Name: "http", 3189 }, 3190 ConnectionPool: overrideConnectionPool, 3191 }, 3192 }, 3193 }, 3194 want: map[int]*networking.ConnectionPoolSettings{ 3195 // with a default setting on the sidecar, we'll return it for any port we're asked about 3196 22: connectionPoolSettings, 3197 80: overrideConnectionPool, 3198 443: connectionPoolSettings, 3199 }, 3200 }, 3201 } 3202 for name, tt := range tests { 3203 t.Run(name, func(t *testing.T) { 3204 ps := NewPushContext() 3205 ps.Mesh = mesh.DefaultMeshConfig() 3206 3207 sidecar := &config.Config{ 3208 Meta: config.Meta{ 3209 GroupVersionKind: gvk.Sidecar, 3210 Name: "sidecar", 3211 Namespace: strings.Replace(name, " ", "-", -1), 3212 }, 3213 Spec: tt.sidecar, 3214 } 3215 scope := convertToSidecarScope(ps, sidecar, sidecar.Namespace) 3216 3217 for port, expected := range tt.want { 3218 actual := scope.InboundConnectionPoolForPort(port) 3219 if !reflect.DeepEqual(actual, expected) { 3220 t.Errorf("for port %d, wanted %#v but got: %#v", port, expected, actual) 3221 } 3222 } 3223 }) 3224 } 3225 } 3226 3227 func BenchmarkConvertIstioListenerToWrapper(b *testing.B) { 3228 b.Run("small-exact", func(b *testing.B) { 3229 benchmarkConvertIstioListenerToWrapper(b, 10, 3, "", false) 3230 }) 3231 b.Run("small-wildcard", func(b *testing.B) { 3232 benchmarkConvertIstioListenerToWrapper(b, 10, 3, "*.", false) 3233 }) 3234 b.Run("small-match-all", func(b *testing.B) { 3235 benchmarkConvertIstioListenerToWrapper(b, 10, 3, "", true) 3236 }) 3237 3238 b.Run("middle-exact", func(b *testing.B) { 3239 benchmarkConvertIstioListenerToWrapper(b, 100, 10, "", false) 3240 }) 3241 b.Run("middle-wildcard", func(b *testing.B) { 3242 benchmarkConvertIstioListenerToWrapper(b, 100, 10, "*.", false) 3243 }) 3244 b.Run("middle-match-all", func(b *testing.B) { 3245 benchmarkConvertIstioListenerToWrapper(b, 100, 10, "", true) 3246 }) 3247 3248 b.Run("big-exact", func(b *testing.B) { 3249 benchmarkConvertIstioListenerToWrapper(b, 300, 15, "", false) 3250 }) 3251 b.Run("big-wildcard", func(b *testing.B) { 3252 benchmarkConvertIstioListenerToWrapper(b, 300, 15, "*.", false) 3253 }) 3254 b.Run("big-match-all", func(b *testing.B) { 3255 benchmarkConvertIstioListenerToWrapper(b, 300, 15, "", true) 3256 }) 3257 } 3258 3259 func benchmarkConvertIstioListenerToWrapper(b *testing.B, vsNum int, hostNum int, wildcard string, matchAll bool) { 3260 // virtual service 3261 cfgs := make([]config.Config, 0) 3262 for i := 0; i < vsNum; i++ { 3263 cfgs = append(cfgs, config.Config{ 3264 Meta: config.Meta{ 3265 GroupVersionKind: gvk.VirtualService, 3266 Name: "vs-name-" + strconv.Itoa(i), 3267 Namespace: "default", 3268 }, 3269 Spec: &networking.VirtualService{ 3270 Hosts: []string{"host-" + strconv.Itoa(i) + ".com"}, 3271 }, 3272 }) 3273 } 3274 ps := NewPushContext() 3275 ps.virtualServiceIndex.publicByGateway[constants.IstioMeshGateway] = cfgs 3276 3277 // service 3278 svcList := make([]*Service, 0, vsNum) 3279 for i := 0; i < vsNum; i++ { 3280 svcList = append(svcList, &Service{ 3281 Attributes: ServiceAttributes{Namespace: "default"}, 3282 Hostname: host.Name("host-" + strconv.Itoa(i) + ".com"), 3283 }) 3284 } 3285 ps.ServiceIndex.public = svcList 3286 3287 hosts := make([]string, 0) 3288 if matchAll { 3289 // default/* 3290 hosts = append(hosts, "default/*") 3291 } else { 3292 // default/xx or default/*.xx 3293 for i := 0; i < hostNum; i++ { 3294 h := "default/" + wildcard + "host-" + strconv.Itoa(i) + ".com" 3295 hosts = append(hosts, h) 3296 } 3297 } 3298 3299 istioListener := &networking.IstioEgressListener{ 3300 Hosts: hosts, 3301 } 3302 3303 b.ResetTimer() 3304 for i := 0; i < b.N; i++ { 3305 convertIstioListenerToWrapper(ps, "default", istioListener) 3306 } 3307 } 3308 3309 func TestComputeWildcardHostVirtualServiceIndex(t *testing.T) { 3310 oldestTime := time.Now().Add(-2 * time.Hour) 3311 olderTime := time.Now().Add(-1 * time.Hour) 3312 newerTime := time.Now() 3313 virtualServices := []config.Config{ 3314 { 3315 Meta: config.Meta{ 3316 Name: "foo", 3317 Namespace: "default", 3318 CreationTimestamp: newerTime, 3319 }, 3320 Spec: &networking.VirtualService{ 3321 Hosts: []string{"foo.example.com"}, 3322 }, 3323 }, 3324 { 3325 Meta: config.Meta{ 3326 Name: "foo2", 3327 Namespace: "default", 3328 CreationTimestamp: olderTime.Add(30 * time.Minute), // This should not be used despite being older than foo 3329 }, 3330 Spec: &networking.VirtualService{ 3331 Hosts: []string{"foo.example.com"}, 3332 }, 3333 }, 3334 { 3335 Meta: config.Meta{ 3336 Name: "wild", 3337 Namespace: "default", 3338 CreationTimestamp: olderTime, 3339 }, 3340 Spec: &networking.VirtualService{ 3341 Hosts: []string{"*.example.com"}, 3342 }, 3343 }, 3344 { 3345 Meta: config.Meta{ 3346 Name: "barwild", 3347 Namespace: "default", 3348 CreationTimestamp: oldestTime, 3349 }, 3350 Spec: &networking.VirtualService{ 3351 Hosts: []string{"*.bar.example.com"}, 3352 }, 3353 }, 3354 { 3355 Meta: config.Meta{ 3356 Name: "barwild2", 3357 Namespace: "default", 3358 CreationTimestamp: olderTime, 3359 }, 3360 Spec: &networking.VirtualService{ 3361 Hosts: []string{"*.bar.example.com"}, 3362 }, 3363 }, 3364 } 3365 3366 services := []*Service{ 3367 { 3368 Hostname: "foo.example.com", 3369 }, 3370 { 3371 Hostname: "baz.example.com", 3372 }, 3373 { 3374 Hostname: "qux.bar.example.com", 3375 }, 3376 { 3377 Hostname: "*.bar.example.com", 3378 }, 3379 } 3380 3381 tests := []struct { 3382 name string 3383 virtualServices []config.Config 3384 services []*Service 3385 expectedIndex map[host.Name]types.NamespacedName 3386 oldestWins bool 3387 }{ 3388 { 3389 name: "most specific", 3390 virtualServices: virtualServices, 3391 services: services, 3392 expectedIndex: map[host.Name]types.NamespacedName{ 3393 "foo.example.com": {Name: "foo", Namespace: "default"}, 3394 "baz.example.com": {Name: "wild", Namespace: "default"}, 3395 "qux.bar.example.com": {Name: "barwild", Namespace: "default"}, 3396 "*.bar.example.com": {Name: "barwild", Namespace: "default"}, 3397 }, 3398 }, 3399 { 3400 name: "oldest wins", 3401 virtualServices: virtualServices, 3402 services: services, 3403 expectedIndex: map[host.Name]types.NamespacedName{ 3404 "foo.example.com": {Name: "wild", Namespace: "default"}, 3405 "baz.example.com": {Name: "wild", Namespace: "default"}, 3406 "qux.bar.example.com": {Name: "barwild", Namespace: "default"}, 3407 "*.bar.example.com": {Name: "barwild", Namespace: "default"}, 3408 }, 3409 oldestWins: true, 3410 }, 3411 } 3412 3413 for _, tt := range tests { 3414 t.Run(tt.name, func(t *testing.T) { 3415 if tt.oldestWins { 3416 test.SetForTest(t, &features.PersistOldestWinsHeuristicForVirtualServiceHostMatching, true) 3417 } 3418 index := computeWildcardHostVirtualServiceIndex(tt.virtualServices, tt.services) 3419 if !reflect.DeepEqual(tt.expectedIndex, index) { 3420 t.Errorf("Expected index %v, got %v", tt.expectedIndex, index) 3421 } 3422 }) 3423 } 3424 }