github.com/cilium/cilium@v1.16.2/operator/pkg/model/ingestion/ingress_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package ingestion 5 6 import ( 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 networkingv1 "k8s.io/api/networking/v1" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 14 "github.com/cilium/cilium/operator/pkg/model" 15 ) 16 17 var exactPathType = networkingv1.PathTypeExact 18 19 var prefixPathType = networkingv1.PathTypePrefix 20 21 var implementationSpecificPathType = networkingv1.PathTypeImplementationSpecific 22 23 var testAnnotations = map[string]string{ 24 "service.beta.kubernetes.io/dummy-load-balancer-backend-protocol": "http", 25 "service.beta.kubernetes.io/dummy-load-balancer-access-log-enabled": "true", 26 "service.alpha.kubernetes.io/dummy-load-balancer-access-log-enabled": "true", 27 } 28 29 var defaultSecretNamespace = "default-secret-namespace" 30 31 var defaultSecretName = "default-secret-name" 32 33 // Add the ingress objects in 34 // https://github.com/kubernetes-sigs/ingress-controller-conformance/tree/master/features 35 // as test fixtures 36 37 // default timeout for the ingress conformance tests 38 var listenerDefaultTimeout = model.Timeout{ 39 Request: nil, 40 } 41 42 // Just a default backend should produce one simple listener. 43 var defaultBackend = networkingv1.Ingress{ 44 ObjectMeta: metav1.ObjectMeta{ 45 Name: "load-balancing", 46 Namespace: "random-namespace", 47 }, 48 Spec: networkingv1.IngressSpec{ 49 IngressClassName: stringp("cilium"), 50 DefaultBackend: &networkingv1.IngressBackend{ 51 Service: &networkingv1.IngressServiceBackend{ 52 Name: "default-backend", 53 Port: networkingv1.ServiceBackendPort{ 54 Number: 8080, 55 }, 56 }, 57 }, 58 }, 59 } 60 61 var defaultBackendLegacy = networkingv1.Ingress{ 62 ObjectMeta: metav1.ObjectMeta{ 63 Name: "load-balancing", 64 Namespace: "random-namespace", 65 Annotations: map[string]string{"kubernetes.io/ingress.class": "cilium"}, 66 }, 67 Spec: networkingv1.IngressSpec{ 68 DefaultBackend: &networkingv1.IngressBackend{ 69 Service: &networkingv1.IngressServiceBackend{ 70 Name: "default-backend", 71 Port: networkingv1.ServiceBackendPort{ 72 Number: 8080, 73 }, 74 }, 75 }, 76 }, 77 } 78 79 var defaultBackendLegacyOverride = networkingv1.Ingress{ 80 ObjectMeta: metav1.ObjectMeta{ 81 Name: "load-balancing", 82 Namespace: "random-namespace", 83 Annotations: map[string]string{"kubernetes.io/ingress.class": "cilium"}, 84 }, 85 Spec: networkingv1.IngressSpec{ 86 IngressClassName: stringp("contour"), 87 DefaultBackend: &networkingv1.IngressBackend{ 88 Service: &networkingv1.IngressServiceBackend{ 89 Name: "default-backend", 90 Port: networkingv1.ServiceBackendPort{ 91 Number: 8080, 92 }, 93 }, 94 }, 95 }, 96 } 97 98 var defaultBackendListeners = []model.HTTPListener{ 99 { 100 Sources: []model.FullyQualifiedResource{ 101 { 102 Name: "load-balancing", 103 Namespace: "random-namespace", 104 Version: "v1", 105 Kind: "Ingress", 106 }, 107 }, 108 Port: 80, 109 Hostname: "*", 110 Routes: []model.HTTPRoute{ 111 { 112 Backends: []model.Backend{ 113 { 114 Name: "default-backend", 115 Namespace: "random-namespace", 116 Port: &model.BackendPort{ 117 Port: 8080, 118 }, 119 }, 120 }, 121 Timeout: listenerDefaultTimeout, 122 }, 123 }, 124 }, 125 } 126 127 var defaultBackendListenersWithRequestTimeout = []model.HTTPListener{ 128 { 129 Sources: []model.FullyQualifiedResource{ 130 { 131 Name: "load-balancing", 132 Namespace: "random-namespace", 133 Version: "v1", 134 Kind: "Ingress", 135 }, 136 }, 137 Port: 80, 138 Hostname: "*", 139 Routes: []model.HTTPRoute{ 140 { 141 Backends: []model.Backend{ 142 { 143 Name: "default-backend", 144 Namespace: "random-namespace", 145 Port: &model.BackendPort{ 146 Port: 8080, 147 }, 148 }, 149 }, 150 Timeout: model.Timeout{ 151 Request: model.AddressOf(time.Second * 10), 152 }, 153 }, 154 }, 155 }, 156 } 157 158 // Ingress Conformance test resources 159 160 // The hostRules resource from the ingress conformance test should produce 161 // three listeners, one for host with no TLS config, then one insecure and one 162 // secure for the host with TLS config. 163 var hostRules = networkingv1.Ingress{ 164 ObjectMeta: metav1.ObjectMeta{ 165 Name: "host-rules", 166 Namespace: "random-namespace", 167 }, 168 Spec: networkingv1.IngressSpec{ 169 TLS: []networkingv1.IngressTLS{ 170 { 171 Hosts: []string{"foo.bar.com"}, 172 SecretName: "conformance-tls", 173 }, 174 }, 175 Rules: []networkingv1.IngressRule{ 176 { 177 Host: "*.foo.com", 178 IngressRuleValue: networkingv1.IngressRuleValue{ 179 HTTP: &networkingv1.HTTPIngressRuleValue{ 180 Paths: []networkingv1.HTTPIngressPath{ 181 { 182 Path: "/", 183 Backend: networkingv1.IngressBackend{ 184 Service: &networkingv1.IngressServiceBackend{ 185 Name: "wildcard-foo-com", 186 Port: networkingv1.ServiceBackendPort{ 187 Number: 8080, 188 }, 189 }, 190 }, 191 PathType: &prefixPathType, 192 }, 193 }, 194 }, 195 }, 196 }, 197 { 198 Host: "foo.bar.com", 199 IngressRuleValue: networkingv1.IngressRuleValue{ 200 HTTP: &networkingv1.HTTPIngressRuleValue{ 201 Paths: []networkingv1.HTTPIngressPath{ 202 { 203 Path: "/", 204 Backend: networkingv1.IngressBackend{ 205 Service: &networkingv1.IngressServiceBackend{ 206 Name: "foo-bar-com", 207 Port: networkingv1.ServiceBackendPort{ 208 Name: "http", 209 }, 210 }, 211 }, 212 PathType: &prefixPathType, 213 }, 214 }, 215 }, 216 }, 217 }, 218 }, 219 }, 220 } 221 222 var hostRulesListeners = []model.HTTPListener{ 223 { 224 Name: "ing-host-rules-random-namespace-*.foo.com", 225 Sources: []model.FullyQualifiedResource{ 226 { 227 Name: "host-rules", 228 Namespace: "random-namespace", 229 Version: "v1", 230 Kind: "Ingress", 231 }, 232 }, 233 Port: 80, 234 Hostname: "*.foo.com", 235 Routes: []model.HTTPRoute{ 236 { 237 PathMatch: model.StringMatch{ 238 Prefix: "/", 239 }, 240 Backends: []model.Backend{ 241 { 242 Name: "wildcard-foo-com", 243 Namespace: "random-namespace", 244 Port: &model.BackendPort{ 245 Port: 8080, 246 }, 247 }, 248 }, 249 Timeout: listenerDefaultTimeout, 250 }, 251 }, 252 }, 253 { 254 Name: "ing-host-rules-random-namespace-foo.bar.com", 255 Sources: []model.FullyQualifiedResource{ 256 { 257 Name: "host-rules", 258 Namespace: "random-namespace", 259 Version: "v1", 260 Kind: "Ingress", 261 }, 262 }, 263 Port: 80, 264 Hostname: "foo.bar.com", 265 Routes: []model.HTTPRoute{ 266 { 267 PathMatch: model.StringMatch{ 268 Prefix: "/", 269 }, 270 Backends: []model.Backend{ 271 { 272 Name: "foo-bar-com", 273 Namespace: "random-namespace", 274 Port: &model.BackendPort{ 275 Name: "http", 276 }, 277 }, 278 }, 279 Timeout: listenerDefaultTimeout, 280 }, 281 }, 282 }, 283 { 284 Name: "ing-host-rules-random-namespace-foo.bar.com", 285 Sources: []model.FullyQualifiedResource{ 286 { 287 Name: "host-rules", 288 Namespace: "random-namespace", 289 Version: "v1", 290 Kind: "Ingress", 291 }, 292 }, 293 Port: 443, 294 Hostname: "foo.bar.com", 295 TLS: []model.TLSSecret{ 296 { 297 Name: "conformance-tls", 298 Namespace: "random-namespace", 299 }, 300 }, 301 Routes: []model.HTTPRoute{ 302 { 303 PathMatch: model.StringMatch{ 304 Prefix: "/", 305 }, 306 Backends: []model.Backend{ 307 { 308 Name: "foo-bar-com", 309 Namespace: "random-namespace", 310 Port: &model.BackendPort{ 311 Name: "http", 312 }, 313 }, 314 }, 315 Timeout: listenerDefaultTimeout, 316 }, 317 }, 318 }, 319 } 320 321 // The pathRules resource should produce four listeners, one for each host 322 // used in the Ingress. 323 324 var pathRules = networkingv1.Ingress{ 325 ObjectMeta: metav1.ObjectMeta{ 326 Name: "path-rules", 327 Namespace: "random-namespace", 328 }, 329 Spec: networkingv1.IngressSpec{ 330 Rules: []networkingv1.IngressRule{ 331 { 332 Host: "exact-path-rules", 333 IngressRuleValue: networkingv1.IngressRuleValue{ 334 HTTP: &networkingv1.HTTPIngressRuleValue{ 335 Paths: []networkingv1.HTTPIngressPath{ 336 { 337 Path: "/foo", 338 Backend: networkingv1.IngressBackend{ 339 Service: &networkingv1.IngressServiceBackend{ 340 Name: "foo-exact", 341 Port: networkingv1.ServiceBackendPort{ 342 Number: 8080, 343 }, 344 }, 345 }, 346 PathType: &exactPathType, 347 }, 348 }, 349 }, 350 }, 351 }, 352 { 353 Host: "prefix-path-rules", 354 IngressRuleValue: networkingv1.IngressRuleValue{ 355 HTTP: &networkingv1.HTTPIngressRuleValue{ 356 Paths: []networkingv1.HTTPIngressPath{ 357 { 358 Path: "/foo", 359 Backend: networkingv1.IngressBackend{ 360 Service: &networkingv1.IngressServiceBackend{ 361 Name: "foo-prefix", 362 Port: networkingv1.ServiceBackendPort{ 363 Number: 8080, 364 }, 365 }, 366 }, 367 PathType: &prefixPathType, 368 }, 369 { 370 Path: "/aaa/bbb", 371 Backend: networkingv1.IngressBackend{ 372 Service: &networkingv1.IngressServiceBackend{ 373 Name: "aaa-slash-bbb-prefix", 374 Port: networkingv1.ServiceBackendPort{ 375 Number: 8080, 376 }, 377 }, 378 }, 379 PathType: &prefixPathType, 380 }, 381 { 382 Path: "/aaa", 383 Backend: networkingv1.IngressBackend{ 384 Service: &networkingv1.IngressServiceBackend{ 385 Name: "aaa-prefix", 386 Port: networkingv1.ServiceBackendPort{ 387 Number: 8080, 388 }, 389 }, 390 }, 391 PathType: &prefixPathType, 392 }, 393 }, 394 }, 395 }, 396 }, 397 { 398 Host: "mixed-path-rules", 399 IngressRuleValue: networkingv1.IngressRuleValue{ 400 HTTP: &networkingv1.HTTPIngressRuleValue{ 401 Paths: []networkingv1.HTTPIngressPath{ 402 { 403 Path: "/foo", 404 Backend: networkingv1.IngressBackend{ 405 Service: &networkingv1.IngressServiceBackend{ 406 Name: "foo-prefix", 407 Port: networkingv1.ServiceBackendPort{ 408 Number: 8080, 409 }, 410 }, 411 }, 412 PathType: &prefixPathType, 413 }, 414 { 415 Path: "/foo", 416 Backend: networkingv1.IngressBackend{ 417 Service: &networkingv1.IngressServiceBackend{ 418 Name: "foo-exact", 419 Port: networkingv1.ServiceBackendPort{ 420 Number: 8080, 421 }, 422 }, 423 }, 424 PathType: &exactPathType, 425 }, 426 }, 427 }, 428 }, 429 }, 430 { 431 Host: "trailing-slash-path-rules", 432 IngressRuleValue: networkingv1.IngressRuleValue{ 433 HTTP: &networkingv1.HTTPIngressRuleValue{ 434 Paths: []networkingv1.HTTPIngressPath{ 435 { 436 Path: "/aaa/bbb/", 437 Backend: networkingv1.IngressBackend{ 438 Service: &networkingv1.IngressServiceBackend{ 439 Name: "aaa-slash-bbb-slash-prefix", 440 Port: networkingv1.ServiceBackendPort{ 441 Number: 8080, 442 }, 443 }, 444 }, 445 PathType: &prefixPathType, 446 }, 447 { 448 Path: "/foo/", 449 Backend: networkingv1.IngressBackend{ 450 Service: &networkingv1.IngressServiceBackend{ 451 Name: "foo-slash-exact", 452 Port: networkingv1.ServiceBackendPort{ 453 Number: 8080, 454 }, 455 }, 456 }, 457 PathType: &exactPathType, 458 }, 459 }, 460 }, 461 }, 462 }, 463 }, 464 }, 465 } 466 467 var pathRulesListeners = []model.HTTPListener{ 468 { 469 Name: "ing-path-rules-random-namespace-exact-path-rules", 470 Sources: []model.FullyQualifiedResource{ 471 { 472 Name: "path-rules", 473 Namespace: "random-namespace", 474 Version: "v1", 475 Kind: "Ingress", 476 }, 477 }, 478 Port: 80, 479 Hostname: "exact-path-rules", 480 Routes: []model.HTTPRoute{ 481 { 482 PathMatch: model.StringMatch{ 483 Exact: "/foo", 484 }, 485 Backends: []model.Backend{ 486 { 487 Name: "foo-exact", 488 Namespace: "random-namespace", 489 Port: &model.BackendPort{ 490 Port: 8080, 491 }, 492 }, 493 }, 494 Timeout: listenerDefaultTimeout, 495 }, 496 }, 497 }, 498 { 499 Name: "ing-path-rules-random-namespace-mixed-path-rules", 500 Sources: []model.FullyQualifiedResource{ 501 { 502 Name: "path-rules", 503 Namespace: "random-namespace", 504 Version: "v1", 505 Kind: "Ingress", 506 }, 507 }, 508 Port: 80, 509 Hostname: "mixed-path-rules", 510 Routes: []model.HTTPRoute{ 511 { 512 PathMatch: model.StringMatch{ 513 Prefix: "/foo", 514 }, 515 Backends: []model.Backend{ 516 { 517 Name: "foo-prefix", 518 Namespace: "random-namespace", 519 Port: &model.BackendPort{ 520 Port: 8080, 521 }, 522 }, 523 }, 524 Timeout: listenerDefaultTimeout, 525 }, 526 { 527 PathMatch: model.StringMatch{ 528 Exact: "/foo", 529 }, 530 Backends: []model.Backend{ 531 { 532 Name: "foo-exact", 533 Namespace: "random-namespace", 534 Port: &model.BackendPort{ 535 Port: 8080, 536 }, 537 }, 538 }, 539 Timeout: listenerDefaultTimeout, 540 }, 541 }, 542 }, 543 { 544 Name: "ing-path-rules-random-namespace-prefix-path-rules", 545 Sources: []model.FullyQualifiedResource{ 546 { 547 Name: "path-rules", 548 Namespace: "random-namespace", 549 Version: "v1", 550 Kind: "Ingress", 551 }, 552 }, 553 Port: 80, 554 Hostname: "prefix-path-rules", 555 Routes: []model.HTTPRoute{ 556 { 557 PathMatch: model.StringMatch{ 558 Prefix: "/foo", 559 }, 560 Backends: []model.Backend{ 561 { 562 Name: "foo-prefix", 563 Namespace: "random-namespace", 564 Port: &model.BackendPort{ 565 Port: 8080, 566 }, 567 }, 568 }, 569 Timeout: listenerDefaultTimeout, 570 }, 571 { 572 PathMatch: model.StringMatch{ 573 Prefix: "/aaa/bbb", 574 }, 575 Backends: []model.Backend{ 576 { 577 Name: "aaa-slash-bbb-prefix", 578 Namespace: "random-namespace", 579 Port: &model.BackendPort{ 580 Port: 8080, 581 }, 582 }, 583 }, 584 Timeout: listenerDefaultTimeout, 585 }, 586 { 587 PathMatch: model.StringMatch{ 588 Prefix: "/aaa", 589 }, 590 Backends: []model.Backend{ 591 { 592 Name: "aaa-prefix", 593 Namespace: "random-namespace", 594 Port: &model.BackendPort{ 595 Port: 8080, 596 }, 597 }, 598 }, 599 Timeout: listenerDefaultTimeout, 600 }, 601 }, 602 }, 603 { 604 Name: "ing-path-rules-random-namespace-trailing-slash-path-rules", 605 Sources: []model.FullyQualifiedResource{ 606 { 607 Name: "path-rules", 608 Namespace: "random-namespace", 609 Version: "v1", 610 Kind: "Ingress", 611 }, 612 }, 613 Port: 80, 614 Hostname: "trailing-slash-path-rules", 615 Routes: []model.HTTPRoute{ 616 { 617 PathMatch: model.StringMatch{ 618 Prefix: "/aaa/bbb/", 619 }, 620 Backends: []model.Backend{ 621 { 622 Name: "aaa-slash-bbb-slash-prefix", 623 Namespace: "random-namespace", 624 Port: &model.BackendPort{ 625 Port: 8080, 626 }, 627 }, 628 }, 629 Timeout: listenerDefaultTimeout, 630 }, 631 { 632 PathMatch: model.StringMatch{ 633 Exact: "/foo/", 634 }, 635 Backends: []model.Backend{ 636 { 637 Name: "foo-slash-exact", 638 Namespace: "random-namespace", 639 Port: &model.BackendPort{ 640 Port: 8080, 641 }, 642 }, 643 }, 644 Timeout: listenerDefaultTimeout, 645 }, 646 }, 647 }, 648 } 649 650 // The complexIngress resource from the operator/pkg/ingress testsuite should 651 // produce three Listeners with identical routes, for the default host `*`, 652 // and then the two TLS hostnames. 653 var complexIngress = networkingv1.Ingress{ 654 ObjectMeta: metav1.ObjectMeta{ 655 Name: "dummy-ingress", 656 Namespace: "dummy-namespace", 657 Annotations: testAnnotations, 658 Labels: testAnnotations, 659 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 660 }, 661 Spec: networkingv1.IngressSpec{ 662 IngressClassName: stringp("cilium"), 663 DefaultBackend: &networkingv1.IngressBackend{ 664 Service: &networkingv1.IngressServiceBackend{ 665 Name: "default-backend", 666 Port: networkingv1.ServiceBackendPort{ 667 Number: 8080, 668 }, 669 }, 670 }, 671 TLS: []networkingv1.IngressTLS{ 672 { 673 Hosts: []string{"very-secure.server.com"}, 674 SecretName: "tls-very-secure-server-com", 675 }, 676 { 677 Hosts: []string{ 678 "another-very-secure.server.com", 679 "not-in-use.another-very-secure.server.com", 680 }, 681 SecretName: "tls-another-very-secure-server-com", 682 }, 683 }, 684 Rules: []networkingv1.IngressRule{ 685 { 686 IngressRuleValue: networkingv1.IngressRuleValue{ 687 HTTP: &networkingv1.HTTPIngressRuleValue{ 688 Paths: []networkingv1.HTTPIngressPath{ 689 { 690 Path: "/dummy-path", 691 Backend: networkingv1.IngressBackend{ 692 Service: &networkingv1.IngressServiceBackend{ 693 Name: "dummy-backend", 694 Port: networkingv1.ServiceBackendPort{ 695 Number: 8080, 696 }, 697 }, 698 }, 699 PathType: &exactPathType, 700 }, 701 { 702 Path: "/another-dummy-path", 703 Backend: networkingv1.IngressBackend{ 704 Service: &networkingv1.IngressServiceBackend{ 705 Name: "another-dummy-backend", 706 Port: networkingv1.ServiceBackendPort{ 707 Number: 8081, 708 }, 709 }, 710 }, 711 PathType: &prefixPathType, 712 }, 713 }, 714 }, 715 }, 716 }, 717 }, 718 }, 719 } 720 721 var complexIngressListeners = []model.HTTPListener{ 722 { 723 Sources: []model.FullyQualifiedResource{ 724 { 725 Name: "dummy-ingress", 726 Namespace: "dummy-namespace", 727 Version: "v1", 728 Kind: "Ingress", 729 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 730 }, 731 }, 732 Port: 80, 733 Hostname: "*", 734 Routes: []model.HTTPRoute{ 735 { 736 Backends: []model.Backend{ 737 { 738 Name: "default-backend", 739 Namespace: "dummy-namespace", 740 Port: &model.BackendPort{ 741 Port: 8080, 742 }, 743 }, 744 }, 745 Timeout: listenerDefaultTimeout, 746 }, 747 { 748 PathMatch: model.StringMatch{ 749 Exact: "/dummy-path", 750 }, 751 Backends: []model.Backend{ 752 { 753 Name: "dummy-backend", 754 Namespace: "dummy-namespace", 755 Port: &model.BackendPort{ 756 Port: 8080, 757 }, 758 }, 759 }, 760 Timeout: listenerDefaultTimeout, 761 }, 762 { 763 PathMatch: model.StringMatch{ 764 Prefix: "/another-dummy-path", 765 }, 766 Backends: []model.Backend{ 767 { 768 Name: "another-dummy-backend", 769 Namespace: "dummy-namespace", 770 Port: &model.BackendPort{ 771 Port: 8081, 772 }, 773 }, 774 }, 775 Timeout: listenerDefaultTimeout, 776 }, 777 }, 778 }, 779 { 780 Sources: []model.FullyQualifiedResource{ 781 { 782 Name: "dummy-ingress", 783 Namespace: "dummy-namespace", 784 Version: "v1", 785 Kind: "Ingress", 786 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 787 }, 788 }, 789 Port: 443, 790 Hostname: "another-very-secure.server.com", 791 TLS: []model.TLSSecret{ 792 { 793 Name: "tls-another-very-secure-server-com", 794 Namespace: "dummy-namespace", 795 }, 796 }, 797 Routes: []model.HTTPRoute{ 798 { 799 Backends: []model.Backend{ 800 { 801 Name: "default-backend", 802 Namespace: "dummy-namespace", 803 Port: &model.BackendPort{ 804 Port: 8080, 805 }, 806 }, 807 }, 808 Timeout: listenerDefaultTimeout, 809 }, 810 { 811 PathMatch: model.StringMatch{ 812 Exact: "/dummy-path", 813 }, 814 Backends: []model.Backend{ 815 { 816 Name: "dummy-backend", 817 Namespace: "dummy-namespace", 818 Port: &model.BackendPort{ 819 Port: 8080, 820 }, 821 }, 822 }, 823 Timeout: listenerDefaultTimeout, 824 }, 825 { 826 PathMatch: model.StringMatch{ 827 Prefix: "/another-dummy-path", 828 }, 829 Backends: []model.Backend{ 830 { 831 Name: "another-dummy-backend", 832 Namespace: "dummy-namespace", 833 Port: &model.BackendPort{ 834 Port: 8081, 835 }, 836 }, 837 }, 838 Timeout: listenerDefaultTimeout, 839 }, 840 }, 841 }, 842 { 843 Sources: []model.FullyQualifiedResource{ 844 { 845 Name: "dummy-ingress", 846 Namespace: "dummy-namespace", 847 Version: "v1", 848 Kind: "Ingress", 849 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 850 }, 851 }, 852 Port: 443, 853 Hostname: "not-in-use.another-very-secure.server.com", 854 TLS: []model.TLSSecret{ 855 { 856 Name: "tls-another-very-secure-server-com", 857 Namespace: "dummy-namespace", 858 }, 859 }, 860 Routes: []model.HTTPRoute{ 861 { 862 Backends: []model.Backend{ 863 { 864 Name: "default-backend", 865 Namespace: "dummy-namespace", 866 Port: &model.BackendPort{ 867 Port: 8080, 868 }, 869 }, 870 }, 871 Timeout: listenerDefaultTimeout, 872 }, 873 { 874 PathMatch: model.StringMatch{ 875 Exact: "/dummy-path", 876 }, 877 Backends: []model.Backend{ 878 { 879 Name: "dummy-backend", 880 Namespace: "dummy-namespace", 881 Port: &model.BackendPort{ 882 Port: 8080, 883 }, 884 }, 885 }, 886 Timeout: listenerDefaultTimeout, 887 }, 888 { 889 PathMatch: model.StringMatch{ 890 Prefix: "/another-dummy-path", 891 }, 892 Backends: []model.Backend{ 893 { 894 Name: "another-dummy-backend", 895 Namespace: "dummy-namespace", 896 Port: &model.BackendPort{ 897 Port: 8081, 898 }, 899 }, 900 }, 901 Timeout: listenerDefaultTimeout, 902 }, 903 }, 904 }, 905 { 906 Sources: []model.FullyQualifiedResource{ 907 { 908 Name: "dummy-ingress", 909 Namespace: "dummy-namespace", 910 Version: "v1", 911 Kind: "Ingress", 912 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 913 }, 914 }, 915 Port: 443, 916 Hostname: "very-secure.server.com", 917 TLS: []model.TLSSecret{ 918 { 919 Name: "tls-very-secure-server-com", 920 Namespace: "dummy-namespace", 921 }, 922 }, 923 Routes: []model.HTTPRoute{ 924 { 925 Backends: []model.Backend{ 926 { 927 Name: "default-backend", 928 Namespace: "dummy-namespace", 929 Port: &model.BackendPort{ 930 Port: 8080, 931 }, 932 }, 933 }, 934 Timeout: listenerDefaultTimeout, 935 }, 936 { 937 PathMatch: model.StringMatch{ 938 Exact: "/dummy-path", 939 }, 940 Backends: []model.Backend{ 941 { 942 Name: "dummy-backend", 943 Namespace: "dummy-namespace", 944 Port: &model.BackendPort{ 945 Port: 8080, 946 }, 947 }, 948 }, 949 Timeout: listenerDefaultTimeout, 950 }, 951 { 952 PathMatch: model.StringMatch{ 953 Prefix: "/another-dummy-path", 954 }, 955 Backends: []model.Backend{ 956 { 957 Name: "another-dummy-backend", 958 Namespace: "dummy-namespace", 959 Port: &model.BackendPort{ 960 Port: 8081, 961 }, 962 }, 963 }, 964 Timeout: listenerDefaultTimeout, 965 }, 966 }, 967 }, 968 } 969 970 // complexNodePortIngress is same as complexIngress but with NodePort service 971 var complexNodePortIngress = networkingv1.Ingress{ 972 ObjectMeta: metav1.ObjectMeta{ 973 Name: "dummy-ingress", 974 Namespace: "dummy-namespace", 975 Annotations: map[string]string{ 976 "ingress.cilium.io/service-type": "NodePort", 977 "ingress.cilium.io/insecure-node-port": "30000", 978 "ingress.cilium.io/secure-node-port": "30001", 979 }, 980 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 981 }, 982 Spec: networkingv1.IngressSpec{ 983 IngressClassName: stringp("cilium"), 984 DefaultBackend: &networkingv1.IngressBackend{ 985 Service: &networkingv1.IngressServiceBackend{ 986 Name: "default-backend", 987 Port: networkingv1.ServiceBackendPort{ 988 Number: 8080, 989 }, 990 }, 991 }, 992 TLS: []networkingv1.IngressTLS{ 993 { 994 Hosts: []string{"very-secure.server.com"}, 995 SecretName: "tls-very-secure-server-com", 996 }, 997 { 998 Hosts: []string{ 999 "another-very-secure.server.com", 1000 "not-in-use.another-very-secure.server.com", 1001 }, 1002 SecretName: "tls-another-very-secure-server-com", 1003 }, 1004 }, 1005 Rules: []networkingv1.IngressRule{ 1006 { 1007 IngressRuleValue: networkingv1.IngressRuleValue{ 1008 HTTP: &networkingv1.HTTPIngressRuleValue{ 1009 Paths: []networkingv1.HTTPIngressPath{ 1010 { 1011 Path: "/dummy-path", 1012 Backend: networkingv1.IngressBackend{ 1013 Service: &networkingv1.IngressServiceBackend{ 1014 Name: "dummy-backend", 1015 Port: networkingv1.ServiceBackendPort{ 1016 Number: 8080, 1017 }, 1018 }, 1019 }, 1020 PathType: &exactPathType, 1021 }, 1022 { 1023 Path: "/another-dummy-path", 1024 Backend: networkingv1.IngressBackend{ 1025 Service: &networkingv1.IngressServiceBackend{ 1026 Name: "another-dummy-backend", 1027 Port: networkingv1.ServiceBackendPort{ 1028 Number: 8081, 1029 }, 1030 }, 1031 }, 1032 PathType: &prefixPathType, 1033 }, 1034 }, 1035 }, 1036 }, 1037 }, 1038 }, 1039 }, 1040 } 1041 1042 var complexNodePortIngressListeners = []model.HTTPListener{ 1043 { 1044 Sources: []model.FullyQualifiedResource{ 1045 { 1046 Name: "dummy-ingress", 1047 Namespace: "dummy-namespace", 1048 Version: "v1", 1049 Kind: "Ingress", 1050 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 1051 }, 1052 }, 1053 Port: 80, 1054 Hostname: "*", 1055 Routes: []model.HTTPRoute{ 1056 { 1057 Backends: []model.Backend{ 1058 { 1059 Name: "default-backend", 1060 Namespace: "dummy-namespace", 1061 Port: &model.BackendPort{ 1062 Port: 8080, 1063 }, 1064 }, 1065 }, 1066 Timeout: listenerDefaultTimeout, 1067 }, 1068 { 1069 PathMatch: model.StringMatch{ 1070 Exact: "/dummy-path", 1071 }, 1072 Backends: []model.Backend{ 1073 { 1074 Name: "dummy-backend", 1075 Namespace: "dummy-namespace", 1076 Port: &model.BackendPort{ 1077 Port: 8080, 1078 }, 1079 }, 1080 }, 1081 Timeout: listenerDefaultTimeout, 1082 }, 1083 { 1084 PathMatch: model.StringMatch{ 1085 Prefix: "/another-dummy-path", 1086 }, 1087 Backends: []model.Backend{ 1088 { 1089 Name: "another-dummy-backend", 1090 Namespace: "dummy-namespace", 1091 Port: &model.BackendPort{ 1092 Port: 8081, 1093 }, 1094 }, 1095 }, 1096 Timeout: listenerDefaultTimeout, 1097 }, 1098 }, 1099 Service: &model.Service{ 1100 Type: "NodePort", 1101 InsecureNodePort: uint32p(30000), 1102 SecureNodePort: uint32p(30001), 1103 }, 1104 }, 1105 { 1106 Sources: []model.FullyQualifiedResource{ 1107 { 1108 Name: "dummy-ingress", 1109 Namespace: "dummy-namespace", 1110 Version: "v1", 1111 Kind: "Ingress", 1112 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 1113 }, 1114 }, 1115 Port: 443, 1116 Hostname: "another-very-secure.server.com", 1117 TLS: []model.TLSSecret{ 1118 { 1119 Name: "tls-another-very-secure-server-com", 1120 Namespace: "dummy-namespace", 1121 }, 1122 }, 1123 Routes: []model.HTTPRoute{ 1124 { 1125 Backends: []model.Backend{ 1126 { 1127 Name: "default-backend", 1128 Namespace: "dummy-namespace", 1129 Port: &model.BackendPort{ 1130 Port: 8080, 1131 }, 1132 }, 1133 }, 1134 Timeout: listenerDefaultTimeout, 1135 }, 1136 { 1137 PathMatch: model.StringMatch{ 1138 Exact: "/dummy-path", 1139 }, 1140 Backends: []model.Backend{ 1141 { 1142 Name: "dummy-backend", 1143 Namespace: "dummy-namespace", 1144 Port: &model.BackendPort{ 1145 Port: 8080, 1146 }, 1147 }, 1148 }, 1149 Timeout: listenerDefaultTimeout, 1150 }, 1151 { 1152 PathMatch: model.StringMatch{ 1153 Prefix: "/another-dummy-path", 1154 }, 1155 Backends: []model.Backend{ 1156 { 1157 Name: "another-dummy-backend", 1158 Namespace: "dummy-namespace", 1159 Port: &model.BackendPort{ 1160 Port: 8081, 1161 }, 1162 }, 1163 }, 1164 Timeout: listenerDefaultTimeout, 1165 }, 1166 }, 1167 Service: &model.Service{ 1168 Type: "NodePort", 1169 InsecureNodePort: uint32p(30000), 1170 SecureNodePort: uint32p(30001), 1171 }, 1172 }, 1173 { 1174 Sources: []model.FullyQualifiedResource{ 1175 { 1176 Name: "dummy-ingress", 1177 Namespace: "dummy-namespace", 1178 Version: "v1", 1179 Kind: "Ingress", 1180 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 1181 }, 1182 }, 1183 Port: 443, 1184 Hostname: "not-in-use.another-very-secure.server.com", 1185 TLS: []model.TLSSecret{ 1186 { 1187 Name: "tls-another-very-secure-server-com", 1188 Namespace: "dummy-namespace", 1189 }, 1190 }, 1191 Routes: []model.HTTPRoute{ 1192 { 1193 Backends: []model.Backend{ 1194 { 1195 Name: "default-backend", 1196 Namespace: "dummy-namespace", 1197 Port: &model.BackendPort{ 1198 Port: 8080, 1199 }, 1200 }, 1201 }, 1202 Timeout: listenerDefaultTimeout, 1203 }, 1204 { 1205 PathMatch: model.StringMatch{ 1206 Exact: "/dummy-path", 1207 }, 1208 Backends: []model.Backend{ 1209 { 1210 Name: "dummy-backend", 1211 Namespace: "dummy-namespace", 1212 Port: &model.BackendPort{ 1213 Port: 8080, 1214 }, 1215 }, 1216 }, 1217 Timeout: listenerDefaultTimeout, 1218 }, 1219 { 1220 PathMatch: model.StringMatch{ 1221 Prefix: "/another-dummy-path", 1222 }, 1223 Backends: []model.Backend{ 1224 { 1225 Name: "another-dummy-backend", 1226 Namespace: "dummy-namespace", 1227 Port: &model.BackendPort{ 1228 Port: 8081, 1229 }, 1230 }, 1231 }, 1232 Timeout: listenerDefaultTimeout, 1233 }, 1234 }, 1235 Service: &model.Service{ 1236 Type: "NodePort", 1237 InsecureNodePort: uint32p(30000), 1238 SecureNodePort: uint32p(30001), 1239 }, 1240 }, 1241 { 1242 Sources: []model.FullyQualifiedResource{ 1243 { 1244 Name: "dummy-ingress", 1245 Namespace: "dummy-namespace", 1246 Version: "v1", 1247 Kind: "Ingress", 1248 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 1249 }, 1250 }, 1251 Port: 443, 1252 Hostname: "very-secure.server.com", 1253 TLS: []model.TLSSecret{ 1254 { 1255 Name: "tls-very-secure-server-com", 1256 Namespace: "dummy-namespace", 1257 }, 1258 }, 1259 Routes: []model.HTTPRoute{ 1260 { 1261 Backends: []model.Backend{ 1262 { 1263 Name: "default-backend", 1264 Namespace: "dummy-namespace", 1265 Port: &model.BackendPort{ 1266 Port: 8080, 1267 }, 1268 }, 1269 }, 1270 Timeout: listenerDefaultTimeout, 1271 }, 1272 { 1273 PathMatch: model.StringMatch{ 1274 Exact: "/dummy-path", 1275 }, 1276 Backends: []model.Backend{ 1277 { 1278 Name: "dummy-backend", 1279 Namespace: "dummy-namespace", 1280 Port: &model.BackendPort{ 1281 Port: 8080, 1282 }, 1283 }, 1284 }, 1285 Timeout: listenerDefaultTimeout, 1286 }, 1287 { 1288 PathMatch: model.StringMatch{ 1289 Prefix: "/another-dummy-path", 1290 }, 1291 Backends: []model.Backend{ 1292 { 1293 Name: "another-dummy-backend", 1294 Namespace: "dummy-namespace", 1295 Port: &model.BackendPort{ 1296 Port: 8081, 1297 }, 1298 }, 1299 }, 1300 Timeout: listenerDefaultTimeout, 1301 }, 1302 }, 1303 Service: &model.Service{ 1304 Type: "NodePort", 1305 InsecureNodePort: uint32p(30000), 1306 SecureNodePort: uint32p(30001), 1307 }, 1308 }, 1309 } 1310 1311 // multiplePathTypes checks what happens when we have multiple path types in 1312 // the one Ingress object. 1313 // 1314 // Note that there's no sorting done at this point, the sorting is performed 1315 // in the translation step, not this ingestion step. 1316 var multiplePathTypes = networkingv1.Ingress{ 1317 ObjectMeta: metav1.ObjectMeta{ 1318 Name: "dummy-ingress", 1319 Namespace: "dummy-namespace", 1320 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 1321 }, 1322 Spec: networkingv1.IngressSpec{ 1323 IngressClassName: stringp("cilium"), 1324 Rules: []networkingv1.IngressRule{ 1325 { 1326 IngressRuleValue: networkingv1.IngressRuleValue{ 1327 HTTP: &networkingv1.HTTPIngressRuleValue{ 1328 Paths: []networkingv1.HTTPIngressPath{ 1329 { 1330 Path: "/impl", 1331 Backend: networkingv1.IngressBackend{ 1332 Service: &networkingv1.IngressServiceBackend{ 1333 Name: "dummy-backend", 1334 Port: networkingv1.ServiceBackendPort{ 1335 Number: 8080, 1336 }, 1337 }, 1338 }, 1339 PathType: &implementationSpecificPathType, 1340 }, 1341 { 1342 Path: "/", 1343 Backend: networkingv1.IngressBackend{ 1344 Service: &networkingv1.IngressServiceBackend{ 1345 Name: "another-dummy-backend", 1346 Port: networkingv1.ServiceBackendPort{ 1347 Number: 8081, 1348 }, 1349 }, 1350 }, 1351 PathType: &prefixPathType, 1352 }, 1353 { 1354 Path: "/exact", 1355 Backend: networkingv1.IngressBackend{ 1356 Service: &networkingv1.IngressServiceBackend{ 1357 Name: "another-dummy-backend", 1358 Port: networkingv1.ServiceBackendPort{ 1359 Number: 8081, 1360 }, 1361 }, 1362 }, 1363 PathType: &exactPathType, 1364 }, 1365 }, 1366 }, 1367 }, 1368 }, 1369 }, 1370 }, 1371 } 1372 1373 var multiplePathTypesListeners = []model.HTTPListener{ 1374 { 1375 Name: "ing-dummy-ingress-dummy-namespace-*", 1376 Sources: []model.FullyQualifiedResource{ 1377 { 1378 Name: "dummy-ingress", 1379 Namespace: "dummy-namespace", 1380 Version: "v1", 1381 Kind: "Ingress", 1382 UID: "d4bd3dc3-2ac5-4ab4-9dca-89c62c60177e", 1383 }, 1384 }, 1385 Port: 80, 1386 Hostname: "*", 1387 Routes: []model.HTTPRoute{ 1388 { 1389 PathMatch: model.StringMatch{ 1390 Regex: "/impl", 1391 }, 1392 Backends: []model.Backend{ 1393 { 1394 Name: "dummy-backend", 1395 Namespace: "dummy-namespace", 1396 Port: &model.BackendPort{ 1397 Port: 8080, 1398 }, 1399 }, 1400 }, 1401 Timeout: listenerDefaultTimeout, 1402 }, 1403 { 1404 PathMatch: model.StringMatch{ 1405 Prefix: "/", 1406 }, 1407 Backends: []model.Backend{ 1408 { 1409 Name: "another-dummy-backend", 1410 Namespace: "dummy-namespace", 1411 Port: &model.BackendPort{ 1412 Port: 8081, 1413 }, 1414 }, 1415 }, 1416 Timeout: listenerDefaultTimeout, 1417 }, 1418 { 1419 PathMatch: model.StringMatch{ 1420 Exact: "/exact", 1421 }, 1422 Backends: []model.Backend{ 1423 { 1424 Name: "another-dummy-backend", 1425 Namespace: "dummy-namespace", 1426 Port: &model.BackendPort{ 1427 Port: 8081, 1428 }, 1429 }, 1430 }, 1431 Timeout: listenerDefaultTimeout, 1432 }, 1433 }, 1434 }, 1435 } 1436 1437 // hostRulesForceHTTPSenabled tests the force-https annotation and should produce 1438 // three listeners, one for host with no TLS config, then one insecure and one 1439 // secure for the host with TLS config. 1440 var hostRulesForceHTTPSenabled = networkingv1.Ingress{ 1441 ObjectMeta: metav1.ObjectMeta{ 1442 Name: "host-rules", 1443 Namespace: "random-namespace", 1444 Annotations: map[string]string{ 1445 "ingress.cilium.io/force-https": "enabled", 1446 }, 1447 }, 1448 Spec: networkingv1.IngressSpec{ 1449 TLS: []networkingv1.IngressTLS{ 1450 { 1451 Hosts: []string{"foo.bar.com"}, 1452 SecretName: "conformance-tls", 1453 }, 1454 }, 1455 Rules: []networkingv1.IngressRule{ 1456 { 1457 Host: "*.foo.com", 1458 IngressRuleValue: networkingv1.IngressRuleValue{ 1459 HTTP: &networkingv1.HTTPIngressRuleValue{ 1460 Paths: []networkingv1.HTTPIngressPath{ 1461 { 1462 Path: "/", 1463 Backend: networkingv1.IngressBackend{ 1464 Service: &networkingv1.IngressServiceBackend{ 1465 Name: "wildcard-foo-com", 1466 Port: networkingv1.ServiceBackendPort{ 1467 Number: 8080, 1468 }, 1469 }, 1470 }, 1471 PathType: &prefixPathType, 1472 }, 1473 }, 1474 }, 1475 }, 1476 }, 1477 { 1478 Host: "foo.bar.com", 1479 IngressRuleValue: networkingv1.IngressRuleValue{ 1480 HTTP: &networkingv1.HTTPIngressRuleValue{ 1481 Paths: []networkingv1.HTTPIngressPath{ 1482 { 1483 Path: "/", 1484 Backend: networkingv1.IngressBackend{ 1485 Service: &networkingv1.IngressServiceBackend{ 1486 Name: "foo-bar-com", 1487 Port: networkingv1.ServiceBackendPort{ 1488 Name: "http", 1489 }, 1490 }, 1491 }, 1492 PathType: &prefixPathType, 1493 }, 1494 }, 1495 }, 1496 }, 1497 }, 1498 }, 1499 }, 1500 } 1501 1502 var hostRulesForceHTTPSenabledListeners = []model.HTTPListener{ 1503 { 1504 Name: "ing-host-rules-random-namespace-*.foo.com", 1505 Sources: []model.FullyQualifiedResource{ 1506 { 1507 Name: "host-rules", 1508 Namespace: "random-namespace", 1509 Version: "v1", 1510 Kind: "Ingress", 1511 }, 1512 }, 1513 Port: 80, 1514 Hostname: "*.foo.com", 1515 Routes: []model.HTTPRoute{ 1516 { 1517 PathMatch: model.StringMatch{ 1518 Prefix: "/", 1519 }, 1520 Backends: []model.Backend{ 1521 { 1522 Name: "wildcard-foo-com", 1523 Namespace: "random-namespace", 1524 Port: &model.BackendPort{ 1525 Port: 8080, 1526 }, 1527 }, 1528 }, 1529 Timeout: listenerDefaultTimeout, 1530 }, 1531 }, 1532 }, 1533 { 1534 Name: "ing-host-rules-random-namespace-foo.bar.com", 1535 Sources: []model.FullyQualifiedResource{ 1536 { 1537 Name: "host-rules", 1538 Namespace: "random-namespace", 1539 Version: "v1", 1540 Kind: "Ingress", 1541 }, 1542 }, 1543 Port: 80, 1544 Hostname: "foo.bar.com", 1545 Routes: []model.HTTPRoute{ 1546 { 1547 PathMatch: model.StringMatch{ 1548 Prefix: "/", 1549 }, 1550 Backends: []model.Backend{ 1551 { 1552 Name: "foo-bar-com", 1553 Namespace: "random-namespace", 1554 Port: &model.BackendPort{ 1555 Name: "http", 1556 }, 1557 }, 1558 }, 1559 Timeout: listenerDefaultTimeout, 1560 }, 1561 }, 1562 }, 1563 { 1564 Name: "ing-host-rules-random-namespace-foo.bar.com", 1565 Sources: []model.FullyQualifiedResource{ 1566 { 1567 Name: "host-rules", 1568 Namespace: "random-namespace", 1569 Version: "v1", 1570 Kind: "Ingress", 1571 }, 1572 }, 1573 Port: 443, 1574 Hostname: "foo.bar.com", 1575 TLS: []model.TLSSecret{ 1576 { 1577 Name: "conformance-tls", 1578 Namespace: "random-namespace", 1579 }, 1580 }, 1581 ForceHTTPtoHTTPSRedirect: true, 1582 Routes: []model.HTTPRoute{ 1583 { 1584 PathMatch: model.StringMatch{ 1585 Prefix: "/", 1586 }, 1587 Backends: []model.Backend{ 1588 { 1589 Name: "foo-bar-com", 1590 Namespace: "random-namespace", 1591 Port: &model.BackendPort{ 1592 Name: "http", 1593 }, 1594 }, 1595 }, 1596 Timeout: listenerDefaultTimeout, 1597 }, 1598 }, 1599 }, 1600 } 1601 1602 // forceHTTPSenabled tests the force-https annotation and should produce 1603 // three listeners, one for host with no TLS config, then one insecure and one 1604 // secure for the host with TLS config. 1605 var hostRulesForceHTTPSdisabled = networkingv1.Ingress{ 1606 ObjectMeta: metav1.ObjectMeta{ 1607 Name: "host-rules", 1608 Namespace: "random-namespace", 1609 Annotations: map[string]string{ 1610 "ingress.cilium.io/force-https": "disabled", 1611 }, 1612 }, 1613 Spec: networkingv1.IngressSpec{ 1614 TLS: []networkingv1.IngressTLS{ 1615 { 1616 Hosts: []string{"foo.bar.com"}, 1617 SecretName: "conformance-tls", 1618 }, 1619 }, 1620 Rules: []networkingv1.IngressRule{ 1621 { 1622 Host: "*.foo.com", 1623 IngressRuleValue: networkingv1.IngressRuleValue{ 1624 HTTP: &networkingv1.HTTPIngressRuleValue{ 1625 Paths: []networkingv1.HTTPIngressPath{ 1626 { 1627 Path: "/", 1628 Backend: networkingv1.IngressBackend{ 1629 Service: &networkingv1.IngressServiceBackend{ 1630 Name: "wildcard-foo-com", 1631 Port: networkingv1.ServiceBackendPort{ 1632 Number: 8080, 1633 }, 1634 }, 1635 }, 1636 PathType: &prefixPathType, 1637 }, 1638 }, 1639 }, 1640 }, 1641 }, 1642 { 1643 Host: "foo.bar.com", 1644 IngressRuleValue: networkingv1.IngressRuleValue{ 1645 HTTP: &networkingv1.HTTPIngressRuleValue{ 1646 Paths: []networkingv1.HTTPIngressPath{ 1647 { 1648 Path: "/", 1649 Backend: networkingv1.IngressBackend{ 1650 Service: &networkingv1.IngressServiceBackend{ 1651 Name: "foo-bar-com", 1652 Port: networkingv1.ServiceBackendPort{ 1653 Name: "http", 1654 }, 1655 }, 1656 }, 1657 PathType: &prefixPathType, 1658 }, 1659 }, 1660 }, 1661 }, 1662 }, 1663 }, 1664 }, 1665 } 1666 1667 var requestTimeoutAnnotationIngress = networkingv1.Ingress{ 1668 ObjectMeta: metav1.ObjectMeta{ 1669 Name: "load-balancing-request-timeout-annotation", 1670 Namespace: "random-namespace", 1671 Annotations: map[string]string{ 1672 "ingress.cilium.io/request-timeout": "10s", 1673 }, 1674 }, 1675 Spec: networkingv1.IngressSpec{ 1676 IngressClassName: stringp("cilium"), 1677 DefaultBackend: &networkingv1.IngressBackend{ 1678 Service: &networkingv1.IngressServiceBackend{ 1679 Name: "default-backend", 1680 Port: networkingv1.ServiceBackendPort{ 1681 Number: 8080, 1682 }, 1683 }, 1684 }, 1685 }, 1686 } 1687 1688 var requestTimeoutAnnotationListeners = []model.HTTPListener{ 1689 { 1690 Sources: []model.FullyQualifiedResource{ 1691 { 1692 Name: "load-balancing-request-timeout-annotation", 1693 Namespace: "random-namespace", 1694 Version: "v1", 1695 Kind: "Ingress", 1696 }, 1697 }, 1698 Port: 80, 1699 Hostname: "*", 1700 Routes: []model.HTTPRoute{ 1701 { 1702 Backends: []model.Backend{ 1703 { 1704 Name: "default-backend", 1705 Namespace: "random-namespace", 1706 Port: &model.BackendPort{ 1707 Port: 8080, 1708 }, 1709 }, 1710 }, 1711 Timeout: model.Timeout{ 1712 Request: model.AddressOf(time.Second * 10), 1713 }, 1714 }, 1715 }, 1716 }, 1717 } 1718 1719 var requestTimeoutInvalidIngress = networkingv1.Ingress{ 1720 ObjectMeta: metav1.ObjectMeta{ 1721 Name: "load-balancing-request-timeout-invalid-annotation", 1722 Namespace: "random-namespace", 1723 Annotations: map[string]string{ 1724 "ingress.cilium.io/request-timeout": "invalid-duration", 1725 }, 1726 }, 1727 Spec: networkingv1.IngressSpec{ 1728 IngressClassName: stringp("cilium"), 1729 DefaultBackend: &networkingv1.IngressBackend{ 1730 Service: &networkingv1.IngressServiceBackend{ 1731 Name: "default-backend", 1732 Port: networkingv1.ServiceBackendPort{ 1733 Number: 8080, 1734 }, 1735 }, 1736 }, 1737 }, 1738 } 1739 1740 var requestTimeoutInvalidListeners = []model.HTTPListener{ 1741 { 1742 Sources: []model.FullyQualifiedResource{ 1743 { 1744 Name: "load-balancing-request-timeout-invalid-annotation", 1745 Namespace: "random-namespace", 1746 Version: "v1", 1747 Kind: "Ingress", 1748 }, 1749 }, 1750 Port: 80, 1751 Hostname: "*", 1752 Routes: []model.HTTPRoute{ 1753 { 1754 Backends: []model.Backend{ 1755 { 1756 Name: "default-backend", 1757 Namespace: "random-namespace", 1758 Port: &model.BackendPort{ 1759 Port: 8080, 1760 }, 1761 }, 1762 }, 1763 Timeout: listenerDefaultTimeout, 1764 }, 1765 }, 1766 }, 1767 } 1768 1769 func stringp(in string) *string { 1770 return &in 1771 } 1772 1773 func uint32p(in uint32) *uint32 { 1774 return &in 1775 } 1776 1777 func removeIngressTLSsecretName(ing networkingv1.Ingress) networkingv1.Ingress { 1778 ret := networkingv1.Ingress{} 1779 ing.DeepCopyInto(&ret) 1780 for i := range ret.Spec.TLS { 1781 ret.Spec.TLS[i].SecretName = "" 1782 } 1783 return ret 1784 } 1785 1786 func removeListenersTLSsecret(listeners []model.HTTPListener) []model.HTTPListener { 1787 ret := []model.HTTPListener{} 1788 for _, listener := range listeners { 1789 listener.TLS = nil 1790 ret = append(ret, listener) 1791 } 1792 return ret 1793 } 1794 1795 func useDefaultListenersTLSsecret(listeners []model.HTTPListener) []model.HTTPListener { 1796 ret := []model.HTTPListener{} 1797 for _, listener := range listeners { 1798 if listener.Port == 443 { 1799 listener.TLS = []model.TLSSecret{ 1800 {Namespace: defaultSecretNamespace, Name: defaultSecretName}, 1801 } 1802 } 1803 ret = append(ret, listener) 1804 } 1805 return ret 1806 } 1807 1808 func removeIngressHTTPRuleValues(ing networkingv1.Ingress) networkingv1.Ingress { 1809 var rules []networkingv1.IngressRule 1810 1811 for _, r := range ing.Spec.Rules { 1812 r.HTTP = nil 1813 rules = append(rules, r) 1814 } 1815 1816 ret := networkingv1.Ingress{} 1817 ing.DeepCopyInto(&ret) 1818 ret.Spec.Rules = rules 1819 1820 return ret 1821 } 1822 1823 type testcase struct { 1824 ingress networkingv1.Ingress 1825 defaultSecret bool 1826 enforceHTTPS bool 1827 requestTimeout time.Duration 1828 want []model.HTTPListener 1829 } 1830 1831 func TestIngress(t *testing.T) { 1832 tests := map[string]testcase{ 1833 "conformance default backend test": { 1834 ingress: defaultBackend, 1835 want: defaultBackendListeners, 1836 }, 1837 "conformance default backend (legacy annotation) test": { 1838 ingress: defaultBackendLegacy, 1839 want: defaultBackendListeners, 1840 }, 1841 "conformance default backend (legacy + new) test": { 1842 ingress: defaultBackendLegacyOverride, 1843 want: defaultBackendListeners, 1844 }, 1845 "cilium test ingress without http rules": { 1846 ingress: removeIngressHTTPRuleValues(hostRules), 1847 want: []model.HTTPListener{}, 1848 }, 1849 "conformance host rules test": { 1850 ingress: hostRules, 1851 want: hostRulesListeners, 1852 }, 1853 "conformance host rules test without SecretName": { 1854 ingress: removeIngressTLSsecretName(hostRules), 1855 want: removeListenersTLSsecret(hostRulesListeners), 1856 }, 1857 "conformance path rules test": { 1858 ingress: pathRules, 1859 want: pathRulesListeners, 1860 }, 1861 "cilium test ingress": { 1862 ingress: complexIngress, 1863 want: complexIngressListeners, 1864 }, 1865 "cilium test ingress without SecretName": { 1866 ingress: removeIngressTLSsecretName(complexIngress), 1867 want: removeListenersTLSsecret(complexIngressListeners), 1868 }, 1869 "cilium test ingress with NodePort": { 1870 ingress: complexNodePortIngress, 1871 want: complexNodePortIngressListeners, 1872 }, 1873 "cilium test ingress with NodePort without SecretName": { 1874 ingress: removeIngressTLSsecretName(complexNodePortIngress), 1875 want: removeListenersTLSsecret(complexNodePortIngressListeners), 1876 }, 1877 "conformance default backend test with default secret": { 1878 ingress: defaultBackend, 1879 defaultSecret: true, 1880 want: defaultBackendListeners, 1881 }, 1882 "conformance default backend (legacy annotation) test with default secret": { 1883 ingress: defaultBackendLegacy, 1884 defaultSecret: true, 1885 want: defaultBackendListeners, 1886 }, 1887 "conformance default backend (legacy + new) test with default secret": { 1888 ingress: defaultBackendLegacyOverride, 1889 defaultSecret: true, 1890 want: defaultBackendListeners, 1891 }, 1892 "conformance host rules test with default secret": { 1893 ingress: hostRules, 1894 defaultSecret: true, 1895 want: hostRulesListeners, 1896 }, 1897 "conformance host rules test with default secret without SecretName": { 1898 ingress: removeIngressTLSsecretName(hostRules), 1899 defaultSecret: true, 1900 want: useDefaultListenersTLSsecret(hostRulesListeners), 1901 }, 1902 "conformance path rules test with default secret": { 1903 ingress: pathRules, 1904 defaultSecret: true, 1905 want: pathRulesListeners, 1906 }, 1907 "cilium test ingress with default secret": { 1908 ingress: complexIngress, 1909 defaultSecret: true, 1910 want: complexIngressListeners, 1911 }, 1912 "cilium test ingress with default secret without SecretName": { 1913 ingress: removeIngressTLSsecretName(complexIngress), 1914 defaultSecret: true, 1915 want: useDefaultListenersTLSsecret(complexIngressListeners), 1916 }, 1917 "cilium test ingress with NodePort with default secret": { 1918 ingress: complexNodePortIngress, 1919 defaultSecret: true, 1920 want: complexNodePortIngressListeners, 1921 }, 1922 "cilium test ingress with NodePort with default secret without SecretName": { 1923 ingress: removeIngressTLSsecretName(complexNodePortIngress), 1924 defaultSecret: true, 1925 want: useDefaultListenersTLSsecret(complexNodePortIngressListeners), 1926 }, 1927 "cilium multiple path types": { 1928 ingress: multiplePathTypes, 1929 want: multiplePathTypesListeners, 1930 }, 1931 "force-https annotation present and enabled": { 1932 ingress: hostRulesForceHTTPSenabled, 1933 want: hostRulesForceHTTPSenabledListeners, 1934 }, 1935 "force-https annotation present and enabled, enforceHTTPS enabled": { 1936 ingress: hostRulesForceHTTPSenabled, 1937 want: hostRulesForceHTTPSenabledListeners, 1938 enforceHTTPS: true, 1939 }, 1940 "force-https annotation present and disabled, enforceHTTPS enabled": { 1941 ingress: hostRulesForceHTTPSdisabled, 1942 want: hostRulesListeners, 1943 enforceHTTPS: true, 1944 }, 1945 "force-https annotation present and disabled, enforceHTTPS disabled": { 1946 ingress: hostRulesForceHTTPSdisabled, 1947 want: hostRulesListeners, 1948 }, 1949 "force-https annotation not present, enforceHTTPS enabled": { 1950 ingress: hostRules, 1951 want: hostRulesForceHTTPSenabledListeners, 1952 enforceHTTPS: true, 1953 }, 1954 "request-timeout flag present with no annotation": { 1955 ingress: defaultBackend, 1956 want: defaultBackendListenersWithRequestTimeout, 1957 requestTimeout: time.Second * 10, 1958 }, 1959 "request-timeout annotation present": { 1960 ingress: requestTimeoutAnnotationIngress, 1961 want: requestTimeoutAnnotationListeners, 1962 }, 1963 "request-timeout annotation present but invalid": { 1964 ingress: requestTimeoutInvalidIngress, 1965 want: requestTimeoutInvalidListeners, 1966 }, 1967 } 1968 1969 for name, tc := range tests { 1970 t.Run(name, func(t *testing.T) { 1971 var listeners []model.HTTPListener 1972 if tc.defaultSecret { 1973 listeners = Ingress(tc.ingress, defaultSecretNamespace, defaultSecretName, tc.enforceHTTPS, 80, 443, tc.requestTimeout) 1974 } else { 1975 listeners = Ingress(tc.ingress, "", "", tc.enforceHTTPS, 80, 443, tc.requestTimeout) 1976 } 1977 1978 assert.Equal(t, tc.want, listeners, "Listeners did not match") 1979 }) 1980 } 1981 } 1982 1983 // SSL Passthrough tests 1984 // 1985 // Sources for the SSL Passthrough Ingress objects 1986 var sslPassthruSources = []model.FullyQualifiedResource{ 1987 { 1988 Name: "sslpassthru-ingress", 1989 Namespace: "dummy-namespace", 1990 Version: "v1", 1991 Kind: "Ingress", 1992 }, 1993 } 1994 1995 var emptyTLSListeners = []model.TLSPassthroughListener{} 1996 1997 // sslPassthru tests basic SSL Passthrough 1998 var sslPassthru = networkingv1.Ingress{ 1999 ObjectMeta: metav1.ObjectMeta{ 2000 Name: "sslpassthru-ingress", 2001 Namespace: "dummy-namespace", 2002 Annotations: map[string]string{ 2003 "ingress.cilium.io/tls-passthrough": "true", 2004 }, 2005 }, 2006 Spec: networkingv1.IngressSpec{ 2007 IngressClassName: stringp("cilium"), 2008 Rules: []networkingv1.IngressRule{ 2009 { 2010 Host: "sslpassthru.example.com", 2011 IngressRuleValue: networkingv1.IngressRuleValue{ 2012 HTTP: &networkingv1.HTTPIngressRuleValue{ 2013 Paths: []networkingv1.HTTPIngressPath{ 2014 { 2015 Path: "/", 2016 Backend: networkingv1.IngressBackend{ 2017 Service: &networkingv1.IngressServiceBackend{ 2018 Name: "dummy-backend", 2019 Port: networkingv1.ServiceBackendPort{ 2020 Number: 8080, 2021 }, 2022 }, 2023 }, 2024 PathType: &exactPathType, 2025 }, 2026 }, 2027 }, 2028 }, 2029 }, 2030 }, 2031 }, 2032 } 2033 2034 var sslPassthruTLSListeners = []model.TLSPassthroughListener{ 2035 { 2036 Name: "ing-sslpassthru-ingress-dummy-namespace-sslpassthru.example.com", 2037 Sources: sslPassthruSources, 2038 Port: 443, 2039 Hostname: "sslpassthru.example.com", 2040 Routes: []model.TLSPassthroughRoute{ 2041 { 2042 Hostnames: []string{ 2043 "sslpassthru.example.com", 2044 }, 2045 Backends: []model.Backend{ 2046 { 2047 Name: "dummy-backend", 2048 Namespace: "dummy-namespace", 2049 Port: &model.BackendPort{ 2050 Port: 8080, 2051 }, 2052 }, 2053 }, 2054 }, 2055 }, 2056 }, 2057 } 2058 2059 // sslPassthruNoHost tests when there's no host set 2060 var sslPassthruNoHost = networkingv1.Ingress{ 2061 ObjectMeta: metav1.ObjectMeta{ 2062 Name: "sslpassthru-ingress", 2063 Namespace: "dummy-namespace", 2064 Annotations: map[string]string{ 2065 "ingress.cilium.io/tls-passthrough": "true", 2066 }, 2067 }, 2068 Spec: networkingv1.IngressSpec{ 2069 IngressClassName: stringp("cilium"), 2070 Rules: []networkingv1.IngressRule{ 2071 { 2072 IngressRuleValue: networkingv1.IngressRuleValue{ 2073 HTTP: &networkingv1.HTTPIngressRuleValue{ 2074 Paths: []networkingv1.HTTPIngressPath{ 2075 { 2076 Path: "/", 2077 Backend: networkingv1.IngressBackend{ 2078 Service: &networkingv1.IngressServiceBackend{ 2079 Name: "dummy-backend", 2080 Port: networkingv1.ServiceBackendPort{ 2081 Number: 8080, 2082 }, 2083 }, 2084 }, 2085 PathType: &exactPathType, 2086 }, 2087 }, 2088 }, 2089 }, 2090 }, 2091 }, 2092 }, 2093 } 2094 2095 // sslPassthruNoRule tests when there's a hostname but no rule at all 2096 var sslPassthruNoRule = networkingv1.Ingress{ 2097 ObjectMeta: metav1.ObjectMeta{ 2098 Name: "sslpassthru-ingress", 2099 Namespace: "dummy-namespace", 2100 Annotations: map[string]string{ 2101 "ingress.cilium.io/tls-passthrough": "true", 2102 }, 2103 }, 2104 Spec: networkingv1.IngressSpec{ 2105 IngressClassName: stringp("cilium"), 2106 Rules: []networkingv1.IngressRule{ 2107 { 2108 Host: "sslpassthru.example.com", 2109 IngressRuleValue: networkingv1.IngressRuleValue{}, 2110 }, 2111 }, 2112 }, 2113 } 2114 2115 // sslPassthruExtraPath tests when a hostname and a rule but the path isn't '/' 2116 var sslPassthruExtraPath = networkingv1.Ingress{ 2117 ObjectMeta: metav1.ObjectMeta{ 2118 Name: "sslpassthru-ingress", 2119 Namespace: "dummy-namespace", 2120 Annotations: map[string]string{ 2121 "ingress.cilium.io/tls-passthrough": "true", 2122 }, 2123 }, 2124 Spec: networkingv1.IngressSpec{ 2125 IngressClassName: stringp("cilium"), 2126 Rules: []networkingv1.IngressRule{ 2127 { 2128 Host: "sslpassthru.example.com", 2129 IngressRuleValue: networkingv1.IngressRuleValue{ 2130 HTTP: &networkingv1.HTTPIngressRuleValue{ 2131 Paths: []networkingv1.HTTPIngressPath{ 2132 { 2133 Path: "/prefix", 2134 Backend: networkingv1.IngressBackend{ 2135 Service: &networkingv1.IngressServiceBackend{ 2136 Name: "dummy-backend", 2137 Port: networkingv1.ServiceBackendPort{ 2138 Number: 8080, 2139 }, 2140 }, 2141 }, 2142 PathType: &exactPathType, 2143 }, 2144 }, 2145 }, 2146 }, 2147 }, 2148 }, 2149 }, 2150 } 2151 2152 // sslPassthruNodePort tests when the Ingress has a NodePort Service set. 2153 var sslPassthruNodePort = networkingv1.Ingress{ 2154 ObjectMeta: metav1.ObjectMeta{ 2155 Name: "sslpassthru-ingress", 2156 Namespace: "dummy-namespace", 2157 Annotations: map[string]string{ 2158 "ingress.cilium.io/service-type": "NodePort", 2159 "ingress.cilium.io/insecure-node-port": "30000", 2160 "ingress.cilium.io/secure-node-port": "30001", 2161 "ingress.cilium.io/tls-passthrough": "true", 2162 }, 2163 }, 2164 Spec: networkingv1.IngressSpec{ 2165 IngressClassName: stringp("cilium"), 2166 Rules: []networkingv1.IngressRule{ 2167 { 2168 Host: "sslpassthru.example.com", 2169 IngressRuleValue: networkingv1.IngressRuleValue{ 2170 HTTP: &networkingv1.HTTPIngressRuleValue{ 2171 Paths: []networkingv1.HTTPIngressPath{ 2172 { 2173 Path: "/", 2174 Backend: networkingv1.IngressBackend{ 2175 Service: &networkingv1.IngressServiceBackend{ 2176 Name: "dummy-backend", 2177 Port: networkingv1.ServiceBackendPort{ 2178 Number: 8080, 2179 }, 2180 }, 2181 }, 2182 PathType: &exactPathType, 2183 }, 2184 }, 2185 }, 2186 }, 2187 }, 2188 }, 2189 }, 2190 } 2191 2192 var sslPassthruTLSListenersNodePort = []model.TLSPassthroughListener{ 2193 { 2194 Name: "ing-sslpassthru-ingress-dummy-namespace-sslpassthru.example.com", 2195 Sources: sslPassthruSources, 2196 Port: 443, 2197 Hostname: "sslpassthru.example.com", 2198 Routes: []model.TLSPassthroughRoute{ 2199 { 2200 Hostnames: []string{ 2201 "sslpassthru.example.com", 2202 }, 2203 Backends: []model.Backend{ 2204 { 2205 Name: "dummy-backend", 2206 Namespace: "dummy-namespace", 2207 Port: &model.BackendPort{ 2208 Port: 8080, 2209 }, 2210 }, 2211 }, 2212 }, 2213 }, 2214 Service: &model.Service{ 2215 Type: "NodePort", 2216 InsecureNodePort: uint32p(30000), 2217 SecureNodePort: uint32p(30001), 2218 }, 2219 }, 2220 } 2221 2222 // sslPassthruMultiplePaths tests when there are multiple paths, with one being '/' 2223 var sslPassthruMultiplePaths = networkingv1.Ingress{ 2224 ObjectMeta: metav1.ObjectMeta{ 2225 Name: "sslpassthru-ingress", 2226 Namespace: "dummy-namespace", 2227 Annotations: map[string]string{ 2228 "ingress.cilium.io/tls-passthrough": "true", 2229 }, 2230 }, 2231 Spec: networkingv1.IngressSpec{ 2232 IngressClassName: stringp("cilium"), 2233 Rules: []networkingv1.IngressRule{ 2234 { 2235 Host: "sslpassthru.example.com", 2236 IngressRuleValue: networkingv1.IngressRuleValue{ 2237 HTTP: &networkingv1.HTTPIngressRuleValue{ 2238 Paths: []networkingv1.HTTPIngressPath{ 2239 { 2240 Path: "/prefix", 2241 Backend: networkingv1.IngressBackend{ 2242 Service: &networkingv1.IngressServiceBackend{ 2243 Name: "dummy-backend", 2244 Port: networkingv1.ServiceBackendPort{ 2245 Number: 8080, 2246 }, 2247 }, 2248 }, 2249 PathType: &exactPathType, 2250 }, 2251 { 2252 Path: "/", 2253 Backend: networkingv1.IngressBackend{ 2254 Service: &networkingv1.IngressServiceBackend{ 2255 Name: "dummy-backend", 2256 Port: networkingv1.ServiceBackendPort{ 2257 Number: 8080, 2258 }, 2259 }, 2260 }, 2261 PathType: &exactPathType, 2262 }, 2263 }, 2264 }, 2265 }, 2266 }, 2267 }, 2268 }, 2269 } 2270 2271 var sslPassthruMultiplePathsTLSListeners = []model.TLSPassthroughListener{ 2272 { 2273 Name: "ing-sslpassthru-ingress-dummy-namespace-sslpassthru.example.com", 2274 Sources: sslPassthruSources, 2275 Port: 443, 2276 Hostname: "sslpassthru.example.com", 2277 Routes: []model.TLSPassthroughRoute{ 2278 { 2279 Hostnames: []string{ 2280 "sslpassthru.example.com", 2281 }, 2282 Backends: []model.Backend{ 2283 { 2284 Name: "dummy-backend", 2285 Namespace: "dummy-namespace", 2286 Port: &model.BackendPort{ 2287 Port: 8080, 2288 }, 2289 }, 2290 }, 2291 }, 2292 }, 2293 }, 2294 } 2295 2296 // sslPassthruDefaultBackend tests when there's a default backend supplied 2297 var sslPassthruDefaultBackend = networkingv1.Ingress{ 2298 ObjectMeta: metav1.ObjectMeta{ 2299 Name: "sslpassthru-ingress", 2300 Namespace: "dummy-namespace", 2301 Annotations: map[string]string{ 2302 "ingress.cilium.io/tls-passthrough": "true", 2303 }, 2304 }, 2305 Spec: networkingv1.IngressSpec{ 2306 IngressClassName: stringp("cilium"), 2307 DefaultBackend: &networkingv1.IngressBackend{ 2308 Service: &networkingv1.IngressServiceBackend{ 2309 Name: "default-backend", 2310 Port: networkingv1.ServiceBackendPort{ 2311 Number: 8080, 2312 }, 2313 }, 2314 }, 2315 Rules: []networkingv1.IngressRule{}, 2316 }, 2317 } 2318 2319 type passthruTestcase struct { 2320 ingress networkingv1.Ingress 2321 want []model.TLSPassthroughListener 2322 } 2323 2324 func TestIngressPassthrough(t *testing.T) { 2325 tests := map[string]passthruTestcase{ 2326 "Cilium test ingress with SSL Passthrough": { 2327 ingress: sslPassthru, 2328 want: sslPassthruTLSListeners, 2329 }, 2330 "Cilium test ingress with SSL Passthrough, no host set": { 2331 ingress: sslPassthruNoHost, 2332 want: emptyTLSListeners, 2333 }, 2334 "Cilium test ingress with SSL Passthrough, host but no rule": { 2335 ingress: sslPassthruNoRule, 2336 want: emptyTLSListeners, 2337 }, 2338 "Cilium test ingress with SSL Passthrough, prefix path rule": { 2339 ingress: sslPassthruExtraPath, 2340 want: emptyTLSListeners, 2341 }, 2342 "Cilium test ingress with SSL Passthrough and default backend": { 2343 ingress: sslPassthruDefaultBackend, 2344 want: emptyTLSListeners, 2345 }, 2346 "Cilium test ingress with SSL Passthrough, multiple path rules, one valid": { 2347 ingress: sslPassthruMultiplePaths, 2348 want: sslPassthruMultiplePathsTLSListeners, 2349 }, 2350 "Cilium test ingress with SSL Passthrough, Nodeport Service annotations": { 2351 ingress: sslPassthruNodePort, 2352 want: sslPassthruTLSListenersNodePort, 2353 }, 2354 } 2355 2356 for name, tc := range tests { 2357 t.Run(name, func(t *testing.T) { 2358 listeners := IngressPassthrough(tc.ingress, 443) 2359 2360 assert.Equal(t, tc.want, listeners, "Listeners did not match") 2361 }) 2362 } 2363 }