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