sigs.k8s.io/external-dns@v0.14.1/source/kong_tcpingress_test.go (about)

     1  /*
     2  Copyright 2021 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  	"testing"
    23  
    24  	"github.com/stretchr/testify/assert"
    25  	corev1 "k8s.io/api/core/v1"
    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 kongTCPIngressSource is a Source.
    35  var _ Source = &kongTCPIngressSource{}
    36  
    37  const defaultKongNamespace = "kong"
    38  
    39  func TestKongTCPIngressEndpoints(t *testing.T) {
    40  	t.Parallel()
    41  
    42  	for _, ti := range []struct {
    43  		title                    string
    44  		tcpProxy                 TCPIngress
    45  		ignoreHostnameAnnotation bool
    46  		expected                 []*endpoint.Endpoint
    47  	}{
    48  		{
    49  			title: "TCPIngress with hostname annotation",
    50  			tcpProxy: TCPIngress{
    51  				TypeMeta: metav1.TypeMeta{
    52  					APIVersion: kongGroupdVersionResource.GroupVersion().String(),
    53  					Kind:       "TCPIngress",
    54  				},
    55  				ObjectMeta: metav1.ObjectMeta{
    56  					Name:      "tcp-ingress-annotation",
    57  					Namespace: defaultKongNamespace,
    58  					Annotations: map[string]string{
    59  						"external-dns.alpha.kubernetes.io/hostname": "a.example.com",
    60  						"kubernetes.io/ingress.class":               "kong",
    61  					},
    62  				},
    63  				Spec: tcpIngressSpec{
    64  					Rules: []tcpIngressRule{
    65  						{
    66  							Port: 30000,
    67  						},
    68  						{
    69  							Port: 30001,
    70  						},
    71  					},
    72  				},
    73  				Status: tcpIngressStatus{
    74  					LoadBalancer: corev1.LoadBalancerStatus{
    75  						Ingress: []corev1.LoadBalancerIngress{
    76  							{
    77  								Hostname: "a691234567a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com",
    78  							},
    79  						},
    80  					},
    81  				},
    82  			},
    83  			expected: []*endpoint.Endpoint{
    84  				{
    85  					DNSName:    "a.example.com",
    86  					Targets:    []string{"a691234567a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com"},
    87  					RecordType: endpoint.RecordTypeCNAME,
    88  					RecordTTL:  0,
    89  					Labels: endpoint.Labels{
    90  						"resource": "tcpingress/kong/tcp-ingress-annotation",
    91  					},
    92  					ProviderSpecific: endpoint.ProviderSpecific{},
    93  				},
    94  			},
    95  		},
    96  		{
    97  			title: "TCPIngress using SNI",
    98  			tcpProxy: TCPIngress{
    99  				TypeMeta: metav1.TypeMeta{
   100  					APIVersion: kongGroupdVersionResource.GroupVersion().String(),
   101  					Kind:       "TCPIngress",
   102  				},
   103  				ObjectMeta: metav1.ObjectMeta{
   104  					Name:      "tcp-ingress-sni",
   105  					Namespace: defaultKongNamespace,
   106  					Annotations: map[string]string{
   107  						"kubernetes.io/ingress.class": "kong",
   108  					},
   109  				},
   110  				Spec: tcpIngressSpec{
   111  					Rules: []tcpIngressRule{
   112  						{
   113  							Port: 30002,
   114  							Host: "b.example.com",
   115  						},
   116  						{
   117  							Port: 30003,
   118  							Host: "c.example.com",
   119  						},
   120  					},
   121  				},
   122  				Status: tcpIngressStatus{
   123  					LoadBalancer: corev1.LoadBalancerStatus{
   124  						Ingress: []corev1.LoadBalancerIngress{
   125  							{
   126  								Hostname: "a123456769a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com",
   127  							},
   128  						},
   129  					},
   130  				},
   131  			},
   132  			expected: []*endpoint.Endpoint{
   133  				{
   134  					DNSName:    "b.example.com",
   135  					Targets:    []string{"a123456769a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com"},
   136  					RecordType: endpoint.RecordTypeCNAME,
   137  					RecordTTL:  0,
   138  					Labels: endpoint.Labels{
   139  						"resource": "tcpingress/kong/tcp-ingress-sni",
   140  					},
   141  					ProviderSpecific: endpoint.ProviderSpecific{},
   142  				},
   143  				{
   144  					DNSName:    "c.example.com",
   145  					Targets:    []string{"a123456769a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com"},
   146  					RecordType: endpoint.RecordTypeCNAME,
   147  					Labels: endpoint.Labels{
   148  						"resource": "tcpingress/kong/tcp-ingress-sni",
   149  					},
   150  					ProviderSpecific: endpoint.ProviderSpecific{},
   151  				},
   152  			},
   153  		},
   154  		{
   155  			title: "TCPIngress with hostname annotation and using SNI",
   156  			tcpProxy: TCPIngress{
   157  				TypeMeta: metav1.TypeMeta{
   158  					APIVersion: kongGroupdVersionResource.GroupVersion().String(),
   159  					Kind:       "TCPIngress",
   160  				},
   161  				ObjectMeta: metav1.ObjectMeta{
   162  					Name:      "tcp-ingress-both",
   163  					Namespace: defaultKongNamespace,
   164  					Annotations: map[string]string{
   165  						"external-dns.alpha.kubernetes.io/hostname": "d.example.com",
   166  						"kubernetes.io/ingress.class":               "kong",
   167  					},
   168  				},
   169  				Spec: tcpIngressSpec{
   170  					Rules: []tcpIngressRule{
   171  						{
   172  							Port: 30004,
   173  							Host: "e.example.com",
   174  						},
   175  						{
   176  							Port: 30005,
   177  							Host: "f.example.com",
   178  						},
   179  					},
   180  				},
   181  				Status: tcpIngressStatus{
   182  					LoadBalancer: corev1.LoadBalancerStatus{
   183  						Ingress: []corev1.LoadBalancerIngress{
   184  							{
   185  								Hostname: "a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com",
   186  							},
   187  						},
   188  					},
   189  				},
   190  			},
   191  			expected: []*endpoint.Endpoint{
   192  				{
   193  					DNSName:    "d.example.com",
   194  					Targets:    []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"},
   195  					RecordType: endpoint.RecordTypeCNAME,
   196  					RecordTTL:  0,
   197  					Labels: endpoint.Labels{
   198  						"resource": "tcpingress/kong/tcp-ingress-both",
   199  					},
   200  					ProviderSpecific: endpoint.ProviderSpecific{},
   201  				},
   202  				{
   203  					DNSName:    "e.example.com",
   204  					Targets:    []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"},
   205  					RecordType: endpoint.RecordTypeCNAME,
   206  					RecordTTL:  0,
   207  					Labels: endpoint.Labels{
   208  						"resource": "tcpingress/kong/tcp-ingress-both",
   209  					},
   210  					ProviderSpecific: endpoint.ProviderSpecific{},
   211  				},
   212  				{
   213  					DNSName:    "f.example.com",
   214  					Targets:    []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"},
   215  					RecordType: endpoint.RecordTypeCNAME,
   216  					RecordTTL:  0,
   217  					Labels: endpoint.Labels{
   218  						"resource": "tcpingress/kong/tcp-ingress-both",
   219  					},
   220  					ProviderSpecific: endpoint.ProviderSpecific{},
   221  				},
   222  			},
   223  		},
   224  		{
   225  			title: "TCPIngress ignoring hostname annotation",
   226  			tcpProxy: TCPIngress{
   227  				TypeMeta: metav1.TypeMeta{
   228  					APIVersion: kongGroupdVersionResource.GroupVersion().String(),
   229  					Kind:       "TCPIngress",
   230  				},
   231  				ObjectMeta: metav1.ObjectMeta{
   232  					Name:      "tcp-ingress-both",
   233  					Namespace: defaultKongNamespace,
   234  					Annotations: map[string]string{
   235  						"external-dns.alpha.kubernetes.io/hostname": "d.example.com",
   236  						"kubernetes.io/ingress.class":               "kong",
   237  					},
   238  				},
   239  				Spec: tcpIngressSpec{
   240  					Rules: []tcpIngressRule{
   241  						{
   242  							Port: 30004,
   243  							Host: "e.example.com",
   244  						},
   245  						{
   246  							Port: 30005,
   247  							Host: "f.example.com",
   248  						},
   249  					},
   250  				},
   251  				Status: tcpIngressStatus{
   252  					LoadBalancer: corev1.LoadBalancerStatus{
   253  						Ingress: []corev1.LoadBalancerIngress{
   254  							{
   255  								Hostname: "a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com",
   256  							},
   257  						},
   258  					},
   259  				},
   260  			},
   261  			ignoreHostnameAnnotation: true,
   262  			expected: []*endpoint.Endpoint{
   263  				{
   264  					DNSName:    "e.example.com",
   265  					Targets:    []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"},
   266  					RecordType: endpoint.RecordTypeCNAME,
   267  					RecordTTL:  0,
   268  					Labels: endpoint.Labels{
   269  						"resource": "tcpingress/kong/tcp-ingress-both",
   270  					},
   271  					ProviderSpecific: endpoint.ProviderSpecific{},
   272  				},
   273  				{
   274  					DNSName:    "f.example.com",
   275  					Targets:    []string{"a12e71861a4303f063456769a314a3bd-1291189659.us-east-1.elb.amazonaws.com"},
   276  					RecordType: endpoint.RecordTypeCNAME,
   277  					RecordTTL:  0,
   278  					Labels: endpoint.Labels{
   279  						"resource": "tcpingress/kong/tcp-ingress-both",
   280  					},
   281  					ProviderSpecific: endpoint.ProviderSpecific{},
   282  				},
   283  			},
   284  		},
   285  		{
   286  			title: "TCPIngress with target annotation",
   287  			tcpProxy: TCPIngress{
   288  				TypeMeta: metav1.TypeMeta{
   289  					APIVersion: kongGroupdVersionResource.GroupVersion().String(),
   290  					Kind:       "TCPIngress",
   291  				},
   292  				ObjectMeta: metav1.ObjectMeta{
   293  					Name:      "tcp-ingress-sni",
   294  					Namespace: defaultKongNamespace,
   295  					Annotations: map[string]string{
   296  						"kubernetes.io/ingress.class":             "kong",
   297  						"external-dns.alpha.kubernetes.io/target": "203.2.45.7",
   298  					},
   299  				},
   300  				Spec: tcpIngressSpec{
   301  					Rules: []tcpIngressRule{
   302  						{
   303  							Port: 30002,
   304  							Host: "b.example.com",
   305  						},
   306  						{
   307  							Port: 30003,
   308  							Host: "c.example.com",
   309  						},
   310  					},
   311  				},
   312  				Status: tcpIngressStatus{
   313  					LoadBalancer: corev1.LoadBalancerStatus{
   314  						Ingress: []corev1.LoadBalancerIngress{
   315  							{
   316  								Hostname: "a123456769a314e71861a4303f06a3bd-1291189659.us-east-1.elb.amazonaws.com",
   317  							},
   318  						},
   319  					},
   320  				},
   321  			},
   322  			expected: []*endpoint.Endpoint{
   323  				{
   324  					DNSName:    "b.example.com",
   325  					Targets:    []string{"203.2.45.7"},
   326  					RecordType: endpoint.RecordTypeA,
   327  					RecordTTL:  0,
   328  					Labels: endpoint.Labels{
   329  						"resource": "tcpingress/kong/tcp-ingress-sni",
   330  					},
   331  					ProviderSpecific: endpoint.ProviderSpecific{},
   332  				},
   333  				{
   334  					DNSName:    "c.example.com",
   335  					Targets:    []string{"203.2.45.7"},
   336  					RecordType: endpoint.RecordTypeA,
   337  					Labels: endpoint.Labels{
   338  						"resource": "tcpingress/kong/tcp-ingress-sni",
   339  					},
   340  					ProviderSpecific: endpoint.ProviderSpecific{},
   341  				},
   342  			},
   343  		},
   344  	} {
   345  		ti := ti
   346  		t.Run(ti.title, func(t *testing.T) {
   347  			t.Parallel()
   348  
   349  			fakeKubernetesClient := fakeKube.NewSimpleClientset()
   350  			scheme := runtime.NewScheme()
   351  			scheme.AddKnownTypes(kongGroupdVersionResource.GroupVersion(), &TCPIngress{}, &TCPIngressList{})
   352  			fakeDynamicClient := fakeDynamic.NewSimpleDynamicClient(scheme)
   353  
   354  			tcpi := unstructured.Unstructured{}
   355  
   356  			tcpIngressAsJSON, err := json.Marshal(ti.tcpProxy)
   357  			assert.NoError(t, err)
   358  
   359  			assert.NoError(t, tcpi.UnmarshalJSON(tcpIngressAsJSON))
   360  
   361  			// Create proxy resources
   362  			_, err = fakeDynamicClient.Resource(kongGroupdVersionResource).Namespace(defaultKongNamespace).Create(context.Background(), &tcpi, metav1.CreateOptions{})
   363  			assert.NoError(t, err)
   364  
   365  			source, err := NewKongTCPIngressSource(context.TODO(), fakeDynamicClient, fakeKubernetesClient, defaultKongNamespace, "kubernetes.io/ingress.class=kong", ti.ignoreHostnameAnnotation)
   366  			assert.NoError(t, err)
   367  			assert.NotNil(t, source)
   368  
   369  			count := &unstructured.UnstructuredList{}
   370  			for len(count.Items) < 1 {
   371  				count, _ = fakeDynamicClient.Resource(kongGroupdVersionResource).Namespace(defaultKongNamespace).List(context.Background(), metav1.ListOptions{})
   372  			}
   373  
   374  			endpoints, err := source.Endpoints(context.Background())
   375  			assert.NoError(t, err)
   376  			assert.Len(t, endpoints, len(ti.expected))
   377  			assert.Equal(t, ti.expected, endpoints)
   378  		})
   379  	}
   380  }