Added tests for traefik source

This commit is contained in:
Thomas Kosiewski 2022-09-28 21:07:08 +02:00
parent 6c25133bce
commit b7016a0f38
2 changed files with 655 additions and 26 deletions

View File

@ -19,7 +19,9 @@ package source
import (
"context"
"fmt"
"regexp"
"sort"
"strings"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
@ -57,6 +59,11 @@ var (
}
)
var (
traefikHostExtractor = regexp.MustCompile(`(?:HostSNI|HostHeader|Host)\s*\(\s*(\x60.*?\x60)\s*\)`)
traefikValueProcessor = regexp.MustCompile(`\x60([^,\x60]+)\x60`)
)
type traefikSource struct {
annotationFilter string
dynamicKubeClient dynamic.Interface
@ -459,14 +466,17 @@ func (ts *traefikSource) endpointsFromIngressRoute(ingressRoute *traefikV1alpha1
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...)
}
// TODO: Implement Traefik router rule logic/regex magic
// if ingressRoute.Spec.Rules != nil {
// for _, rule := range ingressRoute.Spec.Rules {
// if rule.Host != "" {
// endpoints = append(endpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...)
// }
// }
// }
for _, route := range ingressRoute.Spec.Routes {
match := route.Match
for _, hostEntry := range traefikHostExtractor.FindAllString(match, -1) {
for _, host := range traefikValueProcessor.FindAllString(hostEntry, -1) {
host = strings.TrimPrefix(host, "`")
host = strings.TrimSuffix(host, "`")
endpoints = append(endpoints, endpointsForHostname(host, targets, ttl, providerSpecific, setIdentifier)...)
}
}
}
return endpoints, nil
}
@ -487,14 +497,17 @@ func (ts *traefikSource) endpointsFromIngressRouteTCP(ingressRoute *traefikV1alp
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...)
}
// TODO: Implement Traefik router rule logic/regex magic
// if ingressRoute.Spec.Rules != nil {
// for _, rule := range ingressRoute.Spec.Rules {
// if rule.Host != "" {
// endpoints = append(endpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...)
// }
// }
// }
for _, route := range ingressRoute.Spec.Routes {
match := route.Match
for _, hostEntry := range traefikHostExtractor.FindAllString(match, -1) {
for _, host := range traefikValueProcessor.FindAllString(hostEntry, -1) {
host = strings.TrimPrefix(host, "`")
host = strings.TrimSuffix(host, "`")
endpoints = append(endpoints, endpointsForHostname(host, targets, ttl, providerSpecific, setIdentifier)...)
}
}
}
return endpoints, nil
}
@ -515,15 +528,6 @@ func (ts *traefikSource) endpointsFromIngressRouteUDP(ingressRoute *traefikV1alp
endpoints = append(endpoints, endpointsForHostname(hostname, targets, ttl, providerSpecific, setIdentifier)...)
}
// TODO: Implement Traefik router rule logic/regex magic
// if ingressRoute.Spec.Rules != nil {
// for _, rule := range ingressRoute.Spec.Rules {
// if rule.Host != "" {
// endpoints = append(endpoints, endpointsForHostname(rule.Host, targets, ttl, providerSpecific, setIdentifier)...)
// }
// }
// }
return endpoints, nil
}
@ -547,7 +551,7 @@ func newTraefikUnstructuredConverter() (*unstructuredConverter, error) {
// Add the core types we need
uc.scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &traefikV1alpha1.IngressRoute{}, &traefikV1alpha1.IngressRouteList{})
uc.scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteTCP{}, &traefikV1alpha1.IngressRouteTCPList{})
uc.scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteUDP{}, &traefikV1alpha1.IngressRouteUDP{})
uc.scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteUDP{}, &traefikV1alpha1.IngressRouteUDPList{})
if err := scheme.AddToScheme(uc.scheme); err != nil {
return nil, err
}

View File

@ -0,0 +1,625 @@
/*
Copyright 2022 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package source
import (
"context"
"encoding/json"
"testing"
"github.com/stretchr/testify/assert"
traefikV1alpha1 "github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd/traefik/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
fakeDynamic "k8s.io/client-go/dynamic/fake"
fakeKube "k8s.io/client-go/kubernetes/fake"
"sigs.k8s.io/external-dns/endpoint"
)
// This is a compile-time validation that traefikSource is a Source.
var _ Source = &traefikSource{}
const defaultTraefikNamespace = "traefik"
func TestTraefikProxyIngressRouteEndpoints(t *testing.T) {
t.Parallel()
for _, ti := range []struct {
title string
ingressRoute traefikV1alpha1.IngressRoute
expected []*endpoint.Endpoint
}{
{
title: "IngressRoute with hostname annotation",
ingressRoute: traefikV1alpha1.IngressRoute{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRoute",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroute-annotation",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/hostname": "a.example.com",
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "a.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-annotation",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRoute with host rule",
ingressRoute: traefikV1alpha1.IngressRoute{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRoute",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroute-host-match",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
Spec: traefikV1alpha1.IngressRouteSpec{
Routes: []traefikV1alpha1.Route{
{
Match: "Host(`b.example.com`)",
},
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "b.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-host-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRoute with hostheader rule",
ingressRoute: traefikV1alpha1.IngressRoute{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRoute",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroute-hostheader-match",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
Spec: traefikV1alpha1.IngressRouteSpec{
Routes: []traefikV1alpha1.Route{
{
Match: "HostHeader(`c.example.com`)",
},
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "c.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-hostheader-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRoute with multiple host rules",
ingressRoute: traefikV1alpha1.IngressRoute{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRoute",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroute-multi-host-match",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
Spec: traefikV1alpha1.IngressRouteSpec{
Routes: []traefikV1alpha1.Route{
{
Match: "Host(`d.example.com`) || Host(`e.example.com`)",
},
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "d.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-multi-host-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
{
DNSName: "e.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-multi-host-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRoute with multiple host rules and annotation",
ingressRoute: traefikV1alpha1.IngressRoute{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRoute",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroute-multi-host-annotations-match",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/hostname": "f.example.com",
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
Spec: traefikV1alpha1.IngressRouteSpec{
Routes: []traefikV1alpha1.Route{
{
Match: "Host(`g.example.com`, `h.example.com`)",
},
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "f.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
{
DNSName: "g.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
{
DNSName: "h.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroute/traefik/ingressroute-multi-host-annotations-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
} {
ti := ti
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
fakeKubernetesClient := fakeKube.NewSimpleClientset()
scheme := runtime.NewScheme()
scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &traefikV1alpha1.IngressRoute{}, &traefikV1alpha1.IngressRouteList{})
scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteTCP{}, &traefikV1alpha1.IngressRouteTCPList{})
scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteUDP{}, &traefikV1alpha1.IngressRouteUDPList{})
fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme)
ir := unstructured.Unstructured{}
ingressRouteAsJSON, err := json.Marshal(ti.ingressRoute)
assert.NoError(t, err)
assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON))
// Create proxy resources
_, err = fakeDynamicClient.Resource(ingressrouteGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{})
assert.NoError(t, err)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik")
assert.NoError(t, err)
assert.NotNil(t, source)
count := &unstructured.UnstructuredList{}
for len(count.Items) < 1 {
count, _ = fakeDynamicClient.Resource(ingressrouteGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{})
}
endpoints, err := source.Endpoints(context.Background())
assert.NoError(t, err)
assert.Len(t, endpoints, len(ti.expected))
assert.Equal(t, endpoints, ti.expected)
})
}
}
func TestTraefikProxyIngressRouteTCPEndpoints(t *testing.T) {
t.Parallel()
for _, ti := range []struct {
title string
ingressRouteTCP traefikV1alpha1.IngressRouteTCP
expected []*endpoint.Endpoint
}{
{
title: "IngressRouteTCP with hostname annotation",
ingressRouteTCP: traefikV1alpha1.IngressRouteTCP{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRouteTCP",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroutetcp-annotation",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/hostname": "a.example.com",
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "a.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroutetcp/traefik/ingressroutetcp-annotation",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRouteTCP with host sni rule",
ingressRouteTCP: traefikV1alpha1.IngressRouteTCP{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRouteTCP",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroutetcp-hostsni-match",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
Spec: traefikV1alpha1.IngressRouteTCPSpec{
Routes: []traefikV1alpha1.RouteTCP{
{
Match: "HostSNI(`b.example.com`)",
},
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "b.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroutetcp/traefik/ingressroutetcp-hostsni-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRouteTCP with multiple host sni rules",
ingressRouteTCP: traefikV1alpha1.IngressRouteTCP{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRouteTCP",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroutetcp-multi-host-match",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
Spec: traefikV1alpha1.IngressRouteTCPSpec{
Routes: []traefikV1alpha1.RouteTCP{
{
Match: "HostSNI(`d.example.com`) || HostSNI(`e.example.com`)",
},
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "d.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
{
DNSName: "e.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRouteTCP with multiple host sni rules and annotation",
ingressRouteTCP: traefikV1alpha1.IngressRouteTCP{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRouteTCP",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressroutetcp-multi-host-annotations-match",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/hostname": "f.example.com",
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
Spec: traefikV1alpha1.IngressRouteTCPSpec{
Routes: []traefikV1alpha1.RouteTCP{
{
Match: "HostSNI(`g.example.com`, `h.example.com`)",
},
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "f.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
{
DNSName: "g.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
{
DNSName: "h.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressroutetcp/traefik/ingressroutetcp-multi-host-annotations-match",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
} {
ti := ti
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
fakeKubernetesClient := fakeKube.NewSimpleClientset()
scheme := runtime.NewScheme()
scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &traefikV1alpha1.IngressRoute{}, &traefikV1alpha1.IngressRouteList{})
scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteTCP{}, &traefikV1alpha1.IngressRouteTCPList{})
scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteUDP{}, &traefikV1alpha1.IngressRouteUDPList{})
fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme)
ir := unstructured.Unstructured{}
ingressRouteAsJSON, err := json.Marshal(ti.ingressRouteTCP)
assert.NoError(t, err)
assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON))
// Create proxy resources
_, err = fakeDynamicClient.Resource(ingressrouteTCPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{})
assert.NoError(t, err)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik")
assert.NoError(t, err)
assert.NotNil(t, source)
count := &unstructured.UnstructuredList{}
for len(count.Items) < 1 {
count, _ = fakeDynamicClient.Resource(ingressrouteTCPGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{})
}
endpoints, err := source.Endpoints(context.Background())
assert.NoError(t, err)
assert.Len(t, endpoints, len(ti.expected))
assert.Equal(t, endpoints, ti.expected)
})
}
}
func TestTraefikProxyIngressRouteUDPEndpoints(t *testing.T) {
t.Parallel()
for _, ti := range []struct {
title string
ingressRouteUDP traefikV1alpha1.IngressRouteUDP
expected []*endpoint.Endpoint
}{
{
title: "IngressRouteTCP with hostname annotation",
ingressRouteUDP: traefikV1alpha1.IngressRouteUDP{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRouteUDP",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressrouteudp-annotation",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/hostname": "a.example.com",
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "a.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressrouteudp/traefik/ingressrouteudp-annotation",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
{
title: "IngressRouteTCP with multiple hostname annotation",
ingressRouteUDP: traefikV1alpha1.IngressRouteUDP{
TypeMeta: metav1.TypeMeta{
APIVersion: traefikV1alpha1.SchemeGroupVersion.String(),
Kind: "IngressRouteUDP",
},
ObjectMeta: metav1.ObjectMeta{
Name: "ingressrouteudp-multi-annotation",
Namespace: defaultTraefikNamespace,
Annotations: map[string]string{
"external-dns.alpha.kubernetes.io/hostname": "a.example.com, b.example.com",
"external-dns.alpha.kubernetes.io/target": "target.domain.tld",
"kubernetes.io/ingress.class": "traefik",
},
},
},
expected: []*endpoint.Endpoint{
{
DNSName: "a.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressrouteudp/traefik/ingressrouteudp-multi-annotation",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
{
DNSName: "b.example.com",
Targets: []string{"target.domain.tld"},
RecordType: endpoint.RecordTypeCNAME,
RecordTTL: 0,
Labels: endpoint.Labels{
"resource": "ingressrouteudp/traefik/ingressrouteudp-multi-annotation",
},
ProviderSpecific: endpoint.ProviderSpecific{},
},
},
},
} {
ti := ti
t.Run(ti.title, func(t *testing.T) {
t.Parallel()
fakeKubernetesClient := fakeKube.NewSimpleClientset()
scheme := runtime.NewScheme()
scheme.AddKnownTypes(ingressrouteGVR.GroupVersion(), &traefikV1alpha1.IngressRoute{}, &traefikV1alpha1.IngressRouteList{})
scheme.AddKnownTypes(ingressrouteTCPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteTCP{}, &traefikV1alpha1.IngressRouteTCPList{})
scheme.AddKnownTypes(ingressrouteUDPGVR.GroupVersion(), &traefikV1alpha1.IngressRouteUDP{}, &traefikV1alpha1.IngressRouteUDPList{})
fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme)
ir := unstructured.Unstructured{}
ingressRouteAsJSON, err := json.Marshal(ti.ingressRouteUDP)
assert.NoError(t, err)
assert.NoError(t, ir.UnmarshalJSON(ingressRouteAsJSON))
// Create proxy resources
_, err = fakeDynamicClient.Resource(ingressrouteUDPGVR).Namespace(defaultTraefikNamespace).Create(context.Background(), &ir, metav1.CreateOptions{})
assert.NoError(t, err)
source, err := NewTraefikSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultTraefikNamespace, "kubernetes.io/ingress.class=traefik")
assert.NoError(t, err)
assert.NotNil(t, source)
count := &unstructured.UnstructuredList{}
for len(count.Items) < 1 {
count, _ = fakeDynamicClient.Resource(ingressrouteUDPGVR).Namespace(defaultTraefikNamespace).List(context.Background(), metav1.ListOptions{})
}
endpoints, err := source.Endpoints(context.Background())
assert.NoError(t, err)
assert.Len(t, endpoints, len(ti.expected))
assert.Equal(t, endpoints, ti.expected)
})
}
}