@@ -72,6 +72,13 @@ func TestReconcile1Pod(t *testing.T) {
72
72
namespace := "test"
73
73
ipv6Family := corev1 .IPv6Protocol
74
74
svcv4 , _ := newServiceAndEndpointMeta ("foo" , namespace )
75
+ svcv4ClusterIP , _ := newServiceAndEndpointMeta ("foo" , namespace )
76
+ svcv4ClusterIP .Spec .ClusterIP = "1.1.1.1"
77
+ svcv4Labels , _ := newServiceAndEndpointMeta ("foo" , namespace )
78
+ svcv4Labels .Labels = map [string ]string {"foo" : "bar" }
79
+ svcv4BadLabels , _ := newServiceAndEndpointMeta ("foo" , namespace )
80
+ svcv4BadLabels .Labels = map [string ]string {discovery .LabelServiceName : "bad" ,
81
+ discovery .LabelManagedBy : "actor" , corev1 .IsHeadlessService : "invalid" }
75
82
svcv6 , _ := newServiceAndEndpointMeta ("foo" , namespace )
76
83
svcv6 .Spec .IPFamily = & ipv6Family
77
84
svcv6ClusterIP , _ := newServiceAndEndpointMeta ("foo" , namespace )
@@ -94,6 +101,7 @@ func TestReconcile1Pod(t *testing.T) {
94
101
service corev1.Service
95
102
expectedAddressType discovery.AddressType
96
103
expectedEndpoint discovery.Endpoint
104
+ expectedLabels map [string ]string
97
105
}{
98
106
"ipv4" : {
99
107
service : svcv4 ,
@@ -112,6 +120,80 @@ func TestReconcile1Pod(t *testing.T) {
112
120
Name : "pod1" ,
113
121
},
114
122
},
123
+ expectedLabels : map [string ]string {
124
+ discovery .LabelManagedBy : controllerName ,
125
+ discovery .LabelServiceName : "foo" ,
126
+ corev1 .IsHeadlessService : "" ,
127
+ },
128
+ },
129
+ "ipv4-clusterip" : {
130
+ service : svcv4ClusterIP ,
131
+ expectedAddressType : discovery .AddressTypeIPv4 ,
132
+ expectedEndpoint : discovery.Endpoint {
133
+ Addresses : []string {"1.2.3.4" },
134
+ Conditions : discovery.EndpointConditions {Ready : utilpointer .BoolPtr (true )},
135
+ Topology : map [string ]string {
136
+ "kubernetes.io/hostname" : "node-1" ,
137
+ "topology.kubernetes.io/zone" : "us-central1-a" ,
138
+ "topology.kubernetes.io/region" : "us-central1" ,
139
+ },
140
+ TargetRef : & corev1.ObjectReference {
141
+ Kind : "Pod" ,
142
+ Namespace : namespace ,
143
+ Name : "pod1" ,
144
+ },
145
+ },
146
+ expectedLabels : map [string ]string {
147
+ discovery .LabelManagedBy : controllerName ,
148
+ discovery .LabelServiceName : "foo" ,
149
+ },
150
+ },
151
+ "ipv4-labels" : {
152
+ service : svcv4Labels ,
153
+ expectedAddressType : discovery .AddressTypeIPv4 ,
154
+ expectedEndpoint : discovery.Endpoint {
155
+ Addresses : []string {"1.2.3.4" },
156
+ Conditions : discovery.EndpointConditions {Ready : utilpointer .BoolPtr (true )},
157
+ Topology : map [string ]string {
158
+ "kubernetes.io/hostname" : "node-1" ,
159
+ "topology.kubernetes.io/zone" : "us-central1-a" ,
160
+ "topology.kubernetes.io/region" : "us-central1" ,
161
+ },
162
+ TargetRef : & corev1.ObjectReference {
163
+ Kind : "Pod" ,
164
+ Namespace : namespace ,
165
+ Name : "pod1" ,
166
+ },
167
+ },
168
+ expectedLabels : map [string ]string {
169
+ discovery .LabelManagedBy : controllerName ,
170
+ discovery .LabelServiceName : "foo" ,
171
+ "foo" : "bar" ,
172
+ corev1 .IsHeadlessService : "" ,
173
+ },
174
+ },
175
+ "ipv4-bad-labels" : {
176
+ service : svcv4BadLabels ,
177
+ expectedAddressType : discovery .AddressTypeIPv4 ,
178
+ expectedEndpoint : discovery.Endpoint {
179
+ Addresses : []string {"1.2.3.4" },
180
+ Conditions : discovery.EndpointConditions {Ready : utilpointer .BoolPtr (true )},
181
+ Topology : map [string ]string {
182
+ "kubernetes.io/hostname" : "node-1" ,
183
+ "topology.kubernetes.io/zone" : "us-central1-a" ,
184
+ "topology.kubernetes.io/region" : "us-central1" ,
185
+ },
186
+ TargetRef : & corev1.ObjectReference {
187
+ Kind : "Pod" ,
188
+ Namespace : namespace ,
189
+ Name : "pod1" ,
190
+ },
191
+ },
192
+ expectedLabels : map [string ]string {
193
+ discovery .LabelManagedBy : controllerName ,
194
+ discovery .LabelServiceName : "foo" ,
195
+ corev1 .IsHeadlessService : "" ,
196
+ },
115
197
},
116
198
"ipv6" : {
117
199
service : svcv6 ,
@@ -130,6 +212,11 @@ func TestReconcile1Pod(t *testing.T) {
130
212
Name : "pod1" ,
131
213
},
132
214
},
215
+ expectedLabels : map [string ]string {
216
+ discovery .LabelManagedBy : controllerName ,
217
+ discovery .LabelServiceName : "foo" ,
218
+ corev1 .IsHeadlessService : "" ,
219
+ },
133
220
},
134
221
"ipv6-clusterip" : {
135
222
service : svcv6ClusterIP ,
@@ -148,6 +235,10 @@ func TestReconcile1Pod(t *testing.T) {
148
235
Name : "pod1" ,
149
236
},
150
237
},
238
+ expectedLabels : map [string ]string {
239
+ discovery .LabelManagedBy : controllerName ,
240
+ discovery .LabelServiceName : "foo" ,
241
+ },
151
242
},
152
243
}
153
244
@@ -174,8 +265,8 @@ func TestReconcile1Pod(t *testing.T) {
174
265
t .Errorf ("Expected EndpointSlice name to start with %s, got %s" , testCase .service .Name , slice .Name )
175
266
}
176
267
177
- if slice . Labels [ discovery . LabelServiceName ] != testCase . service . Name {
178
- t .Errorf ("Expected EndpointSlice to have label set with %s value , got %s " , testCase .service . Name , slice .Labels [ discovery . LabelServiceName ] )
268
+ if ! reflect . DeepEqual ( testCase . expectedLabels , slice . Labels ) {
269
+ t .Errorf ("Expected EndpointSlice to have labels: %v , got %v " , testCase .expectedLabels , slice .Labels )
179
270
}
180
271
181
272
if slice .Annotations [corev1 .EndpointsLastChangeTriggerTime ] != triggerTime .Format (time .RFC3339Nano ) {
@@ -431,6 +522,81 @@ func TestReconcileEndpointSlicesUpdating(t *testing.T) {
431
522
expectUnorderedSlicesWithLengths (t , fetchEndpointSlices (t , client , namespace ), []int {100 , 100 , 50 })
432
523
}
433
524
525
+ // In some cases, such as service labels updates, all slices for that service will require a change
526
+ // This test ensures that we are updating those slices and not calling create + delete for each
527
+ func TestReconcileEndpointSlicesServicesLabelsUpdating (t * testing.T ) {
528
+ client := newClientset ()
529
+ namespace := "test"
530
+ svc , _ := newServiceAndEndpointMeta ("foo" , namespace )
531
+
532
+ // start with 250 pods
533
+ pods := []* corev1.Pod {}
534
+ for i := 0 ; i < 250 ; i ++ {
535
+ ready := ! (i % 3 == 0 )
536
+ pods = append (pods , newPod (i , namespace , ready , 1 ))
537
+ }
538
+
539
+ r := newReconciler (client , []* corev1.Node {{ObjectMeta : metav1.ObjectMeta {Name : "node-1" }}}, defaultMaxEndpointsPerSlice )
540
+ reconcileHelper (t , r , & svc , pods , []* discovery.EndpointSlice {}, time .Now ())
541
+ numActionsExpected := 3
542
+ assert .Len (t , client .Actions (), numActionsExpected , "Expected 3 additional clientset actions" )
543
+
544
+ slices := fetchEndpointSlices (t , client , namespace )
545
+ numActionsExpected ++
546
+ expectUnorderedSlicesWithLengths (t , slices , []int {100 , 100 , 50 })
547
+
548
+ // update service with new labels
549
+ svc .Labels = map [string ]string {"foo" : "bar" }
550
+ reconcileHelper (t , r , & svc , pods , []* discovery.EndpointSlice {& slices [0 ], & slices [1 ], & slices [2 ]}, time .Now ())
551
+
552
+ numActionsExpected += 3
553
+ assert .Len (t , client .Actions (), numActionsExpected , "Expected 3 additional clientset actions" )
554
+ expectActions (t , client .Actions (), 3 , "update" , "endpointslices" )
555
+
556
+ newSlices := fetchEndpointSlices (t , client , namespace )
557
+ expectUnorderedSlicesWithLengths (t , newSlices , []int {100 , 100 , 50 })
558
+ // check that the labels were updated
559
+ for _ , slice := range newSlices {
560
+ w , ok := slice .Labels ["foo" ]
561
+ if ! ok {
562
+ t .Errorf ("Expected label \" foo\" from parent service not found" )
563
+ } else if "bar" != w {
564
+ t .Errorf ("Expected EndpointSlice to have parent service labels: have %s value, expected bar" , w )
565
+ }
566
+ }
567
+ }
568
+
569
+ // In some cases, such as service labels updates, all slices for that service will require a change
570
+ // However, this should not happen for reserved labels
571
+ func TestReconcileEndpointSlicesServicesReservedLabels (t * testing.T ) {
572
+ client := newClientset ()
573
+ namespace := "test"
574
+ svc , _ := newServiceAndEndpointMeta ("foo" , namespace )
575
+
576
+ // start with 250 pods
577
+ pods := []* corev1.Pod {}
578
+ for i := 0 ; i < 250 ; i ++ {
579
+ ready := ! (i % 3 == 0 )
580
+ pods = append (pods , newPod (i , namespace , ready , 1 ))
581
+ }
582
+
583
+ r := newReconciler (client , []* corev1.Node {{ObjectMeta : metav1.ObjectMeta {Name : "node-1" }}}, defaultMaxEndpointsPerSlice )
584
+ reconcileHelper (t , r , & svc , pods , []* discovery.EndpointSlice {}, time .Now ())
585
+ numActionsExpected := 3
586
+ assert .Len (t , client .Actions (), numActionsExpected , "Expected 3 additional clientset actions" )
587
+ slices := fetchEndpointSlices (t , client , namespace )
588
+ numActionsExpected ++
589
+ expectUnorderedSlicesWithLengths (t , slices , []int {100 , 100 , 50 })
590
+
591
+ // update service with new labels
592
+ svc .Labels = map [string ]string {discovery .LabelServiceName : "bad" , discovery .LabelManagedBy : "actor" , corev1 .IsHeadlessService : "invalid" }
593
+ reconcileHelper (t , r , & svc , pods , []* discovery.EndpointSlice {& slices [0 ], & slices [1 ], & slices [2 ]}, time .Now ())
594
+ assert .Len (t , client .Actions (), numActionsExpected , "Expected no additional clientset actions" )
595
+
596
+ newSlices := fetchEndpointSlices (t , client , namespace )
597
+ expectUnorderedSlicesWithLengths (t , newSlices , []int {100 , 100 , 50 })
598
+ }
599
+
434
600
// In this test, we start with 10 slices that only have 30 endpoints each
435
601
// An initial reconcile makes no changes (as desired to limit writes)
436
602
// When we change a service port, all slices will need to be updated in some way
0 commit comments