istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/networking/core/gateway_simulation_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 core_test 16 17 import ( 18 "testing" 19 20 "istio.io/istio/pilot/pkg/model" 21 "istio.io/istio/pilot/pkg/simulation" 22 "istio.io/istio/pilot/test/xds" 23 "istio.io/istio/pilot/test/xdstest" 24 "istio.io/istio/pkg/env" 25 "istio.io/istio/pkg/test/util/tmpl" 26 ) 27 28 func TestDisablePortTranslation(t *testing.T) { 29 virtualServices := ` 30 apiVersion: networking.istio.io/v1alpha3 31 kind: VirtualService 32 metadata: 33 name: a 34 spec: 35 hosts: 36 - "example.com" 37 gateways: 38 - gateway80 39 - gateway8081 40 http: 41 - match: 42 - uri: 43 prefix: / 44 route: 45 - destination: 46 host: a 47 port: 48 number: 80 49 --- 50 apiVersion: networking.istio.io/v1alpha3 51 kind: VirtualService 52 metadata: 53 name: b 54 spec: 55 hosts: 56 - "example.com" 57 gateways: 58 - gateway80 59 - gateway8081 60 http: 61 - match: 62 - uri: 63 prefix: / 64 route: 65 - destination: 66 host: b 67 port: 68 number: 8081` 69 runGatewayTest(t, 70 simulationTest{ 71 name: "multiple target port, target port first", 72 config: createGateway("gateway80", "", ` 73 port: 74 number: 80 75 name: http 76 protocol: HTTP 77 hosts: 78 - "example.com" 79 `) + createGateway("gateway8081", "", ` 80 port: 81 number: 8081 82 name: http 83 protocol: HTTP 84 hosts: 85 - "example.com" 86 `) + ` 87 --- 88 apiVersion: networking.istio.io/v1alpha3 89 kind: ServiceEntry 90 metadata: 91 name: service-instance 92 namespace: istio-system 93 labels: 94 experimental.istio.io/disable-gateway-port-translation: "true" 95 spec: 96 hosts: ["a.example.com"] 97 ports: 98 - number: 80 99 targetPort: 8081 100 name: http 101 protocol: HTTP 102 resolution: STATIC 103 location: MESH_INTERNAL 104 endpoints: 105 - address: 1.1.1.1 106 labels: 107 istio: ingressgateway 108 --- 109 apiVersion: networking.istio.io/v1alpha3 110 kind: ServiceEntry 111 metadata: 112 name: service-instance-2 113 namespace: istio-system 114 spec: 115 hosts: ["b.example.com"] 116 ports: 117 - number: 80 118 targetPort: 8080 119 name: http 120 protocol: HTTP 121 resolution: STATIC 122 location: MESH_INTERNAL 123 endpoints: 124 - address: 1.1.1.1 125 labels: 126 istio: ingressgateway 127 --- 128 ` + virtualServices, 129 calls: []simulation.Expect{ 130 { 131 Name: "target port 1", 132 Call: simulation.Call{ 133 Port: 8080, 134 HostHeader: "example.com", 135 Protocol: simulation.HTTP, 136 }, 137 Result: simulation.Result{ 138 ListenerMatched: "0.0.0.0_8080", 139 ClusterMatched: "outbound|80||a.default", 140 RouteConfigMatched: "http.8080", 141 VirtualHostMatched: "example.com:80", 142 }, 143 }, 144 { 145 Name: "target port 2", 146 Call: simulation.Call{ 147 Port: 8081, 148 HostHeader: "example.com", 149 Protocol: simulation.HTTP, 150 }, 151 Result: simulation.Result{ 152 ListenerMatched: "0.0.0.0_8081", 153 ClusterMatched: "outbound|80||a.default", 154 RouteConfigMatched: "http.8081", 155 VirtualHostMatched: "example.com:8081", 156 }, 157 }, 158 }, 159 }, 160 simulationTest{ 161 name: "multiple target port, service port first", 162 config: createGateway("gateway80", "", ` 163 port: 164 number: 80 165 name: http 166 protocol: HTTP 167 hosts: 168 - "example.com" 169 `) + createGateway("gateway8081", "", ` 170 port: 171 number: 8081 172 name: http 173 protocol: HTTP 174 hosts: 175 - "example.com" 176 `) + ` 177 --- 178 apiVersion: networking.istio.io/v1alpha3 179 kind: ServiceEntry 180 metadata: 181 name: service-instance 182 namespace: istio-system 183 labels: 184 experimental.istio.io/disable-gateway-port-translation: "true" 185 spec: 186 hosts: ["b.example.com"] 187 ports: 188 - number: 80 189 targetPort: 8081 190 name: http 191 protocol: HTTP 192 resolution: STATIC 193 location: MESH_INTERNAL 194 endpoints: 195 - address: 1.1.1.1 196 labels: 197 istio: ingressgateway 198 --- 199 apiVersion: networking.istio.io/v1alpha3 200 kind: ServiceEntry 201 metadata: 202 name: service-instance-2 203 namespace: istio-system 204 spec: 205 hosts: ["a.example.com"] 206 ports: 207 - number: 80 208 targetPort: 8080 209 name: http 210 protocol: HTTP 211 resolution: STATIC 212 location: MESH_INTERNAL 213 endpoints: 214 - address: 1.1.1.1 215 labels: 216 istio: ingressgateway 217 --- 218 ` + virtualServices, 219 calls: []simulation.Expect{ 220 { 221 Name: "target port 1", 222 Call: simulation.Call{ 223 Port: 8080, 224 HostHeader: "example.com", 225 Protocol: simulation.HTTP, 226 }, 227 Result: simulation.Result{ 228 ListenerMatched: "0.0.0.0_8080", 229 ClusterMatched: "outbound|80||a.default", 230 RouteConfigMatched: "http.8080", 231 VirtualHostMatched: "example.com:80", 232 }, 233 }, 234 { 235 Name: "target port 2", 236 Call: simulation.Call{ 237 Port: 8081, 238 HostHeader: "example.com", 239 Protocol: simulation.HTTP, 240 }, 241 Result: simulation.Result{ 242 ListenerMatched: "0.0.0.0_8081", 243 ClusterMatched: "outbound|80||a.default", 244 RouteConfigMatched: "http.8081", 245 VirtualHostMatched: "example.com:8081", 246 }, 247 }, 248 }, 249 }) 250 } 251 252 func TestHTTPGateway(t *testing.T) { 253 httpServer := `port: 254 number: 80 255 name: http 256 protocol: HTTP 257 hosts: 258 - "foo.bar"` 259 simpleRoute := `apiVersion: networking.istio.io/v1alpha3 260 kind: VirtualService 261 metadata: 262 name: vs 263 spec: 264 hosts: 265 - "example.com" 266 gateways: 267 - gateway 268 http: 269 - match: 270 - uri: 271 prefix: / 272 route: 273 - destination: 274 host: b 275 --- 276 ` 277 runGatewayTest(t, 278 simulationTest{ 279 name: "no virtual services", 280 config: createGateway("", "", httpServer), 281 calls: []simulation.Expect{ 282 { 283 // Expect listener, but no routing 284 Name: "defined port", 285 Call: simulation.Call{ 286 Port: 80, 287 HostHeader: "foo.bar", 288 Protocol: simulation.HTTP, 289 }, 290 Result: simulation.Result{ 291 Error: simulation.ErrNoRoute, 292 ListenerMatched: "0.0.0.0_80", 293 RouteConfigMatched: "http.80", 294 VirtualHostMatched: "blackhole:80", 295 }, 296 }, 297 { 298 // There will be no listener 299 Name: "undefined port", 300 Call: simulation.Call{ 301 Port: 81, 302 HostHeader: "foo.bar", 303 Protocol: simulation.HTTP, 304 }, 305 Result: simulation.Result{ 306 Error: simulation.ErrNoListener, 307 }, 308 }, 309 }, 310 }, 311 simulationTest{ 312 name: "simple http and virtual service", 313 config: createGateway("gateway", "", httpServer) + ` 314 apiVersion: networking.istio.io/v1alpha3 315 kind: VirtualService 316 metadata: 317 name: bookinfo 318 spec: 319 hosts: 320 - "*" 321 gateways: 322 - gateway 323 http: 324 - match: 325 - uri: 326 exact: /productpage 327 route: 328 - destination: 329 host: productpage 330 port: 331 number: 9080 332 `, 333 calls: []simulation.Expect{ 334 { 335 Name: "uri mismatch", 336 Call: simulation.Call{ 337 Port: 80, 338 HostHeader: "foo.bar", 339 Protocol: simulation.HTTP, 340 }, 341 Result: simulation.Result{ 342 // We didn't match the URI 343 Error: simulation.ErrNoRoute, 344 ListenerMatched: "0.0.0.0_80", 345 RouteConfigMatched: "http.80", 346 VirtualHostMatched: "foo.bar:80", 347 }, 348 }, 349 { 350 Name: "host mismatch", 351 Call: simulation.Call{ 352 Port: 80, 353 HostHeader: "bad.bar", 354 Protocol: simulation.HTTP, 355 }, 356 Result: simulation.Result{ 357 // We didn't match the host 358 Error: simulation.ErrNoVirtualHost, 359 ListenerMatched: "0.0.0.0_80", 360 RouteConfigMatched: "http.80", 361 }, 362 }, 363 { 364 Name: "match", 365 Call: simulation.Call{ 366 Port: 80, 367 HostHeader: "foo.bar", 368 Path: "/productpage", 369 Protocol: simulation.HTTP, 370 }, 371 Result: simulation.Result{ 372 ListenerMatched: "0.0.0.0_80", 373 VirtualHostMatched: "foo.bar:80", 374 ClusterMatched: "outbound|9080||productpage.default", 375 }, 376 }, 377 }, 378 }, 379 simulationTest{ 380 name: "virtual service merging", 381 config: createGateway("gateway", "", `port: 382 number: 80 383 name: http 384 protocol: HTTP 385 hosts: 386 - "*.example.com"`) + ` 387 apiVersion: networking.istio.io/v1alpha3 388 kind: VirtualService 389 metadata: 390 name: a 391 spec: 392 hosts: 393 - "a.example.com" 394 gateways: 395 - gateway 396 http: 397 - match: 398 - uri: 399 prefix: / 400 route: 401 - destination: 402 host: a 403 port: 404 number: 80 405 --- 406 apiVersion: networking.istio.io/v1alpha3 407 kind: VirtualService 408 metadata: 409 name: b 410 spec: 411 hosts: 412 - "b.example.com" 413 gateways: 414 - gateway 415 http: 416 - match: 417 - uri: 418 prefix: / 419 route: 420 - destination: 421 host: b 422 port: 423 number: 80 424 `, 425 calls: []simulation.Expect{ 426 { 427 Name: "a", 428 Call: simulation.Call{ 429 Port: 80, 430 HostHeader: "a.example.com", 431 Protocol: simulation.HTTP, 432 }, 433 Result: simulation.Result{ClusterMatched: "outbound|80||a.default"}, 434 }, 435 { 436 Name: "b", 437 Call: simulation.Call{ 438 Port: 80, 439 HostHeader: "b.example.com", 440 Protocol: simulation.HTTP, 441 }, 442 Result: simulation.Result{ClusterMatched: "outbound|80||b.default"}, 443 }, 444 { 445 Name: "undefined hostname", 446 Call: simulation.Call{ 447 Port: 80, 448 HostHeader: "c.example.com", 449 Protocol: simulation.HTTP, 450 }, 451 Result: simulation.Result{Error: simulation.ErrNoVirtualHost}, 452 }, 453 }, 454 }, 455 simulationTest{ 456 name: "httpsRedirect without routes", 457 config: createGateway("gateway", "", `port: 458 number: 80 459 name: http 460 protocol: HTTP 461 hosts: 462 - "example.com" 463 tls: 464 httpsRedirect: true`), 465 calls: []simulation.Expect{ 466 { 467 Name: "request", 468 Call: simulation.Call{ 469 Port: 80, 470 HostHeader: "example.com", 471 Protocol: simulation.HTTP, 472 }, 473 Result: simulation.Result{ 474 Error: simulation.ErrTLSRedirect, 475 ListenerMatched: "0.0.0.0_80", 476 VirtualHostMatched: "example.com:80", 477 RouteConfigMatched: "http.80", 478 StrictMatch: true, 479 }, 480 }, 481 }, 482 }, 483 simulationTest{ 484 // This should be the same as without, we elide the routes anyways since they always 485 // redirect 486 name: "httpsRedirect with routes", 487 config: createGateway("gateway", "", `port: 488 number: 80 489 name: http 490 protocol: HTTP 491 hosts: 492 - "example.com" 493 tls: 494 httpsRedirect: true`) + simpleRoute, 495 calls: []simulation.Expect{ 496 { 497 Name: "request", 498 Call: simulation.Call{ 499 Port: 80, 500 HostHeader: "example.com", 501 Protocol: simulation.HTTP, 502 }, 503 Result: simulation.Result{ 504 Error: simulation.ErrTLSRedirect, 505 ListenerMatched: "0.0.0.0_80", 506 VirtualHostMatched: "example.com:80", 507 RouteConfigMatched: "http.80", 508 StrictMatch: true, 509 }, 510 }, 511 }, 512 }, 513 simulationTest{ 514 // A common example of when this would occur is when a user defines their Gateway with 515 // httpsRedirect, then cert-manager creates an Ingress which requires sending HTTP 516 // traffic Unfortunately, Envoy doesn't have a good way to do HTTPS redirect per-route. 517 name: "mixed httpsRedirect with routes", 518 config: createGateway("gateway", "", `port: 519 number: 80 520 name: http 521 protocol: HTTP 522 hosts: 523 - "example.com" 524 tls: 525 httpsRedirect: true`) + createGateway("gateway2", "", `port: 526 number: 80 527 name: http 528 protocol: HTTP 529 hosts: 530 - "example.com"`) + simpleRoute, 531 calls: []simulation.Expect{ 532 { 533 Name: "request", 534 Call: simulation.Call{ 535 Port: 80, 536 HostHeader: "example.com", 537 Protocol: simulation.HTTP, 538 }, 539 Result: simulation.Result{ 540 Error: simulation.ErrTLSRedirect, 541 ListenerMatched: "0.0.0.0_80", 542 VirtualHostMatched: "example.com:80", 543 RouteConfigMatched: "http.80", 544 StrictMatch: true, 545 }, 546 }, 547 }, 548 }, 549 simulationTest{ 550 name: "httpsRedirect on https", 551 config: createGateway("gateway", "", `port: 552 number: 443 553 name: https 554 protocol: HTTPS 555 hosts: 556 - "example.com" 557 tls: 558 httpsRedirect: true 559 mode: SIMPLE 560 credentialName: test`) + simpleRoute, 561 calls: []simulation.Expect{ 562 { 563 Name: "request", 564 Call: simulation.Call{ 565 Port: 443, 566 HostHeader: "example.com", 567 Protocol: simulation.HTTP, 568 TLS: simulation.TLS, 569 }, 570 Result: simulation.Result{ 571 ListenerMatched: "0.0.0.0_443", 572 VirtualHostMatched: "example.com:443", 573 RouteConfigMatched: "https.443.https.gateway.default", 574 ClusterMatched: "outbound|443||b.default", 575 StrictMatch: true, 576 }, 577 }, 578 }, 579 }, 580 ) 581 } 582 583 func TestGatewayConflicts(t *testing.T) { 584 tcpServer := `port: 585 number: 80 586 name: tcp 587 protocol: TCP 588 hosts: 589 - "foo.bar"` 590 httpServer := `port: 591 number: 80 592 name: http 593 protocol: HTTP 594 hosts: 595 - "foo.bar"` 596 tlsServer := `hosts: 597 - ./* 598 port: 599 name: https-ingress 600 number: 443 601 protocol: HTTPS 602 tls: 603 credentialName: sds-credential 604 mode: SIMPLE` 605 gatewayCollision := ` 606 apiVersion: networking.istio.io/v1alpha3 607 kind: VirtualService 608 metadata: 609 name: bookinfo 610 spec: 611 hosts: 612 - "*" 613 gateways: 614 - istio-system/gateway 615 tcp: 616 - route: 617 - destination: 618 host: productpage 619 port: 620 number: 9080 621 ` 622 runGatewayTest(t, 623 simulationTest{ 624 name: "duplicate cross namespace gateway collision", 625 config: createGateway("gateway", "istio-system", tcpServer) + 626 createGateway("gateway", "alpha", tcpServer) + // namespace comes before istio-system 627 628 gatewayCollision, 629 calls: []simulation.Expect{ 630 { 631 Name: "call", 632 Call: simulation.Call{Port: 80, Protocol: simulation.TCP}, 633 // TODO(https://github.com/istio/istio/issues/21394) This is a bug! 634 // Should have identical result to the test below 635 Result: simulation.Result{Error: simulation.ErrNoListener}, 636 }, 637 }, 638 }, 639 simulationTest{ 640 name: "duplicate cross namespace gateway collision - selected first", 641 config: createGateway("gateway", "istio-system", tcpServer) + 642 createGateway("gateway", "zeta", tcpServer) + // namespace comes after istio-system 643 gatewayCollision, 644 calls: []simulation.Expect{ 645 { 646 Name: "call", 647 Call: simulation.Call{Port: 80, Protocol: simulation.TCP}, 648 Result: simulation.Result{ListenerMatched: "0.0.0.0_80", ClusterMatched: "outbound|9080||productpage.default"}, 649 }, 650 }, 651 }, 652 simulationTest{ 653 name: "duplicate tls gateway", 654 skipValidation: true, 655 // Create the same gateway in two namespaces 656 config: createGateway("", "istio-system", tlsServer) + 657 createGateway("", "default", tlsServer), 658 calls: []simulation.Expect{ 659 { 660 // TODO(https://github.com/istio/istio/issues/24638) This is a bug! 661 // We should not have multiple matches, envoy will NACK this 662 Name: "call", 663 Call: simulation.Call{Port: 443, Protocol: simulation.HTTP, TLS: simulation.TLS, HostHeader: "foo.bar"}, 664 Result: simulation.Result{Error: simulation.ErrMultipleFilterChain}, 665 }, 666 }, 667 }, 668 simulationTest{ 669 name: "duplicate tls virtual service", 670 // Create the same virtual service in two namespaces 671 config: ` 672 apiVersion: networking.istio.io/v1alpha3 673 kind: Gateway 674 metadata: 675 name: ingressgateway 676 namespace: istio-system 677 spec: 678 selector: 679 istio: ingressgateway 680 servers: 681 - hosts: 682 - '*.example.com' 683 port: 684 name: https 685 number: 443 686 protocol: HTTPS 687 tls: 688 mode: PASSTHROUGH 689 --- 690 apiVersion: networking.istio.io/v1alpha3 691 kind: VirtualService 692 metadata: 693 name: vs1 694 namespace: default 695 spec: 696 gateways: 697 - istio-system/ingressgateway 698 hosts: 699 - mysite.example.com 700 tls: 701 - match: 702 - port: 443 703 sniHosts: 704 - mysite.example.com 705 route: 706 - destination: 707 host: mysite.default.svc.cluster.local 708 port: 709 number: 443 710 --- 711 apiVersion: networking.istio.io/v1alpha3 712 kind: VirtualService 713 metadata: 714 name: vs2 715 namespace: default 716 spec: 717 gateways: 718 - istio-system/ingressgateway 719 hosts: 720 - mysite.example.com 721 tls: 722 - match: 723 - port: 443 724 sniHosts: 725 - mysite.example.com 726 route: 727 - destination: 728 host: mysite.default.svc.cluster.local 729 port: 730 number: 443 731 `, 732 calls: []simulation.Expect{ 733 { 734 Name: "call", 735 Call: simulation.Call{Port: 443, Protocol: simulation.HTTP, TLS: simulation.TLS, HostHeader: "mysite.example.com"}, 736 Result: simulation.Result{ 737 ListenerMatched: "0.0.0.0_443", 738 ClusterMatched: "outbound|443||mysite.default.svc.cluster.local", 739 }, 740 }, 741 }, 742 }, 743 simulationTest{ 744 // TODO(https://github.com/istio/istio/issues/27481) this may be a bug. At very least, this should have indication to user 745 name: "multiple protocols on a port - tcp first", 746 config: createGateway("alpha", "", tcpServer) + 747 createGateway("beta", "", httpServer), 748 calls: []simulation.Expect{ 749 { 750 Name: "call tcp", 751 // TCP takes precedence. Since we have no tcp routes, this will result in no listeners 752 Call: simulation.Call{ 753 Port: 80, 754 Protocol: simulation.TCP, 755 }, 756 Result: simulation.Result{ 757 Error: simulation.ErrNoListener, 758 }, 759 }, 760 }, 761 }, 762 simulationTest{ 763 // TODO(https://github.com/istio/istio/issues/27481) this may be a bug. At very least, this should have indication to user 764 name: "multiple protocols on a port - http first", 765 config: createGateway("beta", "", tcpServer) + 766 createGateway("alpha", "", httpServer), 767 calls: []simulation.Expect{ 768 { 769 // Port define in gateway, but no virtual services 770 // Expect a 404 771 // HTTP protocol takes precedence 772 Name: "call http", 773 Call: simulation.Call{ 774 Port: 80, 775 HostHeader: "foo.bar", 776 Protocol: simulation.HTTP, 777 }, 778 Result: simulation.Result{ 779 Error: simulation.ErrNoRoute, 780 ListenerMatched: "0.0.0.0_80", 781 RouteConfigMatched: "http.80", 782 VirtualHostMatched: "blackhole:80", 783 }, 784 }, 785 }, 786 }, 787 simulationTest{ 788 name: "multiple wildcards with virtual service disambiguator", 789 config: createGateway("alpha", "", ` 790 hosts: 791 - ns-1/*.example.com 792 port: 793 name: http 794 number: 80 795 protocol: HTTP`) + 796 createGateway("beta", "", ` 797 hosts: 798 - ns-2/*.example.com 799 port: 800 name: http 801 number: 80 802 protocol: HTTP`) + ` 803 apiVersion: networking.istio.io/v1alpha3 804 kind: VirtualService 805 metadata: 806 name: default 807 namespace: ns-1 808 spec: 809 hosts: 810 - "ns-1.example.com" 811 gateways: 812 - default/alpha 813 http: 814 - route: 815 - destination: 816 host: echo 817 --- 818 apiVersion: networking.istio.io/v1alpha3 819 kind: VirtualService 820 metadata: 821 name: default 822 namespace: ns-2 823 spec: 824 hosts: 825 - "ns-2.example.com" 826 gateways: 827 - default/beta 828 http: 829 - route: 830 - destination: 831 host: echo 832 `, 833 calls: []simulation.Expect{ 834 { 835 Name: "ns-1", 836 Call: simulation.Call{ 837 Port: 80, 838 HostHeader: "ns-1.example.com", 839 Protocol: simulation.HTTP, 840 }, 841 Result: simulation.Result{ 842 ListenerMatched: "0.0.0.0_80", 843 RouteConfigMatched: "http.80", 844 ClusterMatched: "outbound|80||echo.ns-1", 845 }, 846 }, 847 { 848 Name: "ns-2", 849 Call: simulation.Call{ 850 Port: 80, 851 HostHeader: "ns-2.example.com", 852 Protocol: simulation.HTTP, 853 }, 854 Result: simulation.Result{ 855 ListenerMatched: "0.0.0.0_80", 856 RouteConfigMatched: "http.80", 857 ClusterMatched: "outbound|80||echo.ns-2", 858 }, 859 }, 860 }, 861 }, 862 simulationTest{ 863 name: "multiple virtual services that should become separate vhosts", 864 config: ` 865 apiVersion: networking.istio.io/v1beta1 866 kind: Gateway 867 metadata: 868 name: public-gw 869 namespace: istio-system 870 spec: 871 selector: 872 istio: ingressgateway 873 servers: 874 - port: 875 number: 80 876 name: http 877 protocol: HTTP 878 hosts: 879 - foo.example.com 880 - bar.example.com 881 --- 882 apiVersion: networking.istio.io/v1alpha3 883 kind: VirtualService 884 metadata: 885 name: foobar-vs 886 namespace: default 887 creationTimestamp: 2010-01-01T00:00:00Z 888 spec: 889 hosts: 890 - foo.example.com 891 - bar.example.com 892 gateways: 893 - istio-system/public-gw 894 http: 895 - name: foobar 896 match: 897 - uri: 898 prefix: /1 899 - uri: 900 prefix: /2 901 - uri: 902 prefix: /3 903 route: 904 - destination: 905 host: echo-foobar 906 --- 907 apiVersion: networking.istio.io/v1beta1 908 kind: VirtualService 909 metadata: 910 name: foo-vs 911 namespace: default 912 creationTimestamp: 2015-01-01T00:00:00Z 913 spec: 914 gateways: 915 - istio-system/public-gw 916 hosts: 917 - foo.example.com 918 http: 919 - name: foo 920 match: 921 - uri: 922 prefix: /foo 923 route: 924 - destination: 925 host: echo-foo 926 port: 927 number: 80 928 --- 929 apiVersion: networking.istio.io/v1beta1 930 kind: VirtualService 931 metadata: 932 name: bar-vs 933 namespace: default 934 creationTimestamp: 2020-01-01T00:00:00Z 935 spec: 936 gateways: 937 - istio-system/public-gw 938 hosts: 939 - bar.example.com 940 http: 941 - name: bar 942 match: 943 - uri: 944 prefix: /bar 945 route: 946 - destination: 947 host: echo-bar 948 port: 949 number: 80 950 `, 951 calls: []simulation.Expect{ 952 { 953 Name: "foobar", 954 Call: simulation.Call{ 955 Port: 80, 956 HostHeader: "foo.example.com", 957 Protocol: simulation.HTTP, 958 Path: "/1", 959 }, 960 Result: simulation.Result{ 961 ListenerMatched: "0.0.0.0_80", 962 RouteConfigMatched: "http.80", 963 ClusterMatched: "outbound|80||echo-foobar.default", 964 }, 965 }, 966 { 967 Name: "foo", 968 Call: simulation.Call{ 969 Port: 80, 970 HostHeader: "foo.example.com", 971 Protocol: simulation.HTTP, 972 Path: "/foo", 973 }, 974 Result: simulation.Result{ 975 ListenerMatched: "0.0.0.0_80", 976 RouteConfigMatched: "http.80", 977 ClusterMatched: "outbound|80||echo-foo.default", 978 }, 979 }, 980 { 981 Name: "bar", 982 Call: simulation.Call{ 983 Port: 80, 984 HostHeader: "bar.example.com", 985 Protocol: simulation.HTTP, 986 Path: "/bar", 987 }, 988 Result: simulation.Result{ 989 ListenerMatched: "0.0.0.0_80", 990 RouteConfigMatched: "http.80", 991 ClusterMatched: "outbound|80||echo-bar.default", 992 }, 993 }, 994 }, 995 }, 996 ) 997 } 998 999 func TestIngress(t *testing.T) { 1000 cfg := ` 1001 apiVersion: networking.k8s.io/v1 1002 kind: Ingress 1003 metadata: 1004 name: {{.Name}} 1005 namespace: default 1006 creationTimestamp: "{{.Time}}" 1007 annotations: 1008 kubernetes.io/ingress.class: istio 1009 spec: 1010 rules: 1011 - host: example.com 1012 http: 1013 paths: 1014 - pathType: Prefix 1015 backend: 1016 service: 1017 name: {{.Name}} 1018 port: 1019 number: 80 1020 path: /{{.Name}} 1021 tls: 1022 - hosts: 1023 - example.com 1024 secretName: ingressgateway-certs 1025 ---` 1026 runGatewayTest(t, simulationTest{ 1027 name: "ingress shared TLS cert conflict - beta first", 1028 // TODO(https://github.com/istio/istio/issues/24385) this is a bug 1029 // "alpha" is created after "beta". This triggers a mismatch in the conflict resolution logic in Ingress and VirtualService, leading to unexpected results 1030 kubeConfig: tmpl.MustEvaluate(cfg, map[string]string{"Name": "alpha", "Time": "2020-01-01T00:00:00Z"}) + 1031 tmpl.MustEvaluate(cfg, map[string]string{"Name": "beta", "Time": "2010-01-01T00:00:00Z"}), 1032 calls: []simulation.Expect{ 1033 { 1034 Name: "http alpha", 1035 Call: simulation.Call{ 1036 Port: 80, 1037 HostHeader: "example.com", 1038 Path: "/alpha", 1039 Protocol: simulation.HTTP, 1040 }, 1041 Result: simulation.Result{ 1042 ListenerMatched: "0.0.0.0_80", 1043 RouteConfigMatched: "http.80", 1044 ClusterMatched: "outbound|80||alpha.default.svc.cluster.local", 1045 }, 1046 }, 1047 { 1048 Name: "http beta", 1049 Call: simulation.Call{ 1050 Port: 80, 1051 HostHeader: "example.com", 1052 Path: "/beta", 1053 Protocol: simulation.HTTP, 1054 }, 1055 Result: simulation.Result{ 1056 ListenerMatched: "0.0.0.0_80", 1057 RouteConfigMatched: "http.80", 1058 ClusterMatched: "outbound|80||beta.default.svc.cluster.local", 1059 }, 1060 }, 1061 { 1062 Name: "https alpha", 1063 Call: simulation.Call{ 1064 Port: 443, 1065 HostHeader: "example.com", 1066 Path: "/alpha", 1067 Protocol: simulation.HTTP, 1068 TLS: simulation.TLS, 1069 }, 1070 Result: simulation.Result{ 1071 Error: simulation.ErrNoRoute, 1072 ListenerMatched: "0.0.0.0_443", 1073 RouteConfigMatched: "https.443.https-443-ingress-alpha-default-0.alpha-istio-autogenerated-k8s-ingress-default.istio-system", 1074 VirtualHostMatched: "blackhole:443", 1075 }, 1076 }, 1077 { 1078 Name: "https beta", 1079 Call: simulation.Call{ 1080 Port: 443, 1081 HostHeader: "example.com", 1082 Path: "/beta", 1083 Protocol: simulation.HTTP, 1084 TLS: simulation.TLS, 1085 }, 1086 Result: simulation.Result{ 1087 Error: simulation.ErrNoRoute, 1088 ListenerMatched: "0.0.0.0_443", 1089 RouteConfigMatched: "https.443.https-443-ingress-alpha-default-0.alpha-istio-autogenerated-k8s-ingress-default.istio-system", 1090 VirtualHostMatched: "blackhole:443", 1091 }, 1092 }, 1093 }, 1094 }, simulationTest{ 1095 name: "ingress shared TLS cert conflict - alpha first", 1096 // "alpha" is created before "beta". This avoids the bug in the previous test 1097 kubeConfig: tmpl.MustEvaluate(cfg, map[string]string{"Name": "alpha", "Time": "2010-01-01T00:00:00Z"}) + 1098 tmpl.MustEvaluate(cfg, map[string]string{"Name": "beta", "Time": "2020-01-01T00:00:00Z"}), 1099 calls: []simulation.Expect{ 1100 { 1101 Name: "http alpha", 1102 Call: simulation.Call{ 1103 Port: 80, 1104 HostHeader: "example.com", 1105 Path: "/alpha", 1106 Protocol: simulation.HTTP, 1107 }, 1108 Result: simulation.Result{ 1109 ListenerMatched: "0.0.0.0_80", 1110 RouteConfigMatched: "http.80", 1111 ClusterMatched: "outbound|80||alpha.default.svc.cluster.local", 1112 }, 1113 }, 1114 { 1115 Name: "http beta", 1116 Call: simulation.Call{ 1117 Port: 80, 1118 HostHeader: "example.com", 1119 Path: "/beta", 1120 Protocol: simulation.HTTP, 1121 }, 1122 Result: simulation.Result{ 1123 ListenerMatched: "0.0.0.0_80", 1124 RouteConfigMatched: "http.80", 1125 ClusterMatched: "outbound|80||beta.default.svc.cluster.local", 1126 }, 1127 }, 1128 { 1129 Name: "https alpha", 1130 Call: simulation.Call{ 1131 Port: 443, 1132 HostHeader: "example.com", 1133 Path: "/alpha", 1134 Protocol: simulation.HTTP, 1135 TLS: simulation.TLS, 1136 }, 1137 Result: simulation.Result{ 1138 ListenerMatched: "0.0.0.0_443", 1139 RouteConfigMatched: "https.443.https-443-ingress-alpha-default-0.alpha-istio-autogenerated-k8s-ingress-default.istio-system", 1140 ClusterMatched: "outbound|80||alpha.default.svc.cluster.local", 1141 }, 1142 }, 1143 { 1144 Name: "https beta", 1145 Call: simulation.Call{ 1146 Port: 443, 1147 HostHeader: "example.com", 1148 Path: "/beta", 1149 Protocol: simulation.HTTP, 1150 TLS: simulation.TLS, 1151 }, 1152 Result: simulation.Result{ 1153 ListenerMatched: "0.0.0.0_443", 1154 RouteConfigMatched: "https.443.https-443-ingress-alpha-default-0.alpha-istio-autogenerated-k8s-ingress-default.istio-system", 1155 ClusterMatched: "outbound|80||beta.default.svc.cluster.local", 1156 }, 1157 }, 1158 }, 1159 }) 1160 } 1161 1162 type simulationTest struct { 1163 name string 1164 config string 1165 kubeConfig string 1166 // skipValidation disables validation of XDS resources. Should be used only when we expect a failure (regression catching) 1167 skipValidation bool 1168 calls []simulation.Expect 1169 } 1170 1171 var debugMode = env.Register("SIMULATION_DEBUG", true, "if enabled, will dump verbose output").Get() 1172 1173 func runGatewayTest(t *testing.T, cases ...simulationTest) { 1174 for _, tt := range cases { 1175 proxy := &model.Proxy{ 1176 Labels: map[string]string{"istio": "ingressgateway"}, 1177 Metadata: &model.NodeMetadata{ 1178 Labels: map[string]string{"istio": "ingressgateway"}, 1179 Namespace: "istio-system", 1180 }, 1181 Type: model.Router, 1182 } 1183 runSimulationTest(t, proxy, xds.FakeOptions{}, tt) 1184 } 1185 } 1186 1187 func runSimulationTest(t *testing.T, proxy *model.Proxy, o xds.FakeOptions, tt simulationTest) { 1188 runTest := func(t *testing.T) { 1189 o.ConfigString = tt.config 1190 o.KubernetesObjectString = tt.kubeConfig 1191 s := xds.NewFakeDiscoveryServer(t, o) 1192 sim := simulation.NewSimulation(t, s, s.SetupProxy(proxy)) 1193 sim.RunExpectations(tt.calls) 1194 if t.Failed() && debugMode { 1195 t.Log(xdstest.MapKeys(xdstest.ExtractClusters(sim.Clusters))) 1196 t.Log(xdstest.ExtractListenerNames(sim.Listeners)) 1197 t.Log(xdstest.DumpList(t, sim.Listeners)) 1198 t.Log(xdstest.DumpList(t, sim.Routes)) 1199 t.Log(tt.config) 1200 t.Log(tt.kubeConfig) 1201 } 1202 t.Run("validate configs", func(t *testing.T) { 1203 if tt.skipValidation { 1204 t.Skip() 1205 } 1206 xdstest.ValidateClusters(t, sim.Clusters) 1207 xdstest.ValidateListeners(t, sim.Listeners) 1208 xdstest.ValidateRouteConfigurations(t, sim.Routes) 1209 }) 1210 } 1211 if tt.name != "" { 1212 t.Run(tt.name, runTest) 1213 } else { 1214 runTest(t) 1215 } 1216 } 1217 1218 func createGateway(name, namespace string, servers ...string) string { 1219 if name == "" { 1220 name = "default" 1221 } 1222 if namespace == "" { 1223 namespace = "default" 1224 } 1225 return tmpl.MustEvaluate(`apiVersion: networking.istio.io/v1alpha3 1226 kind: Gateway 1227 metadata: 1228 name: "{{.Name}}" 1229 namespace: "{{.Namespace}}" 1230 spec: 1231 selector: 1232 istio: ingressgateway 1233 servers: 1234 {{- range $i, $p := $.Servers }} 1235 - 1236 {{$p | trim | indent 4}} 1237 {{- end }} 1238 --- 1239 `, struct { 1240 Name string 1241 Namespace string 1242 Servers []string 1243 }{name, namespace, servers}) 1244 } 1245 1246 func createGatewayWithServiceSelector(name, service string, servers ...string) string { 1247 if name == "" { 1248 name = "default" 1249 } 1250 return tmpl.MustEvaluate(`apiVersion: networking.istio.io/v1alpha3 1251 kind: Gateway 1252 metadata: 1253 name: "{{.Name}}" 1254 namespace: "istio-system" 1255 annotations: 1256 internal.istio.io/gateway-service: "{{.Service}}" 1257 spec: 1258 servers: 1259 {{- range $i, $p := $.Servers }} 1260 - 1261 {{$p | trim | indent 4}} 1262 {{- end }} 1263 --- 1264 `, struct { 1265 Name string 1266 Service string 1267 Servers []string 1268 }{name, service, servers}) 1269 } 1270 1271 func TestTargetPort(t *testing.T) { 1272 runGatewayTest(t, 1273 simulationTest{ 1274 name: "basic", 1275 config: createGatewayWithServiceSelector("gateway80", "istio-ingressgateway.istio-system.svc.cluster.local", ` 1276 port: 1277 number: 80 1278 name: http 1279 protocol: HTTP 1280 hosts: 1281 - "example.com" 1282 `) + createGatewayWithServiceSelector("gateway81", "istio-ingressgateway.istio-system.svc.cluster.local", ` 1283 port: 1284 number: 8080 1285 name: http 1286 protocol: HTTP 1287 hosts: 1288 - "example.com" 1289 `) + ` 1290 --- 1291 apiVersion: networking.istio.io/v1alpha3 1292 kind: ServiceEntry 1293 metadata: 1294 name: service-instance 1295 namespace: istio-system 1296 spec: 1297 hosts: ["istio-ingressgateway.istio-system.svc.cluster.local"] 1298 ports: 1299 - number: 80 1300 targetPort: 8080 1301 name: http 1302 protocol: HTTP 1303 resolution: STATIC 1304 location: MESH_INTERNAL 1305 endpoints: 1306 - address: 1.1.1.1 1307 --- 1308 apiVersion: networking.istio.io/v1alpha3 1309 kind: VirtualService 1310 metadata: 1311 name: a 1312 spec: 1313 hosts: 1314 - "example.com" 1315 gateways: 1316 - istio-system/gateway80 1317 - istio-system/gateway81 1318 http: 1319 - match: 1320 - uri: 1321 prefix: / 1322 route: 1323 - destination: 1324 host: a 1325 port: 1326 number: 80`, 1327 calls: []simulation.Expect{ 1328 { 1329 Call: simulation.Call{ 1330 Port: 8080, 1331 HostHeader: "example.com", 1332 Protocol: simulation.HTTP, 1333 }, 1334 Result: simulation.Result{ 1335 ListenerMatched: "0.0.0.0_8080", 1336 ClusterMatched: "outbound|80||a.default", 1337 RouteConfigMatched: "http.8080", 1338 VirtualHostMatched: "example.com:80", 1339 }, 1340 }, 1341 }, 1342 }, 1343 simulationTest{ 1344 name: "multiple target port", 1345 config: createGatewayWithServiceSelector("gateway80", "ingress1.istio-system.svc.cluster.local", ` 1346 port: 1347 number: 80 1348 name: http 1349 protocol: HTTP 1350 hosts: 1351 - "example.com" 1352 `) + createGatewayWithServiceSelector("gateway81", "ingress2.istio-system.svc.cluster.local", ` 1353 port: 1354 number: 80 1355 name: http 1356 protocol: HTTP 1357 hosts: 1358 - "example.com" 1359 `) + ` 1360 --- 1361 apiVersion: networking.istio.io/v1alpha3 1362 kind: ServiceEntry 1363 metadata: 1364 name: service-instance 1365 namespace: istio-system 1366 spec: 1367 hosts: ["ingress1.istio-system.svc.cluster.local"] 1368 ports: 1369 - number: 80 1370 targetPort: 8080 1371 name: http 1372 protocol: HTTP 1373 resolution: STATIC 1374 location: MESH_INTERNAL 1375 endpoints: 1376 - address: 1.1.1.1 1377 --- 1378 apiVersion: networking.istio.io/v1alpha3 1379 kind: ServiceEntry 1380 metadata: 1381 name: service-instance-2 1382 namespace: istio-system 1383 spec: 1384 hosts: ["ingress2.istio-system.svc.cluster.local"] 1385 ports: 1386 - number: 80 1387 targetPort: 8081 1388 name: http 1389 protocol: HTTP 1390 resolution: STATIC 1391 location: MESH_INTERNAL 1392 endpoints: 1393 - address: 1.1.1.1 1394 --- 1395 apiVersion: networking.istio.io/v1alpha3 1396 kind: VirtualService 1397 metadata: 1398 name: a 1399 spec: 1400 hosts: 1401 - "example.com" 1402 gateways: 1403 - istio-system/gateway80 1404 - istio-system/gateway81 1405 http: 1406 - match: 1407 - uri: 1408 prefix: / 1409 route: 1410 - destination: 1411 host: a 1412 port: 1413 number: 80 1414 --- 1415 apiVersion: networking.istio.io/v1alpha3 1416 kind: VirtualService 1417 metadata: 1418 name: b 1419 spec: 1420 hosts: 1421 - "example.com" 1422 gateways: 1423 - istio-system/gateway80 1424 - istio-system/gateway81 1425 http: 1426 - match: 1427 - uri: 1428 prefix: / 1429 route: 1430 - destination: 1431 host: b 1432 port: 1433 number: 8081`, 1434 calls: []simulation.Expect{ 1435 { 1436 Name: "target port 1", 1437 Call: simulation.Call{ 1438 Port: 8080, 1439 HostHeader: "example.com", 1440 Protocol: simulation.HTTP, 1441 }, 1442 Result: simulation.Result{ 1443 ListenerMatched: "0.0.0.0_8080", 1444 ClusterMatched: "outbound|80||a.default", 1445 RouteConfigMatched: "http.8080", 1446 VirtualHostMatched: "example.com:80", 1447 }, 1448 }, 1449 { 1450 Name: "target port 2", 1451 Call: simulation.Call{ 1452 Port: 8081, 1453 HostHeader: "example.com", 1454 Protocol: simulation.HTTP, 1455 }, 1456 Result: simulation.Result{ 1457 ListenerMatched: "0.0.0.0_8081", 1458 ClusterMatched: "outbound|80||a.default", 1459 RouteConfigMatched: "http.8081", 1460 VirtualHostMatched: "example.com:80", 1461 }, 1462 }, 1463 }, 1464 }) 1465 } 1466 1467 func TestGatewayServices(t *testing.T) { 1468 runGatewayTest(t, 1469 simulationTest{ 1470 name: "single service", 1471 config: createGatewayWithServiceSelector("gateway", "istio-ingressgateway.istio-system.svc.cluster.local", ` 1472 port: 1473 number: 80 1474 name: http-80 1475 protocol: HTTP 1476 hosts: 1477 - "80.example.com" 1478 `, ` 1479 port: 1480 number: 82 1481 name: http-82 1482 protocol: HTTP 1483 hosts: 1484 - "82.example.com" 1485 `) + ` 1486 --- 1487 apiVersion: networking.istio.io/v1alpha3 1488 kind: ServiceEntry 1489 metadata: 1490 name: service-instance 1491 namespace: istio-system 1492 spec: 1493 hosts: ["istio-ingressgateway.istio-system.svc.cluster.local"] 1494 ports: 1495 - number: 80 1496 targetPort: 8080 1497 name: http 1498 protocol: HTTP 1499 resolution: STATIC 1500 location: MESH_INTERNAL 1501 endpoints: 1502 - address: 1.1.1.1 1503 --- 1504 apiVersion: networking.istio.io/v1alpha3 1505 kind: VirtualService 1506 metadata: 1507 name: a 1508 spec: 1509 hosts: 1510 - "*.example.com" 1511 gateways: 1512 - istio-system/gateway 1513 http: 1514 - match: 1515 - uri: 1516 prefix: / 1517 route: 1518 - destination: 1519 host: a 1520 port: 1521 number: 80`, 1522 calls: []simulation.Expect{ 1523 { 1524 Name: "port 8080", 1525 Call: simulation.Call{ 1526 Port: 8080, 1527 HostHeader: "80.example.com", 1528 Protocol: simulation.HTTP, 1529 }, 1530 Result: simulation.Result{ 1531 ListenerMatched: "0.0.0.0_8080", 1532 ClusterMatched: "outbound|80||a.default", 1533 RouteConfigMatched: "http.8080", 1534 VirtualHostMatched: "80.example.com:80", 1535 }, 1536 }, 1537 { 1538 Name: "no service match", 1539 Call: simulation.Call{ 1540 Port: 82, 1541 HostHeader: "81.example.com", 1542 Protocol: simulation.HTTP, 1543 }, 1544 // For gateway service reference, if there is no matching port we do not setup a listener 1545 Result: simulation.Result{ 1546 Error: simulation.ErrNoListener, 1547 }, 1548 }, 1549 }, 1550 }, 1551 simulationTest{ 1552 name: "wrong namespace", 1553 config: createGatewayWithServiceSelector("gateway", "istio-ingressgateway.not-istio-system.svc.cluster.local", ` 1554 port: 1555 number: 80 1556 name: http-80 1557 protocol: HTTP 1558 hosts: 1559 - "80.example.com" 1560 `) + ` 1561 --- 1562 apiVersion: networking.istio.io/v1alpha3 1563 kind: ServiceEntry 1564 metadata: 1565 name: service-instance 1566 namespace: not-istio-system 1567 spec: 1568 hosts: ["istio-ingressgateway.not-istio-system.svc.cluster.local"] 1569 ports: 1570 - number: 80 1571 name: http 1572 protocol: HTTP 1573 resolution: STATIC 1574 location: MESH_INTERNAL 1575 endpoints: 1576 - address: 1.1.1.1 1577 ---`, 1578 calls: []simulation.Expect{ 1579 { 1580 Name: "port 80", 1581 Call: simulation.Call{ 1582 Port: 80, 1583 HostHeader: "80.example.com", 1584 Protocol: simulation.HTTP, 1585 }, 1586 Result: simulation.Result{ 1587 // Service selected is in another namespace, we cannot cross namespace boundary 1588 Error: simulation.ErrNoListener, 1589 }, 1590 }, 1591 }, 1592 }, 1593 simulationTest{ 1594 name: "multiple services", 1595 config: createGatewayWithServiceSelector("gateway", "istio-ingressgateway.istio-system.svc.cluster.local,ingress.com", ` 1596 port: 1597 number: 80 1598 name: http-80 1599 protocol: HTTP 1600 hosts: 1601 - "80.example.com" 1602 `, ` 1603 port: 1604 number: 81 1605 name: http-81 1606 protocol: HTTP 1607 hosts: 1608 - "81.example.com" 1609 `, ` 1610 port: 1611 number: 82 1612 name: http-82 1613 protocol: HTTP 1614 hosts: 1615 - "82.example.com" 1616 `) + ` 1617 --- 1618 apiVersion: networking.istio.io/v1alpha3 1619 kind: ServiceEntry 1620 metadata: 1621 name: service-instance 1622 namespace: istio-system 1623 spec: 1624 hosts: ["istio-ingressgateway.istio-system.svc.cluster.local"] 1625 ports: 1626 - number: 80 1627 targetPort: 8080 1628 name: http 1629 protocol: HTTP 1630 resolution: STATIC 1631 location: MESH_INTERNAL 1632 endpoints: 1633 - address: 1.1.1.1 1634 --- 1635 apiVersion: networking.istio.io/v1alpha3 1636 kind: ServiceEntry 1637 metadata: 1638 name: service-instance2 1639 namespace: istio-system 1640 spec: 1641 hosts: ["ingress.com"] 1642 ports: 1643 - number: 81 1644 targetPort: 8081 1645 name: http 1646 protocol: HTTP 1647 resolution: STATIC 1648 location: MESH_INTERNAL 1649 endpoints: 1650 - address: 1.1.1.1 1651 --- 1652 apiVersion: networking.istio.io/v1alpha3 1653 kind: VirtualService 1654 metadata: 1655 name: a 1656 spec: 1657 hosts: 1658 - "*.example.com" 1659 gateways: 1660 - istio-system/gateway 1661 http: 1662 - match: 1663 - uri: 1664 prefix: / 1665 route: 1666 - destination: 1667 host: a 1668 port: 1669 number: 80`, 1670 calls: []simulation.Expect{ 1671 { 1672 Name: "port 8080", 1673 Call: simulation.Call{ 1674 Port: 8080, 1675 HostHeader: "80.example.com", 1676 Protocol: simulation.HTTP, 1677 }, 1678 Result: simulation.Result{ 1679 ListenerMatched: "0.0.0.0_8080", 1680 ClusterMatched: "outbound|80||a.default", 1681 RouteConfigMatched: "http.8080", 1682 VirtualHostMatched: "80.example.com:80", 1683 }, 1684 }, 1685 { 1686 Name: "port 8081", 1687 Call: simulation.Call{ 1688 Port: 8081, 1689 HostHeader: "81.example.com", 1690 Protocol: simulation.HTTP, 1691 }, 1692 Result: simulation.Result{ 1693 ListenerMatched: "0.0.0.0_8081", 1694 ClusterMatched: "outbound|80||a.default", 1695 RouteConfigMatched: "http.8081", 1696 VirtualHostMatched: "81.example.com:81", 1697 }, 1698 }, 1699 { 1700 // For gateway service reference, if there is no matching port we do not setup a listener 1701 Name: "no service match", 1702 Call: simulation.Call{ 1703 Port: 82, 1704 HostHeader: "81.example.com", 1705 Protocol: simulation.HTTP, 1706 }, 1707 Result: simulation.Result{ 1708 Error: simulation.ErrNoListener, 1709 }, 1710 }, 1711 }, 1712 }, 1713 simulationTest{ 1714 name: "multiple overlapping services", 1715 config: createGatewayWithServiceSelector("gateway", "istio-ingressgateway.istio-system.svc.cluster.local,ingress.com", ` 1716 port: 1717 number: 80 1718 name: http-80 1719 protocol: HTTP 1720 hosts: 1721 - "80.example.com" 1722 `, ` 1723 port: 1724 number: 81 1725 name: http-81 1726 protocol: HTTP 1727 hosts: 1728 - "81.example.com" 1729 `) + ` 1730 --- 1731 apiVersion: networking.istio.io/v1alpha3 1732 kind: ServiceEntry 1733 metadata: 1734 name: service-instance 1735 namespace: istio-system 1736 spec: 1737 hosts: ["istio-ingressgateway.istio-system.svc.cluster.local"] 1738 ports: 1739 - number: 80 1740 targetPort: 8080 1741 name: http 1742 protocol: HTTP 1743 resolution: STATIC 1744 location: MESH_INTERNAL 1745 endpoints: 1746 - address: 1.1.1.1 1747 --- 1748 apiVersion: networking.istio.io/v1alpha3 1749 kind: ServiceEntry 1750 metadata: 1751 name: service-instance2 1752 namespace: istio-system 1753 spec: 1754 hosts: ["ingress.com"] 1755 ports: 1756 - number: 81 1757 targetPort: 8080 1758 name: http 1759 protocol: HTTP 1760 resolution: STATIC 1761 location: MESH_INTERNAL 1762 endpoints: 1763 - address: 1.1.1.1 1764 --- 1765 apiVersion: networking.istio.io/v1alpha3 1766 kind: VirtualService 1767 metadata: 1768 name: a-80 1769 spec: 1770 hosts: 1771 - "80.example.com" 1772 gateways: 1773 - istio-system/gateway 1774 http: 1775 - match: 1776 - uri: 1777 prefix: / 1778 route: 1779 - destination: 1780 host: a 1781 port: 1782 number: 80 1783 --- 1784 apiVersion: networking.istio.io/v1alpha3 1785 kind: VirtualService 1786 metadata: 1787 name: a-81 1788 spec: 1789 hosts: 1790 - "81.example.com" 1791 gateways: 1792 - istio-system/gateway 1793 http: 1794 - match: 1795 - uri: 1796 prefix: / 1797 route: 1798 - destination: 1799 host: a 1800 port: 1801 number: 80`, 1802 calls: []simulation.Expect{ 1803 { 1804 Name: "port 8080 from 80", 1805 Call: simulation.Call{ 1806 Port: 8080, 1807 HostHeader: "80.example.com", 1808 Protocol: simulation.HTTP, 1809 }, 1810 Result: simulation.Result{ 1811 ListenerMatched: "0.0.0.0_8080", 1812 ClusterMatched: "outbound|80||a.default", 1813 RouteConfigMatched: "http.8080", 1814 VirtualHostMatched: "80.example.com:80", 1815 }, 1816 }, 1817 { 1818 Name: "port 8080 from 81", 1819 Call: simulation.Call{ 1820 Port: 8080, 1821 HostHeader: "81.example.com", 1822 Protocol: simulation.HTTP, 1823 }, 1824 Result: simulation.Result{ 1825 ListenerMatched: "0.0.0.0_8080", 1826 ClusterMatched: "outbound|80||a.default", 1827 RouteConfigMatched: "http.8080", 1828 VirtualHostMatched: "81.example.com:81", 1829 }, 1830 }, 1831 }, 1832 }, 1833 simulationTest{ 1834 name: "multiple overlapping services wildcard", 1835 config: createGatewayWithServiceSelector("gateway", "istio-ingressgateway.istio-system.svc.cluster.local,ingress.com", ` 1836 port: 1837 number: 80 1838 name: http-80 1839 protocol: HTTP 1840 hosts: 1841 - "80.example.com" 1842 `, ` 1843 port: 1844 number: 81 1845 name: http-81 1846 protocol: HTTP 1847 hosts: 1848 - "81.example.com" 1849 `) + ` 1850 --- 1851 apiVersion: networking.istio.io/v1alpha3 1852 kind: ServiceEntry 1853 metadata: 1854 name: service-instance 1855 namespace: istio-system 1856 spec: 1857 hosts: ["istio-ingressgateway.istio-system.svc.cluster.local"] 1858 ports: 1859 - number: 80 1860 targetPort: 8080 1861 name: http 1862 protocol: HTTP 1863 resolution: STATIC 1864 location: MESH_INTERNAL 1865 endpoints: 1866 - address: 1.1.1.1 1867 --- 1868 apiVersion: networking.istio.io/v1alpha3 1869 kind: ServiceEntry 1870 metadata: 1871 name: service-instance2 1872 namespace: istio-system 1873 spec: 1874 hosts: ["ingress.com"] 1875 ports: 1876 - number: 81 1877 targetPort: 8080 1878 name: http 1879 protocol: HTTP 1880 resolution: STATIC 1881 location: MESH_INTERNAL 1882 endpoints: 1883 - address: 1.1.1.1 1884 --- 1885 apiVersion: networking.istio.io/v1alpha3 1886 kind: VirtualService 1887 metadata: 1888 name: a-80 1889 spec: 1890 hosts: 1891 - "80.example.com" 1892 gateways: 1893 - istio-system/gateway 1894 http: 1895 - match: 1896 - uri: 1897 prefix: / 1898 route: 1899 - destination: 1900 host: a 1901 port: 1902 number: 80 1903 --- 1904 apiVersion: networking.istio.io/v1alpha3 1905 kind: VirtualService 1906 metadata: 1907 name: a-81 1908 spec: 1909 hosts: 1910 - "81.example.com" 1911 gateways: 1912 - istio-system/gateway 1913 http: 1914 - match: 1915 - uri: 1916 prefix: / 1917 route: 1918 - destination: 1919 host: a 1920 port: 1921 number: 80`, 1922 calls: []simulation.Expect{ 1923 { 1924 Name: "port 8080 from 80", 1925 Call: simulation.Call{ 1926 Port: 8080, 1927 HostHeader: "80.example.com", 1928 Protocol: simulation.HTTP, 1929 }, 1930 Result: simulation.Result{ 1931 ListenerMatched: "0.0.0.0_8080", 1932 ClusterMatched: "outbound|80||a.default", 1933 RouteConfigMatched: "http.8080", 1934 VirtualHostMatched: "80.example.com:80", 1935 }, 1936 }, 1937 { 1938 Name: "port 8080 from 81", 1939 Call: simulation.Call{ 1940 Port: 8080, 1941 HostHeader: "81.example.com", 1942 Protocol: simulation.HTTP, 1943 }, 1944 Result: simulation.Result{ 1945 ListenerMatched: "0.0.0.0_8080", 1946 ClusterMatched: "outbound|80||a.default", 1947 RouteConfigMatched: "http.8080", 1948 VirtualHostMatched: "81.example.com:81", 1949 }, 1950 }, 1951 }, 1952 }, 1953 simulationTest{ 1954 name: "no match selector", 1955 config: createGateway("gateway", "istio-system", ` 1956 port: 1957 number: 80 1958 name: http-80 1959 protocol: HTTP 1960 hosts: 1961 - "80.example.com" 1962 `, ` 1963 port: 1964 number: 82 1965 name: http-82 1966 protocol: HTTP 1967 hosts: 1968 - "82.example.com" 1969 `) + ` 1970 --- 1971 apiVersion: networking.istio.io/v1alpha3 1972 kind: ServiceEntry 1973 metadata: 1974 name: service-instance 1975 namespace: istio-system 1976 spec: 1977 hosts: ["istio-ingressgateway.istio-system.svc.cluster.local"] 1978 ports: 1979 - number: 80 1980 targetPort: 8080 1981 name: http 1982 protocol: HTTP 1983 resolution: STATIC 1984 location: MESH_INTERNAL 1985 endpoints: 1986 - address: 1.1.1.1 1987 --- 1988 apiVersion: networking.istio.io/v1alpha3 1989 kind: VirtualService 1990 metadata: 1991 name: a 1992 spec: 1993 hosts: 1994 - "*.example.com" 1995 gateways: 1996 - istio-system/gateway 1997 http: 1998 - match: 1999 - uri: 2000 prefix: / 2001 route: 2002 - destination: 2003 host: a 2004 port: 2005 number: 80`, 2006 calls: []simulation.Expect{ 2007 { 2008 Name: "port 8080", 2009 Call: simulation.Call{ 2010 Port: 8080, 2011 HostHeader: "80.example.com", 2012 Protocol: simulation.HTTP, 2013 }, 2014 Result: simulation.Result{ 2015 ListenerMatched: "0.0.0.0_8080", 2016 ClusterMatched: "outbound|80||a.default", 2017 RouteConfigMatched: "http.8080", 2018 VirtualHostMatched: "80.example.com:80", 2019 }, 2020 }, 2021 { 2022 // For gateway selector more, if there is no matching service we use the port as is 2023 Name: "no service match", 2024 Call: simulation.Call{ 2025 Port: 82, 2026 HostHeader: "82.example.com", 2027 Protocol: simulation.HTTP, 2028 }, 2029 Result: simulation.Result{ 2030 ListenerMatched: "0.0.0.0_82", 2031 ClusterMatched: "outbound|80||a.default", 2032 RouteConfigMatched: "http.82", 2033 VirtualHostMatched: "82.example.com:82", 2034 }, 2035 }, 2036 }, 2037 }, 2038 simulationTest{ 2039 name: "overlapping SNI match", 2040 skipValidation: true, // TODO: https://github.com/istio/istio/issues/39921 2041 config: `apiVersion: networking.istio.io/v1beta1 2042 kind: Gateway 2043 metadata: 2044 name: gw 2045 namespace: istio-system 2046 spec: 2047 selector: 2048 istio: ingressgateway 2049 servers: 2050 - hosts: 2051 - example.com 2052 port: 2053 name: example 2054 number: 443 2055 protocol: TLS 2056 tls: 2057 mode: PASSTHROUGH 2058 - hosts: 2059 - '*' 2060 port: 2061 name: wildcard-tls 2062 number: 443 2063 protocol: HTTPS 2064 tls: 2065 mode: PASSTHROUGH 2066 --- 2067 apiVersion: networking.istio.io/v1beta1 2068 kind: VirtualService 2069 metadata: 2070 name: example 2071 namespace: istio-system 2072 spec: 2073 gateways: 2074 - gw 2075 hosts: 2076 - example.com 2077 tls: 2078 - match: 2079 - sniHosts: 2080 - example.com 2081 route: 2082 - destination: 2083 host: example 2084 ` + ` 2085 --- 2086 apiVersion: networking.istio.io/v1alpha3 2087 kind: ServiceEntry 2088 metadata: 2089 name: service-instance 2090 namespace: istio-system 2091 spec: 2092 hosts: ["istio-ingressgateway.istio-system.svc.cluster.local"] 2093 ports: 2094 - number: 443 2095 targetPort: 443 2096 name: https 2097 protocol: HTTPS 2098 resolution: STATIC 2099 location: MESH_INTERNAL 2100 endpoints: 2101 - address: 1.1.1.1`, 2102 calls: []simulation.Expect{}, 2103 }, 2104 ) 2105 }