Skip to content

Commit 1f9edcb

Browse files
test(source/service): add serviceTypeFilter edge case (#5872)
* chore(source/service): serviceTypeFilter edge case tests Signed-off-by: ivan katliarchuk <[email protected]> * chore(source/service): serviceTypeFilter edge case tests Signed-off-by: ivan katliarchuk <[email protected]> --------- Signed-off-by: ivan katliarchuk <[email protected]>
1 parent 1da86e8 commit 1f9edcb

File tree

3 files changed

+262
-14
lines changed

3 files changed

+262
-14
lines changed

source/service.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,18 @@ type serviceSource struct {
8787
}
8888

8989
// NewServiceSource creates a new serviceSource with the given config.
90-
func NewServiceSource(ctx context.Context, kubeClient kubernetes.Interface, namespace, annotationFilter, fqdnTemplate string, combineFqdnAnnotation bool, compatibility string, publishInternal, publishHostIP, alwaysPublishNotReadyAddresses bool, serviceTypeFilter []string, ignoreHostnameAnnotation bool, labelSelector labels.Selector, resolveLoadBalancerHostname, listenEndpointEvents bool, exposeInternalIPv6 bool) (Source, error) {
90+
func NewServiceSource(
91+
ctx context.Context,
92+
kubeClient kubernetes.Interface,
93+
namespace, annotationFilter, fqdnTemplate string,
94+
combineFqdnAnnotation bool, compatibility string,
95+
publishInternal, publishHostIP, alwaysPublishNotReadyAddresses bool,
96+
serviceTypeFilter []string,
97+
ignoreHostnameAnnotation bool,
98+
labelSelector labels.Selector,
99+
resolveLoadBalancerHostname,
100+
listenEndpointEvents, exposeInternalIPv6 bool,
101+
) (Source, error) {
91102
tmpl, err := fqdn.ParseTemplate(fqdnTemplate)
92103
if err != nil {
93104
return nil, err
@@ -139,7 +150,7 @@ func NewServiceSource(ctx context.Context, kubeClient kubernetes.Interface, name
139150
// Transformer is used to reduce the memory usage of the informer.
140151
// The pod informer will otherwise store a full in-memory, go-typed copy of all pod schemas in the cluster.
141152
// If watchList is not used it will not prevent memory bursts on the initial informer sync.
142-
podInformer.Informer().SetTransform(func(i interface{}) (interface{}, error) {
153+
_ = podInformer.Informer().SetTransform(func(i interface{}) (interface{}, error) {
143154
pod, ok := i.(*v1.Pod)
144155
if !ok {
145156
return nil, fmt.Errorf("object is not a pod")
@@ -349,6 +360,7 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri
349360
targetsByHeadlessDomainAndType := sc.processHeadlessEndpointsFromSlices(
350361
svc, pods, endpointSlices, hostname, endpointsType, publishPodIPs, publishNotReadyAddresses)
351362
endpoints = buildHeadlessEndpoints(svc, targetsByHeadlessDomainAndType, ttl)
363+
352364
return endpoints
353365
}
354366

@@ -436,7 +448,11 @@ func findPodForEndpoint(ep discoveryv1.Endpoint, pods []*v1.Pod) *v1.Pod {
436448
}
437449

438450
// Helper to get targets for domain
439-
func (sc *serviceSource) getTargetsForDomain(pod *v1.Pod, ep discoveryv1.Endpoint, endpointSlice *discoveryv1.EndpointSlice, endpointsType string, headlessDomain string) endpoint.Targets {
451+
func (sc *serviceSource) getTargetsForDomain(
452+
pod *v1.Pod,
453+
ep discoveryv1.Endpoint,
454+
endpointSlice *discoveryv1.EndpointSlice,
455+
endpointsType, headlessDomain string) endpoint.Targets {
440456
targets := annotations.TargetsFromTargetAnnotation(pod.Annotations)
441457
if len(targets) == 0 {
442458
if endpointsType == EndpointsTypeNodeExternalIP {

source/service_fqdn_test.go

Lines changed: 144 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,14 @@ import (
3131
func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
3232

3333
for _, tt := range []struct {
34-
title string
35-
services []*v1.Service
36-
endpointSlices []*discoveryv1.EndpointSlice
37-
fqdnTemplate string
38-
combineFQDN bool
39-
publishHostIp bool
40-
expected []*endpoint.Endpoint
34+
title string
35+
services []*v1.Service
36+
endpointSlices []*discoveryv1.EndpointSlice
37+
fqdnTemplate string
38+
combineFQDN bool
39+
publishHostIp bool
40+
serviceTypesFilter []string
41+
expected []*endpoint.Endpoint
4142
}{
4243
{
4344
title: "templating with multiple services",
@@ -182,6 +183,129 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
182183
{DNSName: "www.service-two.website.example.tld", RecordType: endpoint.RecordTypeCNAME, Targets: endpoint.Targets{"www.bucket-name.amazonaws.com"}},
183184
},
184185
},
186+
{
187+
title: "fqdn with endpoint-type annotation and loose service type filtering",
188+
serviceTypesFilter: []string{},
189+
services: []*v1.Service{
190+
{
191+
ObjectMeta: metav1.ObjectMeta{
192+
Namespace: "svc-ns",
193+
Name: "svc-one",
194+
Annotations: map[string]string{
195+
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
196+
},
197+
},
198+
Spec: v1.ServiceSpec{
199+
Type: v1.ServiceTypeClusterIP,
200+
ClusterIP: v1.ClusterIPNone,
201+
ClusterIPs: []string{v1.ClusterIPNone},
202+
},
203+
Status: v1.ServiceStatus{
204+
LoadBalancer: v1.LoadBalancerStatus{},
205+
},
206+
},
207+
},
208+
endpointSlices: []*discoveryv1.EndpointSlice{
209+
{
210+
ObjectMeta: metav1.ObjectMeta{
211+
Name: "svc-one-xxxxx",
212+
Namespace: "svc-ns",
213+
Labels: map[string]string{
214+
discoveryv1.LabelServiceName: "svc-one",
215+
v1.IsHeadlessService: "",
216+
},
217+
},
218+
AddressType: discoveryv1.AddressTypeIPv4,
219+
Endpoints: []discoveryv1.Endpoint{
220+
{
221+
Addresses: []string{"100.66.2.246"},
222+
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
223+
NodeName: testutils.ToPtr("test-node"),
224+
TargetRef: &v1.ObjectReference{
225+
Kind: "Pod",
226+
Name: "pod-1",
227+
Namespace: "svc-ns",
228+
},
229+
},
230+
{
231+
Addresses: []string{"100.66.2.247"},
232+
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
233+
NodeName: testutils.ToPtr("test-node"),
234+
TargetRef: &v1.ObjectReference{
235+
Kind: "Pod",
236+
Name: "pod-2",
237+
Namespace: "svc-ns",
238+
},
239+
},
240+
},
241+
},
242+
},
243+
fqdnTemplate: "{{.Name}}.{{.Namespace}}.cluster.com",
244+
expected: []*endpoint.Endpoint{
245+
{DNSName: "ip-10-1-164-158.internal.svc-one.svc-ns.cluster.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"203.0.113.10"}},
246+
{DNSName: "svc-one.svc-ns.cluster.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"203.0.113.10"}},
247+
},
248+
},
249+
{
250+
title: "fqdn with endpoint-type annotation and service type filtering does not include required type",
251+
serviceTypesFilter: []string{string(v1.ServiceTypeClusterIP)},
252+
services: []*v1.Service{
253+
{
254+
ObjectMeta: metav1.ObjectMeta{
255+
Namespace: "svc-ns",
256+
Name: "svc-one",
257+
Annotations: map[string]string{
258+
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
259+
},
260+
},
261+
Spec: v1.ServiceSpec{
262+
Type: v1.ServiceTypeClusterIP,
263+
ClusterIP: v1.ClusterIPNone,
264+
ClusterIPs: []string{v1.ClusterIPNone},
265+
},
266+
Status: v1.ServiceStatus{
267+
LoadBalancer: v1.LoadBalancerStatus{},
268+
},
269+
},
270+
},
271+
endpointSlices: []*discoveryv1.EndpointSlice{
272+
{
273+
ObjectMeta: metav1.ObjectMeta{
274+
Name: "svc-one-xxxxx",
275+
Namespace: "svc-ns",
276+
Labels: map[string]string{
277+
discoveryv1.LabelServiceName: "svc-one",
278+
v1.IsHeadlessService: "",
279+
},
280+
},
281+
AddressType: discoveryv1.AddressTypeIPv4,
282+
Endpoints: []discoveryv1.Endpoint{
283+
{
284+
Addresses: []string{"100.66.2.246"},
285+
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
286+
NodeName: testutils.ToPtr("test-node"),
287+
TargetRef: &v1.ObjectReference{
288+
Kind: "Pod",
289+
Name: "pod-1",
290+
Namespace: "svc-ns",
291+
},
292+
},
293+
{
294+
Addresses: []string{"100.66.2.247"},
295+
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
296+
NodeName: testutils.ToPtr("test-node"),
297+
TargetRef: &v1.ObjectReference{
298+
Kind: "Pod",
299+
Name: "pod-2",
300+
Namespace: "svc-ns",
301+
},
302+
},
303+
},
304+
},
305+
},
306+
fqdnTemplate: "{{.Name}}.{{.Namespace}}.cluster.com",
307+
expected: []*endpoint.Endpoint{},
308+
},
185309
{
186310
title: "templating resolve service with zone PreferSameTrafficDistribution and topology.kubernetes.io/zone annotation",
187311
services: []*v1.Service{
@@ -571,6 +695,17 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
571695
require.NoError(t, err)
572696
}
573697

698+
_, err := kubeClient.CoreV1().Nodes().Create(t.Context(), &v1.Node{
699+
ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
700+
Status: v1.NodeStatus{
701+
Addresses: []v1.NodeAddress{
702+
{Type: v1.NodeExternalIP, Address: "203.0.113.10"},
703+
{Type: v1.NodeInternalIP, Address: "10.0.0.10"},
704+
},
705+
},
706+
}, metav1.CreateOptions{})
707+
require.NoError(t, err)
708+
574709
// Create endpoints and pods for the services
575710
for _, el := range tt.endpointSlices {
576711
_, err := kubeClient.DiscoveryV1().EndpointSlices(el.Namespace).Create(t.Context(), el, metav1.CreateOptions{})
@@ -583,6 +718,7 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
583718
},
584719
Spec: v1.PodSpec{
585720
Hostname: *ep.Hostname,
721+
NodeName: "test-node",
586722
},
587723
Status: v1.PodStatus{
588724
HostIP: fmt.Sprintf("10.1.20.4%d", i),
@@ -603,7 +739,7 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
603739
true,
604740
tt.publishHostIp,
605741
true,
606-
[]string{},
742+
tt.serviceTypesFilter,
607743
false,
608744
labels.Everything(),
609745
false,

source/service_test.go

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3171,6 +3171,102 @@ func TestHeadlessServices(t *testing.T) {
31713171
},
31723172
false,
31733173
},
3174+
{
3175+
"headless service with endpoints-type annotation is outside of serviceTypeFilter scope",
3176+
"",
3177+
"testing",
3178+
"foo",
3179+
v1.ServiceTypeClusterIP,
3180+
"",
3181+
"",
3182+
false,
3183+
false,
3184+
map[string]string{"component": "foo"},
3185+
map[string]string{
3186+
annotations.HostnameKey: "service.example.org",
3187+
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
3188+
},
3189+
map[string]string{},
3190+
v1.ClusterIPNone,
3191+
[]string{"2001:db8::1"},
3192+
[]string{"2001:db8::4"},
3193+
map[string]string{
3194+
"component": "foo",
3195+
},
3196+
[]string{},
3197+
[]string{"foo"},
3198+
[]string{"", "", ""},
3199+
[]bool{true, true, true},
3200+
false,
3201+
[]v1.Node{
3202+
{
3203+
Status: v1.NodeStatus{
3204+
Addresses: []v1.NodeAddress{
3205+
{
3206+
Type: v1.NodeExternalIP,
3207+
Address: "1.2.3.4",
3208+
},
3209+
{
3210+
Type: v1.NodeInternalIP,
3211+
Address: "10.0.10.12",
3212+
},
3213+
},
3214+
},
3215+
},
3216+
},
3217+
[]string{string(v1.ServiceTypeClusterIP)},
3218+
[]*endpoint.Endpoint{},
3219+
false,
3220+
},
3221+
{
3222+
"headless service with endpoints-type annotation is in the scope of serviceTypeFilter",
3223+
"",
3224+
"testing",
3225+
"foo",
3226+
v1.ServiceTypeClusterIP,
3227+
"",
3228+
"",
3229+
false,
3230+
false,
3231+
map[string]string{"component": "foo"},
3232+
map[string]string{
3233+
annotations.HostnameKey: "service.example.org",
3234+
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
3235+
},
3236+
map[string]string{},
3237+
v1.ClusterIPNone,
3238+
[]string{"2001:db8::1"},
3239+
[]string{"1.2.3.4"},
3240+
map[string]string{
3241+
"component": "foo",
3242+
},
3243+
[]string{},
3244+
[]string{"foo"},
3245+
[]string{"", "", ""},
3246+
[]bool{true, true, true},
3247+
false,
3248+
[]v1.Node{
3249+
{
3250+
Status: v1.NodeStatus{
3251+
Addresses: []v1.NodeAddress{
3252+
{
3253+
Type: v1.NodeExternalIP,
3254+
Address: "1.2.3.4",
3255+
},
3256+
{
3257+
Type: v1.NodeInternalIP,
3258+
Address: "10.0.10.12",
3259+
},
3260+
},
3261+
},
3262+
},
3263+
},
3264+
[]string{string(v1.ServiceTypeClusterIP), string(v1.ServiceTypeNodePort)},
3265+
[]*endpoint.Endpoint{
3266+
{DNSName: "service.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
3267+
},
3268+
false,
3269+
},
31743270
} {
31753271

31763272
t.Run(tc.title, func(t *testing.T) {
@@ -3198,15 +3294,15 @@ func TestHeadlessServices(t *testing.T) {
31983294
require.NoError(t, err)
31993295

32003296
var endpointSliceEndpoints []discoveryv1.Endpoint
3201-
for i, podname := range tc.podnames {
3297+
for i, podName := range tc.podnames {
32023298
pod := &v1.Pod{
32033299
Spec: v1.PodSpec{
32043300
Containers: []v1.Container{},
32053301
Hostname: tc.hostnames[i],
32063302
},
32073303
ObjectMeta: metav1.ObjectMeta{
32083304
Namespace: tc.svcNamespace,
3209-
Name: podname,
3305+
Name: podName,
32103306
Labels: tc.labels,
32113307
Annotations: tc.podAnnotations,
32123308
},
@@ -3224,7 +3320,7 @@ func TestHeadlessServices(t *testing.T) {
32243320
TargetRef: &v1.ObjectReference{
32253321
APIVersion: "",
32263322
Kind: "Pod",
3227-
Name: podname,
3323+
Name: podName,
32283324
},
32293325
Conditions: discoveryv1.EndpointConditions{
32303326
Ready: &tc.podsReady[i],

0 commit comments

Comments
 (0)