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  }