sigs.k8s.io/external-dns@v0.14.1/source/traefik_proxy_test.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package source 18 19 import ( 20 "context" 21 "encoding/json" 22 "k8s.io/apimachinery/pkg/runtime/schema" 23 "testing" 24 25 "github.com/stretchr/testify/assert" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 28 "k8s.io/apimachinery/pkg/runtime" 29 fakeDynamic "k8s.io/client-go/dynamic/fake" 30 fakeKube "k8s.io/client-go/kubernetes/fake" 31 "sigs.k8s.io/external-dns/endpoint" 32 ) 33 34 // This is a compile-time validation that traefikSource is a Source. 35 var _ Source = &traefikSource{} 36 37 const defaultTraefikNamespace = "traefik" 38 39 func TestTraefikProxyIngressRouteEndpoints(t *testing.T) { 40 t.Parallel() 41 42 for _, ti := range []struct { 43 title string 44 ingressRoute IngressRoute 45 ignoreHostnameAnnotation bool 46 expected []*endpoint.Endpoint 47 }{ 48 { 49 title: "IngressRoute with hostname annotation", 50 ingressRoute: IngressRoute{ 51 TypeMeta: metav1.TypeMeta{ 52 APIVersion: ingressrouteGVR.GroupVersion().String(), 53 Kind: "IngressRoute", 54 }, 55 ObjectMeta: metav1.ObjectMeta{ 56 Name: "ingressroute-annotation", 57 Namespace: defaultTraefikNamespace, 58 Annotations: map[string]string{ 59 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 60 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 61 "kubernetes.io/ingress.class": "traefik", 62 }, 63 }, 64 }, 65 expected: []*endpoint.Endpoint{ 66 { 67 DNSName: "a.example.com", 68 Targets: []string{"target.domain.tld"}, 69 RecordType: endpoint.RecordTypeCNAME, 70 RecordTTL: 0, 71 Labels: endpoint.Labels{ 72 "resource": "ingressroute/traefik/ingressroute-annotation", 73 }, 74 ProviderSpecific: endpoint.ProviderSpecific{}, 75 }, 76 }, 77 }, 78 { 79 title: "IngressRoute with host rule", 80 ingressRoute: IngressRoute{ 81 TypeMeta: metav1.TypeMeta{ 82 APIVersion: ingressrouteGVR.GroupVersion().String(), 83 Kind: "IngressRoute", 84 }, 85 ObjectMeta: metav1.ObjectMeta{ 86 Name: "ingressroute-host-match", 87 Namespace: defaultTraefikNamespace, 88 Annotations: map[string]string{ 89 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 90 "kubernetes.io/ingress.class": "traefik", 91 }, 92 }, 93 Spec: traefikIngressRouteSpec{ 94 Routes: []traefikRoute{ 95 { 96 Match: "Host(`b.example.com`)", 97 }, 98 }, 99 }, 100 }, 101 expected: []*endpoint.Endpoint{ 102 { 103 DNSName: "b.example.com", 104 Targets: []string{"target.domain.tld"}, 105 RecordType: endpoint.RecordTypeCNAME, 106 RecordTTL: 0, 107 Labels: endpoint.Labels{ 108 "resource": "ingressroute/traefik/ingressroute-host-match", 109 }, 110 ProviderSpecific: endpoint.ProviderSpecific{}, 111 }, 112 }, 113 }, 114 { 115 title: "IngressRoute with hostheader rule", 116 ingressRoute: IngressRoute{ 117 TypeMeta: metav1.TypeMeta{ 118 APIVersion: ingressrouteGVR.GroupVersion().String(), 119 Kind: "IngressRoute", 120 }, 121 ObjectMeta: metav1.ObjectMeta{ 122 Name: "ingressroute-hostheader-match", 123 Namespace: defaultTraefikNamespace, 124 Annotations: map[string]string{ 125 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 126 "kubernetes.io/ingress.class": "traefik", 127 }, 128 }, 129 Spec: traefikIngressRouteSpec{ 130 Routes: []traefikRoute{ 131 { 132 Match: "HostHeader(`c.example.com`)", 133 }, 134 }, 135 }, 136 }, 137 expected: []*endpoint.Endpoint{ 138 { 139 DNSName: "c.example.com", 140 Targets: []string{"target.domain.tld"}, 141 RecordType: endpoint.RecordTypeCNAME, 142 RecordTTL: 0, 143 Labels: endpoint.Labels{ 144 "resource": "ingressroute/traefik/ingressroute-hostheader-match", 145 }, 146 ProviderSpecific: endpoint.ProviderSpecific{}, 147 }, 148 }, 149 }, 150 { 151 title: "IngressRoute with multiple host rules", 152 ingressRoute: IngressRoute{ 153 TypeMeta: metav1.TypeMeta{ 154 APIVersion: ingressrouteGVR.GroupVersion().String(), 155 Kind: "IngressRoute", 156 }, 157 ObjectMeta: metav1.ObjectMeta{ 158 Name: "ingressroute-multi-host-match", 159 Namespace: defaultTraefikNamespace, 160 Annotations: map[string]string{ 161 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 162 "kubernetes.io/ingress.class": "traefik", 163 }, 164 }, 165 Spec: traefikIngressRouteSpec{ 166 Routes: []traefikRoute{ 167 { 168 Match: "Host(`d.example.com`) || Host(`e.example.com`)", 169 }, 170 }, 171 }, 172 }, 173 expected: []*endpoint.Endpoint{ 174 { 175 DNSName: "d.example.com", 176 Targets: []string{"target.domain.tld"}, 177 RecordType: endpoint.RecordTypeCNAME, 178 RecordTTL: 0, 179 Labels: endpoint.Labels{ 180 "resource": "ingressroute/traefik/ingressroute-multi-host-match", 181 }, 182 ProviderSpecific: endpoint.ProviderSpecific{}, 183 }, 184 { 185 DNSName: "e.example.com", 186 Targets: []string{"target.domain.tld"}, 187 RecordType: endpoint.RecordTypeCNAME, 188 RecordTTL: 0, 189 Labels: endpoint.Labels{ 190 "resource": "ingressroute/traefik/ingressroute-multi-host-match", 191 }, 192 ProviderSpecific: endpoint.ProviderSpecific{}, 193 }, 194 }, 195 }, 196 { 197 title: "IngressRoute with multiple host rules and annotation", 198 ingressRoute: IngressRoute{ 199 TypeMeta: metav1.TypeMeta{ 200 APIVersion: ingressrouteGVR.GroupVersion().String(), 201 Kind: "IngressRoute", 202 }, 203 ObjectMeta: metav1.ObjectMeta{ 204 Name: "ingressroute-multi-host-annotations-match", 205 Namespace: defaultTraefikNamespace, 206 Annotations: map[string]string{ 207 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 208 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 209 "kubernetes.io/ingress.class": "traefik", 210 }, 211 }, 212 Spec: traefikIngressRouteSpec{ 213 Routes: []traefikRoute{ 214 { 215 Match: "Host(`g.example.com`, `h.example.com`)", 216 }, 217 }, 218 }, 219 }, 220 expected: []*endpoint.Endpoint{ 221 { 222 DNSName: "f.example.com", 223 Targets: []string{"target.domain.tld"}, 224 RecordType: endpoint.RecordTypeCNAME, 225 RecordTTL: 0, 226 Labels: endpoint.Labels{ 227 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 228 }, 229 ProviderSpecific: endpoint.ProviderSpecific{}, 230 }, 231 { 232 DNSName: "g.example.com", 233 Targets: []string{"target.domain.tld"}, 234 RecordType: endpoint.RecordTypeCNAME, 235 RecordTTL: 0, 236 Labels: endpoint.Labels{ 237 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 238 }, 239 ProviderSpecific: endpoint.ProviderSpecific{}, 240 }, 241 { 242 DNSName: "h.example.com", 243 Targets: []string{"target.domain.tld"}, 244 RecordType: endpoint.RecordTypeCNAME, 245 RecordTTL: 0, 246 Labels: endpoint.Labels{ 247 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 248 }, 249 ProviderSpecific: endpoint.ProviderSpecific{}, 250 }, 251 }, 252 }, 253 { 254 title: "IngressRoute ignoring annotation", 255 ingressRoute: IngressRoute{ 256 TypeMeta: metav1.TypeMeta{ 257 APIVersion: ingressrouteGVR.GroupVersion().String(), 258 Kind: "IngressRoute", 259 }, 260 ObjectMeta: metav1.ObjectMeta{ 261 Name: "ingressroute-multi-host-annotations-match", 262 Namespace: defaultTraefikNamespace, 263 Annotations: map[string]string{ 264 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 265 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 266 "kubernetes.io/ingress.class": "traefik", 267 }, 268 }, 269 Spec: traefikIngressRouteSpec{ 270 Routes: []traefikRoute{ 271 { 272 Match: "Host(`g.example.com`, `h.example.com`)", 273 }, 274 }, 275 }, 276 }, 277 ignoreHostnameAnnotation: true, 278 expected: []*endpoint.Endpoint{ 279 { 280 DNSName: "g.example.com", 281 Targets: []string{"target.domain.tld"}, 282 RecordType: endpoint.RecordTypeCNAME, 283 RecordTTL: 0, 284 Labels: endpoint.Labels{ 285 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 286 }, 287 ProviderSpecific: endpoint.ProviderSpecific{}, 288 }, 289 { 290 DNSName: "h.example.com", 291 Targets: []string{"target.domain.tld"}, 292 RecordType: endpoint.RecordTypeCNAME, 293 RecordTTL: 0, 294 Labels: endpoint.Labels{ 295 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 296 }, 297 ProviderSpecific: endpoint.ProviderSpecific{}, 298 }, 299 }, 300 }, 301 { 302 title: "IngressRoute omit wildcard", 303 ingressRoute: IngressRoute{ 304 TypeMeta: metav1.TypeMeta{ 305 APIVersion: ingressrouteGVR.GroupVersion().String(), 306 Kind: "IngressRoute", 307 }, 308 ObjectMeta: metav1.ObjectMeta{ 309 Name: "ingressroute-omit-wildcard-host", 310 Namespace: defaultTraefikNamespace, 311 Annotations: map[string]string{ 312 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 313 "kubernetes.io/ingress.class": "traefik", 314 }, 315 }, 316 Spec: traefikIngressRouteSpec{ 317 Routes: []traefikRoute{ 318 { 319 Match: "Host(`*`)", 320 }, 321 }, 322 }, 323 }, 324 expected: nil, 325 }, 326 } { 327 ti := ti 328 t.Run(ti.title, func(t *testing.T) { 329 t.Parallel() 330 331 fakeKubernetesClient := fakeKube.NewSimpleClientset() 332 scheme := runtime.NewScheme() 333 scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 334 scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 335 scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 336 scheme.AddKnownTypes(oldIngressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 337 scheme.AddKnownTypes(oldIngressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 338 scheme.AddKnownTypes(oldIngressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 339 fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) 340 341 ir := unstructured.Unstructured{} 342 343 ingressRouteAsJSON, err := json.Marshal(ti.ingressRoute) 344 assert.NoError(t, err) 345 346 assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON)) 347 348 // Create proxy resources 349 _, err = fakeDynamicClient.Resource(ingressrouteGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{}) 350 assert.NoError(t, err) 351 352 source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false) 353 assert.NoError(t, err) 354 assert.NotNil(t, source) 355 356 count := &unstructured.UnstructuredList{} 357 for len(count.Items) < 1 { 358 count, _ = fakeDynamicClient.Resource(ingressrouteGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{}) 359 } 360 361 endpoints, err := source.Endpoints(context.Background()) 362 assert.NoError(t, err) 363 assert.Len(t, endpoints, len(ti.expected)) 364 assert.Equal(t, ti.expected, endpoints) 365 }) 366 } 367 } 368 369 func TestTraefikProxyIngressRouteTCPEndpoints(t *testing.T) { 370 t.Parallel() 371 372 for _, ti := range []struct { 373 title string 374 ingressRouteTCP IngressRouteTCP 375 ignoreHostnameAnnotation bool 376 expected []*endpoint.Endpoint 377 }{ 378 { 379 title: "IngressRouteTCP with hostname annotation", 380 ingressRouteTCP: IngressRouteTCP{ 381 TypeMeta: metav1.TypeMeta{ 382 APIVersion: ingressrouteTCPGVR.GroupVersion().String(), 383 Kind: "IngressRouteTCP", 384 }, 385 ObjectMeta: metav1.ObjectMeta{ 386 Name: "ingressroutetcp-annotation", 387 Namespace: defaultTraefikNamespace, 388 Annotations: map[string]string{ 389 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 390 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 391 "kubernetes.io/ingress.class": "traefik", 392 }, 393 }, 394 }, 395 expected: []*endpoint.Endpoint{ 396 { 397 DNSName: "a.example.com", 398 Targets: []string{"target.domain.tld"}, 399 RecordType: endpoint.RecordTypeCNAME, 400 RecordTTL: 0, 401 Labels: endpoint.Labels{ 402 "resource": "ingressroutetcp/traefik/ingressroutetcp-annotation", 403 }, 404 ProviderSpecific: endpoint.ProviderSpecific{}, 405 }, 406 }, 407 }, 408 { 409 title: "IngressRouteTCP with host sni rule", 410 ingressRouteTCP: IngressRouteTCP{ 411 TypeMeta: metav1.TypeMeta{ 412 APIVersion: ingressrouteTCPGVR.GroupVersion().String(), 413 Kind: "IngressRouteTCP", 414 }, 415 ObjectMeta: metav1.ObjectMeta{ 416 Name: "ingressroutetcp-hostsni-match", 417 Namespace: defaultTraefikNamespace, 418 Annotations: map[string]string{ 419 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 420 "kubernetes.io/ingress.class": "traefik", 421 }, 422 }, 423 Spec: traefikIngressRouteTCPSpec{ 424 Routes: []traefikRouteTCP{ 425 { 426 Match: "HostSNI(`b.example.com`)", 427 }, 428 }, 429 }, 430 }, 431 expected: []*endpoint.Endpoint{ 432 { 433 DNSName: "b.example.com", 434 Targets: []string{"target.domain.tld"}, 435 RecordType: endpoint.RecordTypeCNAME, 436 RecordTTL: 0, 437 Labels: endpoint.Labels{ 438 "resource": "ingressroutetcp/traefik/ingressroutetcp-hostsni-match", 439 }, 440 ProviderSpecific: endpoint.ProviderSpecific{}, 441 }, 442 }, 443 }, 444 { 445 title: "IngressRouteTCP with multiple host sni rules", 446 ingressRouteTCP: IngressRouteTCP{ 447 TypeMeta: metav1.TypeMeta{ 448 APIVersion: ingressrouteTCPGVR.GroupVersion().String(), 449 Kind: "IngressRouteTCP", 450 }, 451 ObjectMeta: metav1.ObjectMeta{ 452 Name: "ingressroutetcp-multi-host-match", 453 Namespace: defaultTraefikNamespace, 454 Annotations: map[string]string{ 455 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 456 "kubernetes.io/ingress.class": "traefik", 457 }, 458 }, 459 Spec: traefikIngressRouteTCPSpec{ 460 Routes: []traefikRouteTCP{ 461 { 462 Match: "HostSNI(`d.example.com`) || HostSNI(`e.example.com`)", 463 }, 464 }, 465 }, 466 }, 467 expected: []*endpoint.Endpoint{ 468 { 469 DNSName: "d.example.com", 470 Targets: []string{"target.domain.tld"}, 471 RecordType: endpoint.RecordTypeCNAME, 472 RecordTTL: 0, 473 Labels: endpoint.Labels{ 474 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-match", 475 }, 476 ProviderSpecific: endpoint.ProviderSpecific{}, 477 }, 478 { 479 DNSName: "e.example.com", 480 Targets: []string{"target.domain.tld"}, 481 RecordType: endpoint.RecordTypeCNAME, 482 RecordTTL: 0, 483 Labels: endpoint.Labels{ 484 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-match", 485 }, 486 ProviderSpecific: endpoint.ProviderSpecific{}, 487 }, 488 }, 489 }, 490 { 491 title: "IngressRouteTCP with multiple host sni rules and annotation", 492 ingressRouteTCP: IngressRouteTCP{ 493 TypeMeta: metav1.TypeMeta{ 494 APIVersion: ingressrouteTCPGVR.GroupVersion().String(), 495 Kind: "IngressRouteTCP", 496 }, 497 ObjectMeta: metav1.ObjectMeta{ 498 Name: "ingressroutetcp-multi-host-annotations-match", 499 Namespace: defaultTraefikNamespace, 500 Annotations: map[string]string{ 501 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 502 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 503 "kubernetes.io/ingress.class": "traefik", 504 }, 505 }, 506 Spec: traefikIngressRouteTCPSpec{ 507 Routes: []traefikRouteTCP{ 508 { 509 Match: "HostSNI(`g.example.com`, `h.example.com`)", 510 }, 511 }, 512 }, 513 }, 514 expected: []*endpoint.Endpoint{ 515 { 516 DNSName: "f.example.com", 517 Targets: []string{"target.domain.tld"}, 518 RecordType: endpoint.RecordTypeCNAME, 519 RecordTTL: 0, 520 Labels: endpoint.Labels{ 521 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 522 }, 523 ProviderSpecific: endpoint.ProviderSpecific{}, 524 }, 525 { 526 DNSName: "g.example.com", 527 Targets: []string{"target.domain.tld"}, 528 RecordType: endpoint.RecordTypeCNAME, 529 RecordTTL: 0, 530 Labels: endpoint.Labels{ 531 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 532 }, 533 ProviderSpecific: endpoint.ProviderSpecific{}, 534 }, 535 { 536 DNSName: "h.example.com", 537 Targets: []string{"target.domain.tld"}, 538 RecordType: endpoint.RecordTypeCNAME, 539 RecordTTL: 0, 540 Labels: endpoint.Labels{ 541 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 542 }, 543 ProviderSpecific: endpoint.ProviderSpecific{}, 544 }, 545 }, 546 }, 547 { 548 title: "IngressRouteTCP ignoring annotation", 549 ingressRouteTCP: IngressRouteTCP{ 550 TypeMeta: metav1.TypeMeta{ 551 APIVersion: ingressrouteTCPGVR.GroupVersion().String(), 552 Kind: "IngressRouteTCP", 553 }, 554 ObjectMeta: metav1.ObjectMeta{ 555 Name: "ingressroutetcp-multi-host-annotations-match", 556 Namespace: defaultTraefikNamespace, 557 Annotations: map[string]string{ 558 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 559 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 560 "kubernetes.io/ingress.class": "traefik", 561 }, 562 }, 563 Spec: traefikIngressRouteTCPSpec{ 564 Routes: []traefikRouteTCP{ 565 { 566 Match: "HostSNI(`g.example.com`, `h.example.com`)", 567 }, 568 }, 569 }, 570 }, 571 ignoreHostnameAnnotation: true, 572 expected: []*endpoint.Endpoint{ 573 { 574 DNSName: "g.example.com", 575 Targets: []string{"target.domain.tld"}, 576 RecordType: endpoint.RecordTypeCNAME, 577 RecordTTL: 0, 578 Labels: endpoint.Labels{ 579 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 580 }, 581 ProviderSpecific: endpoint.ProviderSpecific{}, 582 }, 583 { 584 DNSName: "h.example.com", 585 Targets: []string{"target.domain.tld"}, 586 RecordType: endpoint.RecordTypeCNAME, 587 RecordTTL: 0, 588 Labels: endpoint.Labels{ 589 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 590 }, 591 ProviderSpecific: endpoint.ProviderSpecific{}, 592 }, 593 }, 594 }, 595 { 596 title: "IngressRouteTCP omit wildcard host sni", 597 ingressRouteTCP: IngressRouteTCP{ 598 TypeMeta: metav1.TypeMeta{ 599 APIVersion: ingressrouteTCPGVR.GroupVersion().String(), 600 Kind: "IngressRouteTCP", 601 }, 602 ObjectMeta: metav1.ObjectMeta{ 603 Name: "ingressroutetcp-omit-wildcard-host", 604 Namespace: defaultTraefikNamespace, 605 Annotations: map[string]string{ 606 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 607 "kubernetes.io/ingress.class": "traefik", 608 }, 609 }, 610 Spec: traefikIngressRouteTCPSpec{ 611 Routes: []traefikRouteTCP{ 612 { 613 Match: "HostSNI(`*`)", 614 }, 615 }, 616 }, 617 }, 618 expected: nil, 619 }, 620 } { 621 ti := ti 622 t.Run(ti.title, func(t *testing.T) { 623 t.Parallel() 624 625 fakeKubernetesClient := fakeKube.NewSimpleClientset() 626 scheme := runtime.NewScheme() 627 scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 628 scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 629 scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 630 scheme.AddKnownTypes(oldIngressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 631 scheme.AddKnownTypes(oldIngressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 632 scheme.AddKnownTypes(oldIngressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 633 fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) 634 635 ir := unstructured.Unstructured{} 636 637 ingressRouteAsJSON, err := json.Marshal(ti.ingressRouteTCP) 638 assert.NoError(t, err) 639 640 assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON)) 641 642 // Create proxy resources 643 _, err = fakeDynamicClient.Resource(ingressrouteTCPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{}) 644 assert.NoError(t, err) 645 646 source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false) 647 assert.NoError(t, err) 648 assert.NotNil(t, source) 649 650 count := &unstructured.UnstructuredList{} 651 for len(count.Items) < 1 { 652 count, _ = fakeDynamicClient.Resource(ingressrouteTCPGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{}) 653 } 654 655 endpoints, err := source.Endpoints(context.Background()) 656 assert.NoError(t, err) 657 assert.Len(t, endpoints, len(ti.expected)) 658 assert.Equal(t, ti.expected, endpoints) 659 }) 660 } 661 } 662 663 func TestTraefikProxyIngressRouteUDPEndpoints(t *testing.T) { 664 t.Parallel() 665 666 for _, ti := range []struct { 667 title string 668 ingressRouteUDP IngressRouteUDP 669 ignoreHostnameAnnotation bool 670 expected []*endpoint.Endpoint 671 }{ 672 { 673 title: "IngressRouteTCP with hostname annotation", 674 ingressRouteUDP: IngressRouteUDP{ 675 TypeMeta: metav1.TypeMeta{ 676 APIVersion: ingressrouteUDPGVR.GroupVersion().String(), 677 Kind: "IngressRouteUDP", 678 }, 679 ObjectMeta: metav1.ObjectMeta{ 680 Name: "ingressrouteudp-annotation", 681 Namespace: defaultTraefikNamespace, 682 Annotations: map[string]string{ 683 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 684 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 685 "kubernetes.io/ingress.class": "traefik", 686 }, 687 }, 688 }, 689 expected: []*endpoint.Endpoint{ 690 { 691 DNSName: "a.example.com", 692 Targets: []string{"target.domain.tld"}, 693 RecordType: endpoint.RecordTypeCNAME, 694 RecordTTL: 0, 695 Labels: endpoint.Labels{ 696 "resource": "ingressrouteudp/traefik/ingressrouteudp-annotation", 697 }, 698 ProviderSpecific: endpoint.ProviderSpecific{}, 699 }, 700 }, 701 }, 702 { 703 title: "IngressRouteTCP with multiple hostname annotation", 704 ingressRouteUDP: IngressRouteUDP{ 705 TypeMeta: metav1.TypeMeta{ 706 APIVersion: ingressrouteUDPGVR.GroupVersion().String(), 707 Kind: "IngressRouteUDP", 708 }, 709 ObjectMeta: metav1.ObjectMeta{ 710 Name: "ingressrouteudp-multi-annotation", 711 Namespace: defaultTraefikNamespace, 712 Annotations: map[string]string{ 713 "external-dns.alpha.kubernetes.io/hostname": "a.example.com, b.example.com", 714 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 715 "kubernetes.io/ingress.class": "traefik", 716 }, 717 }, 718 }, 719 expected: []*endpoint.Endpoint{ 720 { 721 DNSName: "a.example.com", 722 Targets: []string{"target.domain.tld"}, 723 RecordType: endpoint.RecordTypeCNAME, 724 RecordTTL: 0, 725 Labels: endpoint.Labels{ 726 "resource": "ingressrouteudp/traefik/ingressrouteudp-multi-annotation", 727 }, 728 ProviderSpecific: endpoint.ProviderSpecific{}, 729 }, 730 { 731 DNSName: "b.example.com", 732 Targets: []string{"target.domain.tld"}, 733 RecordType: endpoint.RecordTypeCNAME, 734 RecordTTL: 0, 735 Labels: endpoint.Labels{ 736 "resource": "ingressrouteudp/traefik/ingressrouteudp-multi-annotation", 737 }, 738 ProviderSpecific: endpoint.ProviderSpecific{}, 739 }, 740 }, 741 }, 742 { 743 title: "IngressRouteTCP ignoring hostname annotation", 744 ingressRouteUDP: IngressRouteUDP{ 745 TypeMeta: metav1.TypeMeta{ 746 APIVersion: ingressrouteUDPGVR.GroupVersion().String(), 747 Kind: "IngressRouteUDP", 748 }, 749 ObjectMeta: metav1.ObjectMeta{ 750 Name: "ingressrouteudp-annotation", 751 Namespace: defaultTraefikNamespace, 752 Annotations: map[string]string{ 753 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 754 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 755 "kubernetes.io/ingress.class": "traefik", 756 }, 757 }, 758 }, 759 ignoreHostnameAnnotation: true, 760 expected: nil, 761 }, 762 } { 763 ti := ti 764 t.Run(ti.title, func(t *testing.T) { 765 t.Parallel() 766 767 fakeKubernetesClient := fakeKube.NewSimpleClientset() 768 scheme := runtime.NewScheme() 769 scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 770 scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 771 scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 772 scheme.AddKnownTypes(oldIngressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 773 scheme.AddKnownTypes(oldIngressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 774 scheme.AddKnownTypes(oldIngressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 775 fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) 776 777 ir := unstructured.Unstructured{} 778 779 ingressRouteAsJSON, err := json.Marshal(ti.ingressRouteUDP) 780 assert.NoError(t, err) 781 782 assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON)) 783 784 // Create proxy resources 785 _, err = fakeDynamicClient.Resource(ingressrouteUDPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{}) 786 assert.NoError(t, err) 787 788 source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false) 789 assert.NoError(t, err) 790 assert.NotNil(t, source) 791 792 count := &unstructured.UnstructuredList{} 793 for len(count.Items) < 1 { 794 count, _ = fakeDynamicClient.Resource(ingressrouteUDPGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{}) 795 } 796 797 endpoints, err := source.Endpoints(context.Background()) 798 assert.NoError(t, err) 799 assert.Len(t, endpoints, len(ti.expected)) 800 assert.Equal(t, ti.expected, endpoints) 801 }) 802 } 803 } 804 805 func TestTraefikProxyOldIngressRouteEndpoints(t *testing.T) { 806 t.Parallel() 807 808 for _, ti := range []struct { 809 title string 810 ingressRoute IngressRoute 811 ignoreHostnameAnnotation bool 812 expected []*endpoint.Endpoint 813 }{ 814 { 815 title: "IngressRoute with hostname annotation", 816 ingressRoute: IngressRoute{ 817 TypeMeta: metav1.TypeMeta{ 818 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 819 Kind: "IngressRoute", 820 }, 821 ObjectMeta: metav1.ObjectMeta{ 822 Name: "ingressroute-annotation", 823 Namespace: defaultTraefikNamespace, 824 Annotations: map[string]string{ 825 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 826 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 827 "kubernetes.io/ingress.class": "traefik", 828 }, 829 }, 830 }, 831 expected: []*endpoint.Endpoint{ 832 { 833 DNSName: "a.example.com", 834 Targets: []string{"target.domain.tld"}, 835 RecordType: endpoint.RecordTypeCNAME, 836 RecordTTL: 0, 837 Labels: endpoint.Labels{ 838 "resource": "ingressroute/traefik/ingressroute-annotation", 839 }, 840 ProviderSpecific: endpoint.ProviderSpecific{}, 841 }, 842 }, 843 }, 844 { 845 title: "IngressRoute with host rule", 846 ingressRoute: IngressRoute{ 847 TypeMeta: metav1.TypeMeta{ 848 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 849 Kind: "IngressRoute", 850 }, 851 ObjectMeta: metav1.ObjectMeta{ 852 Name: "ingressroute-host-match", 853 Namespace: defaultTraefikNamespace, 854 Annotations: map[string]string{ 855 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 856 "kubernetes.io/ingress.class": "traefik", 857 }, 858 }, 859 Spec: traefikIngressRouteSpec{ 860 Routes: []traefikRoute{ 861 { 862 Match: "Host(`b.example.com`)", 863 }, 864 }, 865 }, 866 }, 867 expected: []*endpoint.Endpoint{ 868 { 869 DNSName: "b.example.com", 870 Targets: []string{"target.domain.tld"}, 871 RecordType: endpoint.RecordTypeCNAME, 872 RecordTTL: 0, 873 Labels: endpoint.Labels{ 874 "resource": "ingressroute/traefik/ingressroute-host-match", 875 }, 876 ProviderSpecific: endpoint.ProviderSpecific{}, 877 }, 878 }, 879 }, 880 { 881 title: "IngressRoute with hostheader rule", 882 ingressRoute: IngressRoute{ 883 TypeMeta: metav1.TypeMeta{ 884 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 885 Kind: "IngressRoute", 886 }, 887 ObjectMeta: metav1.ObjectMeta{ 888 Name: "ingressroute-hostheader-match", 889 Namespace: defaultTraefikNamespace, 890 Annotations: map[string]string{ 891 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 892 "kubernetes.io/ingress.class": "traefik", 893 }, 894 }, 895 Spec: traefikIngressRouteSpec{ 896 Routes: []traefikRoute{ 897 { 898 Match: "HostHeader(`c.example.com`)", 899 }, 900 }, 901 }, 902 }, 903 expected: []*endpoint.Endpoint{ 904 { 905 DNSName: "c.example.com", 906 Targets: []string{"target.domain.tld"}, 907 RecordType: endpoint.RecordTypeCNAME, 908 RecordTTL: 0, 909 Labels: endpoint.Labels{ 910 "resource": "ingressroute/traefik/ingressroute-hostheader-match", 911 }, 912 ProviderSpecific: endpoint.ProviderSpecific{}, 913 }, 914 }, 915 }, 916 { 917 title: "IngressRoute with multiple host rules", 918 ingressRoute: IngressRoute{ 919 TypeMeta: metav1.TypeMeta{ 920 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 921 Kind: "IngressRoute", 922 }, 923 ObjectMeta: metav1.ObjectMeta{ 924 Name: "ingressroute-multi-host-match", 925 Namespace: defaultTraefikNamespace, 926 Annotations: map[string]string{ 927 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 928 "kubernetes.io/ingress.class": "traefik", 929 }, 930 }, 931 Spec: traefikIngressRouteSpec{ 932 Routes: []traefikRoute{ 933 { 934 Match: "Host(`d.example.com`) || Host(`e.example.com`)", 935 }, 936 }, 937 }, 938 }, 939 expected: []*endpoint.Endpoint{ 940 { 941 DNSName: "d.example.com", 942 Targets: []string{"target.domain.tld"}, 943 RecordType: endpoint.RecordTypeCNAME, 944 RecordTTL: 0, 945 Labels: endpoint.Labels{ 946 "resource": "ingressroute/traefik/ingressroute-multi-host-match", 947 }, 948 ProviderSpecific: endpoint.ProviderSpecific{}, 949 }, 950 { 951 DNSName: "e.example.com", 952 Targets: []string{"target.domain.tld"}, 953 RecordType: endpoint.RecordTypeCNAME, 954 RecordTTL: 0, 955 Labels: endpoint.Labels{ 956 "resource": "ingressroute/traefik/ingressroute-multi-host-match", 957 }, 958 ProviderSpecific: endpoint.ProviderSpecific{}, 959 }, 960 }, 961 }, 962 { 963 title: "IngressRoute with multiple host rules and annotation", 964 ingressRoute: IngressRoute{ 965 TypeMeta: metav1.TypeMeta{ 966 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 967 Kind: "IngressRoute", 968 }, 969 ObjectMeta: metav1.ObjectMeta{ 970 Name: "ingressroute-multi-host-annotations-match", 971 Namespace: defaultTraefikNamespace, 972 Annotations: map[string]string{ 973 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 974 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 975 "kubernetes.io/ingress.class": "traefik", 976 }, 977 }, 978 Spec: traefikIngressRouteSpec{ 979 Routes: []traefikRoute{ 980 { 981 Match: "Host(`g.example.com`, `h.example.com`)", 982 }, 983 }, 984 }, 985 }, 986 expected: []*endpoint.Endpoint{ 987 { 988 DNSName: "f.example.com", 989 Targets: []string{"target.domain.tld"}, 990 RecordType: endpoint.RecordTypeCNAME, 991 RecordTTL: 0, 992 Labels: endpoint.Labels{ 993 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 994 }, 995 ProviderSpecific: endpoint.ProviderSpecific{}, 996 }, 997 { 998 DNSName: "g.example.com", 999 Targets: []string{"target.domain.tld"}, 1000 RecordType: endpoint.RecordTypeCNAME, 1001 RecordTTL: 0, 1002 Labels: endpoint.Labels{ 1003 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 1004 }, 1005 ProviderSpecific: endpoint.ProviderSpecific{}, 1006 }, 1007 { 1008 DNSName: "h.example.com", 1009 Targets: []string{"target.domain.tld"}, 1010 RecordType: endpoint.RecordTypeCNAME, 1011 RecordTTL: 0, 1012 Labels: endpoint.Labels{ 1013 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 1014 }, 1015 ProviderSpecific: endpoint.ProviderSpecific{}, 1016 }, 1017 }, 1018 }, 1019 { 1020 title: "IngressRoute ignoring annotation", 1021 ingressRoute: IngressRoute{ 1022 TypeMeta: metav1.TypeMeta{ 1023 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 1024 Kind: "IngressRoute", 1025 }, 1026 ObjectMeta: metav1.ObjectMeta{ 1027 Name: "ingressroute-multi-host-annotations-match", 1028 Namespace: defaultTraefikNamespace, 1029 Annotations: map[string]string{ 1030 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 1031 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1032 "kubernetes.io/ingress.class": "traefik", 1033 }, 1034 }, 1035 Spec: traefikIngressRouteSpec{ 1036 Routes: []traefikRoute{ 1037 { 1038 Match: "Host(`g.example.com`, `h.example.com`)", 1039 }, 1040 }, 1041 }, 1042 }, 1043 ignoreHostnameAnnotation: true, 1044 expected: []*endpoint.Endpoint{ 1045 { 1046 DNSName: "g.example.com", 1047 Targets: []string{"target.domain.tld"}, 1048 RecordType: endpoint.RecordTypeCNAME, 1049 RecordTTL: 0, 1050 Labels: endpoint.Labels{ 1051 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 1052 }, 1053 ProviderSpecific: endpoint.ProviderSpecific{}, 1054 }, 1055 { 1056 DNSName: "h.example.com", 1057 Targets: []string{"target.domain.tld"}, 1058 RecordType: endpoint.RecordTypeCNAME, 1059 RecordTTL: 0, 1060 Labels: endpoint.Labels{ 1061 "resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match", 1062 }, 1063 ProviderSpecific: endpoint.ProviderSpecific{}, 1064 }, 1065 }, 1066 }, 1067 { 1068 title: "IngressRoute omit wildcard", 1069 ingressRoute: IngressRoute{ 1070 TypeMeta: metav1.TypeMeta{ 1071 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 1072 Kind: "IngressRoute", 1073 }, 1074 ObjectMeta: metav1.ObjectMeta{ 1075 Name: "ingressroute-omit-wildcard-host", 1076 Namespace: defaultTraefikNamespace, 1077 Annotations: map[string]string{ 1078 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1079 "kubernetes.io/ingress.class": "traefik", 1080 }, 1081 }, 1082 Spec: traefikIngressRouteSpec{ 1083 Routes: []traefikRoute{ 1084 { 1085 Match: "Host(`*`)", 1086 }, 1087 }, 1088 }, 1089 }, 1090 expected: nil, 1091 }, 1092 } { 1093 ti := ti 1094 t.Run(ti.title, func(t *testing.T) { 1095 t.Parallel() 1096 1097 fakeKubernetesClient := fakeKube.NewSimpleClientset() 1098 scheme := runtime.NewScheme() 1099 scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1100 scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1101 scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1102 scheme.AddKnownTypes(oldIngressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1103 scheme.AddKnownTypes(oldIngressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1104 scheme.AddKnownTypes(oldIngressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1105 fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) 1106 1107 ir := unstructured.Unstructured{} 1108 1109 ingressRouteAsJSON, err := json.Marshal(ti.ingressRoute) 1110 assert.NoError(t, err) 1111 1112 assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON)) 1113 1114 // Create proxy resources 1115 _, err = fakeDynamicClient.Resource(oldIngressrouteGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{}) 1116 assert.NoError(t, err) 1117 1118 source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false) 1119 assert.NoError(t, err) 1120 assert.NotNil(t, source) 1121 1122 count := &unstructured.UnstructuredList{} 1123 for len(count.Items) < 1 { 1124 count, _ = fakeDynamicClient.Resource(oldIngressrouteGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{}) 1125 } 1126 1127 endpoints, err := source.Endpoints(context.Background()) 1128 assert.NoError(t, err) 1129 assert.Len(t, endpoints, len(ti.expected)) 1130 assert.Equal(t, ti.expected, endpoints) 1131 }) 1132 } 1133 } 1134 1135 func TestTraefikProxyOldIngressRouteTCPEndpoints(t *testing.T) { 1136 t.Parallel() 1137 1138 for _, ti := range []struct { 1139 title string 1140 ingressRouteTCP IngressRouteTCP 1141 ignoreHostnameAnnotation bool 1142 expected []*endpoint.Endpoint 1143 }{ 1144 { 1145 title: "IngressRouteTCP with hostname annotation", 1146 ingressRouteTCP: IngressRouteTCP{ 1147 TypeMeta: metav1.TypeMeta{ 1148 APIVersion: oldIngressrouteTCPGVR.GroupVersion().String(), 1149 Kind: "IngressRouteTCP", 1150 }, 1151 ObjectMeta: metav1.ObjectMeta{ 1152 Name: "ingressroutetcp-annotation", 1153 Namespace: defaultTraefikNamespace, 1154 Annotations: map[string]string{ 1155 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 1156 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1157 "kubernetes.io/ingress.class": "traefik", 1158 }, 1159 }, 1160 }, 1161 expected: []*endpoint.Endpoint{ 1162 { 1163 DNSName: "a.example.com", 1164 Targets: []string{"target.domain.tld"}, 1165 RecordType: endpoint.RecordTypeCNAME, 1166 RecordTTL: 0, 1167 Labels: endpoint.Labels{ 1168 "resource": "ingressroutetcp/traefik/ingressroutetcp-annotation", 1169 }, 1170 ProviderSpecific: endpoint.ProviderSpecific{}, 1171 }, 1172 }, 1173 }, 1174 { 1175 title: "IngressRouteTCP with host sni rule", 1176 ingressRouteTCP: IngressRouteTCP{ 1177 TypeMeta: metav1.TypeMeta{ 1178 APIVersion: oldIngressrouteTCPGVR.GroupVersion().String(), 1179 Kind: "IngressRouteTCP", 1180 }, 1181 ObjectMeta: metav1.ObjectMeta{ 1182 Name: "ingressroutetcp-hostsni-match", 1183 Namespace: defaultTraefikNamespace, 1184 Annotations: map[string]string{ 1185 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1186 "kubernetes.io/ingress.class": "traefik", 1187 }, 1188 }, 1189 Spec: traefikIngressRouteTCPSpec{ 1190 Routes: []traefikRouteTCP{ 1191 { 1192 Match: "HostSNI(`b.example.com`)", 1193 }, 1194 }, 1195 }, 1196 }, 1197 expected: []*endpoint.Endpoint{ 1198 { 1199 DNSName: "b.example.com", 1200 Targets: []string{"target.domain.tld"}, 1201 RecordType: endpoint.RecordTypeCNAME, 1202 RecordTTL: 0, 1203 Labels: endpoint.Labels{ 1204 "resource": "ingressroutetcp/traefik/ingressroutetcp-hostsni-match", 1205 }, 1206 ProviderSpecific: endpoint.ProviderSpecific{}, 1207 }, 1208 }, 1209 }, 1210 { 1211 title: "IngressRouteTCP with multiple host sni rules", 1212 ingressRouteTCP: IngressRouteTCP{ 1213 TypeMeta: metav1.TypeMeta{ 1214 APIVersion: oldIngressrouteTCPGVR.GroupVersion().String(), 1215 Kind: "IngressRouteTCP", 1216 }, 1217 ObjectMeta: metav1.ObjectMeta{ 1218 Name: "ingressroutetcp-multi-host-match", 1219 Namespace: defaultTraefikNamespace, 1220 Annotations: map[string]string{ 1221 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1222 "kubernetes.io/ingress.class": "traefik", 1223 }, 1224 }, 1225 Spec: traefikIngressRouteTCPSpec{ 1226 Routes: []traefikRouteTCP{ 1227 { 1228 Match: "HostSNI(`d.example.com`) || HostSNI(`e.example.com`)", 1229 }, 1230 }, 1231 }, 1232 }, 1233 expected: []*endpoint.Endpoint{ 1234 { 1235 DNSName: "d.example.com", 1236 Targets: []string{"target.domain.tld"}, 1237 RecordType: endpoint.RecordTypeCNAME, 1238 RecordTTL: 0, 1239 Labels: endpoint.Labels{ 1240 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-match", 1241 }, 1242 ProviderSpecific: endpoint.ProviderSpecific{}, 1243 }, 1244 { 1245 DNSName: "e.example.com", 1246 Targets: []string{"target.domain.tld"}, 1247 RecordType: endpoint.RecordTypeCNAME, 1248 RecordTTL: 0, 1249 Labels: endpoint.Labels{ 1250 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-match", 1251 }, 1252 ProviderSpecific: endpoint.ProviderSpecific{}, 1253 }, 1254 }, 1255 }, 1256 { 1257 title: "IngressRouteTCP with multiple host sni rules and annotation", 1258 ingressRouteTCP: IngressRouteTCP{ 1259 TypeMeta: metav1.TypeMeta{ 1260 APIVersion: oldIngressrouteTCPGVR.GroupVersion().String(), 1261 Kind: "IngressRouteTCP", 1262 }, 1263 ObjectMeta: metav1.ObjectMeta{ 1264 Name: "ingressroutetcp-multi-host-annotations-match", 1265 Namespace: defaultTraefikNamespace, 1266 Annotations: map[string]string{ 1267 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 1268 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1269 "kubernetes.io/ingress.class": "traefik", 1270 }, 1271 }, 1272 Spec: traefikIngressRouteTCPSpec{ 1273 Routes: []traefikRouteTCP{ 1274 { 1275 Match: "HostSNI(`g.example.com`, `h.example.com`)", 1276 }, 1277 }, 1278 }, 1279 }, 1280 expected: []*endpoint.Endpoint{ 1281 { 1282 DNSName: "f.example.com", 1283 Targets: []string{"target.domain.tld"}, 1284 RecordType: endpoint.RecordTypeCNAME, 1285 RecordTTL: 0, 1286 Labels: endpoint.Labels{ 1287 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 1288 }, 1289 ProviderSpecific: endpoint.ProviderSpecific{}, 1290 }, 1291 { 1292 DNSName: "g.example.com", 1293 Targets: []string{"target.domain.tld"}, 1294 RecordType: endpoint.RecordTypeCNAME, 1295 RecordTTL: 0, 1296 Labels: endpoint.Labels{ 1297 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 1298 }, 1299 ProviderSpecific: endpoint.ProviderSpecific{}, 1300 }, 1301 { 1302 DNSName: "h.example.com", 1303 Targets: []string{"target.domain.tld"}, 1304 RecordType: endpoint.RecordTypeCNAME, 1305 RecordTTL: 0, 1306 Labels: endpoint.Labels{ 1307 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 1308 }, 1309 ProviderSpecific: endpoint.ProviderSpecific{}, 1310 }, 1311 }, 1312 }, 1313 { 1314 title: "IngressRouteTCP ignoring annotation", 1315 ingressRouteTCP: IngressRouteTCP{ 1316 TypeMeta: metav1.TypeMeta{ 1317 APIVersion: oldIngressrouteTCPGVR.GroupVersion().String(), 1318 Kind: "IngressRouteTCP", 1319 }, 1320 ObjectMeta: metav1.ObjectMeta{ 1321 Name: "ingressroutetcp-multi-host-annotations-match", 1322 Namespace: defaultTraefikNamespace, 1323 Annotations: map[string]string{ 1324 "external-dns.alpha.kubernetes.io/hostname": "f.example.com", 1325 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1326 "kubernetes.io/ingress.class": "traefik", 1327 }, 1328 }, 1329 Spec: traefikIngressRouteTCPSpec{ 1330 Routes: []traefikRouteTCP{ 1331 { 1332 Match: "HostSNI(`g.example.com`, `h.example.com`)", 1333 }, 1334 }, 1335 }, 1336 }, 1337 ignoreHostnameAnnotation: true, 1338 expected: []*endpoint.Endpoint{ 1339 { 1340 DNSName: "g.example.com", 1341 Targets: []string{"target.domain.tld"}, 1342 RecordType: endpoint.RecordTypeCNAME, 1343 RecordTTL: 0, 1344 Labels: endpoint.Labels{ 1345 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 1346 }, 1347 ProviderSpecific: endpoint.ProviderSpecific{}, 1348 }, 1349 { 1350 DNSName: "h.example.com", 1351 Targets: []string{"target.domain.tld"}, 1352 RecordType: endpoint.RecordTypeCNAME, 1353 RecordTTL: 0, 1354 Labels: endpoint.Labels{ 1355 "resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match", 1356 }, 1357 ProviderSpecific: endpoint.ProviderSpecific{}, 1358 }, 1359 }, 1360 }, 1361 { 1362 title: "IngressRouteTCP omit wildcard host sni", 1363 ingressRouteTCP: IngressRouteTCP{ 1364 TypeMeta: metav1.TypeMeta{ 1365 APIVersion: oldIngressrouteTCPGVR.GroupVersion().String(), 1366 Kind: "IngressRouteTCP", 1367 }, 1368 ObjectMeta: metav1.ObjectMeta{ 1369 Name: "ingressroutetcp-omit-wildcard-host", 1370 Namespace: defaultTraefikNamespace, 1371 Annotations: map[string]string{ 1372 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1373 "kubernetes.io/ingress.class": "traefik", 1374 }, 1375 }, 1376 Spec: traefikIngressRouteTCPSpec{ 1377 Routes: []traefikRouteTCP{ 1378 { 1379 Match: "HostSNI(`*`)", 1380 }, 1381 }, 1382 }, 1383 }, 1384 expected: nil, 1385 }, 1386 } { 1387 ti := ti 1388 t.Run(ti.title, func(t *testing.T) { 1389 t.Parallel() 1390 1391 fakeKubernetesClient := fakeKube.NewSimpleClientset() 1392 scheme := runtime.NewScheme() 1393 scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1394 scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1395 scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1396 scheme.AddKnownTypes(oldIngressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1397 scheme.AddKnownTypes(oldIngressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1398 scheme.AddKnownTypes(oldIngressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1399 fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) 1400 1401 ir := unstructured.Unstructured{} 1402 1403 ingressRouteAsJSON, err := json.Marshal(ti.ingressRouteTCP) 1404 assert.NoError(t, err) 1405 1406 assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON)) 1407 1408 // Create proxy resources 1409 _, err = fakeDynamicClient.Resource(oldIngressrouteTCPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{}) 1410 assert.NoError(t, err) 1411 1412 source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false) 1413 assert.NoError(t, err) 1414 assert.NotNil(t, source) 1415 1416 count := &unstructured.UnstructuredList{} 1417 for len(count.Items) < 1 { 1418 count, _ = fakeDynamicClient.Resource(oldIngressrouteTCPGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{}) 1419 } 1420 1421 endpoints, err := source.Endpoints(context.Background()) 1422 assert.NoError(t, err) 1423 assert.Len(t, endpoints, len(ti.expected)) 1424 assert.Equal(t, ti.expected, endpoints) 1425 }) 1426 } 1427 } 1428 1429 func TestTraefikProxyOldIngressRouteUDPEndpoints(t *testing.T) { 1430 t.Parallel() 1431 1432 for _, ti := range []struct { 1433 title string 1434 ingressRouteUDP IngressRouteUDP 1435 ignoreHostnameAnnotation bool 1436 expected []*endpoint.Endpoint 1437 }{ 1438 { 1439 title: "IngressRouteTCP with hostname annotation", 1440 ingressRouteUDP: IngressRouteUDP{ 1441 TypeMeta: metav1.TypeMeta{ 1442 APIVersion: oldIngressrouteUDPGVR.GroupVersion().String(), 1443 Kind: "IngressRouteUDP", 1444 }, 1445 ObjectMeta: metav1.ObjectMeta{ 1446 Name: "ingressrouteudp-annotation", 1447 Namespace: defaultTraefikNamespace, 1448 Annotations: map[string]string{ 1449 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 1450 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1451 "kubernetes.io/ingress.class": "traefik", 1452 }, 1453 }, 1454 }, 1455 expected: []*endpoint.Endpoint{ 1456 { 1457 DNSName: "a.example.com", 1458 Targets: []string{"target.domain.tld"}, 1459 RecordType: endpoint.RecordTypeCNAME, 1460 RecordTTL: 0, 1461 Labels: endpoint.Labels{ 1462 "resource": "ingressrouteudp/traefik/ingressrouteudp-annotation", 1463 }, 1464 ProviderSpecific: endpoint.ProviderSpecific{}, 1465 }, 1466 }, 1467 }, 1468 { 1469 title: "IngressRouteTCP with multiple hostname annotation", 1470 ingressRouteUDP: IngressRouteUDP{ 1471 TypeMeta: metav1.TypeMeta{ 1472 APIVersion: oldIngressrouteUDPGVR.GroupVersion().String(), 1473 Kind: "IngressRouteUDP", 1474 }, 1475 ObjectMeta: metav1.ObjectMeta{ 1476 Name: "ingressrouteudp-multi-annotation", 1477 Namespace: defaultTraefikNamespace, 1478 Annotations: map[string]string{ 1479 "external-dns.alpha.kubernetes.io/hostname": "a.example.com, b.example.com", 1480 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1481 "kubernetes.io/ingress.class": "traefik", 1482 }, 1483 }, 1484 }, 1485 expected: []*endpoint.Endpoint{ 1486 { 1487 DNSName: "a.example.com", 1488 Targets: []string{"target.domain.tld"}, 1489 RecordType: endpoint.RecordTypeCNAME, 1490 RecordTTL: 0, 1491 Labels: endpoint.Labels{ 1492 "resource": "ingressrouteudp/traefik/ingressrouteudp-multi-annotation", 1493 }, 1494 ProviderSpecific: endpoint.ProviderSpecific{}, 1495 }, 1496 { 1497 DNSName: "b.example.com", 1498 Targets: []string{"target.domain.tld"}, 1499 RecordType: endpoint.RecordTypeCNAME, 1500 RecordTTL: 0, 1501 Labels: endpoint.Labels{ 1502 "resource": "ingressrouteudp/traefik/ingressrouteudp-multi-annotation", 1503 }, 1504 ProviderSpecific: endpoint.ProviderSpecific{}, 1505 }, 1506 }, 1507 }, 1508 { 1509 title: "IngressRouteTCP ignoring hostname annotation", 1510 ingressRouteUDP: IngressRouteUDP{ 1511 TypeMeta: metav1.TypeMeta{ 1512 APIVersion: oldIngressrouteUDPGVR.GroupVersion().String(), 1513 Kind: "IngressRouteUDP", 1514 }, 1515 ObjectMeta: metav1.ObjectMeta{ 1516 Name: "ingressrouteudp-annotation", 1517 Namespace: defaultTraefikNamespace, 1518 Annotations: map[string]string{ 1519 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 1520 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1521 "kubernetes.io/ingress.class": "traefik", 1522 }, 1523 }, 1524 }, 1525 ignoreHostnameAnnotation: true, 1526 expected: nil, 1527 }, 1528 } { 1529 ti := ti 1530 t.Run(ti.title, func(t *testing.T) { 1531 t.Parallel() 1532 1533 fakeKubernetesClient := fakeKube.NewSimpleClientset() 1534 scheme := runtime.NewScheme() 1535 scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1536 scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1537 scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1538 scheme.AddKnownTypes(oldIngressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1539 scheme.AddKnownTypes(oldIngressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1540 scheme.AddKnownTypes(oldIngressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1541 fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) 1542 1543 ir := unstructured.Unstructured{} 1544 1545 ingressRouteAsJSON, err := json.Marshal(ti.ingressRouteUDP) 1546 assert.NoError(t, err) 1547 1548 assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON)) 1549 1550 // Create proxy resources 1551 _, err = fakeDynamicClient.Resource(oldIngressrouteUDPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{}) 1552 assert.NoError(t, err) 1553 1554 source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, false, false) 1555 assert.NoError(t, err) 1556 assert.NotNil(t, source) 1557 1558 count := &unstructured.UnstructuredList{} 1559 for len(count.Items) < 1 { 1560 count, _ = fakeDynamicClient.Resource(oldIngressrouteUDPGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{}) 1561 } 1562 1563 endpoints, err := source.Endpoints(context.Background()) 1564 assert.NoError(t, err) 1565 assert.Len(t, endpoints, len(ti.expected)) 1566 assert.Equal(t, ti.expected, endpoints) 1567 }) 1568 } 1569 } 1570 1571 func TestTraefikAPIGroupDisableFlags(t *testing.T) { 1572 t.Parallel() 1573 1574 for _, ti := range []struct { 1575 title string 1576 ingressRoute IngressRoute 1577 gvr schema.GroupVersionResource 1578 ignoreHostnameAnnotation bool 1579 disableLegacy bool 1580 disableNew bool 1581 expected []*endpoint.Endpoint 1582 }{ 1583 { 1584 title: "IngressRoute.traefik.containo.us with the legacy API group enabled", 1585 ingressRoute: IngressRoute{ 1586 TypeMeta: metav1.TypeMeta{ 1587 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 1588 Kind: "IngressRoute", 1589 }, 1590 ObjectMeta: metav1.ObjectMeta{ 1591 Name: "ingressroute-annotation", 1592 Namespace: defaultTraefikNamespace, 1593 Annotations: map[string]string{ 1594 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 1595 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1596 "kubernetes.io/ingress.class": "traefik", 1597 }, 1598 }, 1599 }, 1600 gvr: oldIngressrouteGVR, 1601 disableLegacy: false, 1602 disableNew: false, 1603 expected: []*endpoint.Endpoint{ 1604 { 1605 DNSName: "a.example.com", 1606 Targets: []string{"target.domain.tld"}, 1607 RecordType: endpoint.RecordTypeCNAME, 1608 RecordTTL: 0, 1609 Labels: endpoint.Labels{ 1610 "resource": "ingressroute/traefik/ingressroute-annotation", 1611 }, 1612 ProviderSpecific: endpoint.ProviderSpecific{}, 1613 }, 1614 }, 1615 }, 1616 { 1617 title: "IngressRoute.traefik.containo.us with the legacy API group disabled", 1618 ingressRoute: IngressRoute{ 1619 TypeMeta: metav1.TypeMeta{ 1620 APIVersion: oldIngressrouteGVR.GroupVersion().String(), 1621 Kind: "IngressRoute", 1622 }, 1623 ObjectMeta: metav1.ObjectMeta{ 1624 Name: "ingressroute-annotation", 1625 Namespace: defaultTraefikNamespace, 1626 Annotations: map[string]string{ 1627 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 1628 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1629 "kubernetes.io/ingress.class": "traefik", 1630 }, 1631 }, 1632 }, 1633 gvr: oldIngressrouteGVR, 1634 disableLegacy: true, 1635 disableNew: false, 1636 }, 1637 { 1638 title: "IngressRoute.traefik.io with the new API group enabled", 1639 ingressRoute: IngressRoute{ 1640 TypeMeta: metav1.TypeMeta{ 1641 APIVersion: ingressrouteGVR.GroupVersion().String(), 1642 Kind: "IngressRoute", 1643 }, 1644 ObjectMeta: metav1.ObjectMeta{ 1645 Name: "ingressroute-annotation", 1646 Namespace: defaultTraefikNamespace, 1647 Annotations: map[string]string{ 1648 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 1649 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1650 "kubernetes.io/ingress.class": "traefik", 1651 }, 1652 }, 1653 }, 1654 gvr: ingressrouteGVR, 1655 disableLegacy: false, 1656 disableNew: false, 1657 expected: []*endpoint.Endpoint{ 1658 { 1659 DNSName: "a.example.com", 1660 Targets: []string{"target.domain.tld"}, 1661 RecordType: endpoint.RecordTypeCNAME, 1662 RecordTTL: 0, 1663 Labels: endpoint.Labels{ 1664 "resource": "ingressroute/traefik/ingressroute-annotation", 1665 }, 1666 ProviderSpecific: endpoint.ProviderSpecific{}, 1667 }, 1668 }, 1669 }, 1670 { 1671 title: "IngressRoute.traefik.io with the new API group disabled", 1672 ingressRoute: IngressRoute{ 1673 TypeMeta: metav1.TypeMeta{ 1674 APIVersion: ingressrouteGVR.GroupVersion().String(), 1675 Kind: "IngressRoute", 1676 }, 1677 ObjectMeta: metav1.ObjectMeta{ 1678 Name: "ingressroute-annotation", 1679 Namespace: defaultTraefikNamespace, 1680 Annotations: map[string]string{ 1681 "external-dns.alpha.kubernetes.io/hostname": "a.example.com", 1682 "external-dns.alpha.kubernetes.io/target": "target.domain.tld", 1683 "kubernetes.io/ingress.class": "traefik", 1684 }, 1685 }, 1686 }, 1687 gvr: ingressrouteGVR, 1688 disableLegacy: false, 1689 disableNew: true, 1690 }, 1691 } { 1692 ti := ti 1693 t.Run(ti.title, func(t *testing.T) { 1694 t.Parallel() 1695 1696 fakeKubernetesClient := fakeKube.NewSimpleClientset() 1697 scheme := runtime.NewScheme() 1698 scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1699 scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1700 scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1701 scheme.AddKnownTypes(oldIngressrouteGVR.GroupVersion(), &IngressRoute{}, &IngressRouteList{}) 1702 scheme.AddKnownTypes(oldIngressrouteTCPGVR.GroupVersion(), &IngressRouteTCP{}, &IngressRouteTCPList{}) 1703 scheme.AddKnownTypes(oldIngressrouteUDPGVR.GroupVersion(), &IngressRouteUDP{}, &IngressRouteUDPList{}) 1704 fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme) 1705 1706 ir := unstructured.Unstructured{} 1707 1708 ingressRouteAsJSON, err := json.Marshal(ti.ingressRoute) 1709 assert.NoError(t, err) 1710 1711 assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON)) 1712 1713 // Create proxy resources 1714 _, err = fakeDynamicClient.Resource(ti.gvr).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{}) 1715 assert.NoError(t, err) 1716 1717 source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik", ti.ignoreHostnameAnnotation, ti.disableLegacy, ti.disableNew) 1718 assert.NoError(t, err) 1719 assert.NotNil(t, source) 1720 1721 count := &unstructured.UnstructuredList{} 1722 for len(count.Items) < 1 { 1723 count, _ = fakeDynamicClient.Resource(ti.gvr).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{}) 1724 } 1725 1726 endpoints, err := source.Endpoints(context.Background()) 1727 assert.NoError(t, err) 1728 assert.Len(t, endpoints, len(ti.expected)) 1729 assert.Equal(t, ti.expected, endpoints) 1730 }) 1731 } 1732 }