@@ -54,6 +54,20 @@ const (
54
54
// 5ms, 10ms, 20ms, 40ms, 80ms, 160ms, 320ms, 640ms, 1.3s, 2.6s, 5.1s,
55
55
// 10.2s, 20.4s, 41s, 82s
56
56
maxRetries = 15
57
+ // controllerName is a unique value used with LabelManagedBy to indicated
58
+ // the component managing an EndpointSlice.
59
+ controllerName = "endpointslice-controller.k8s.io"
60
+ // managedBySetupAnnotation is set on a Service to indicate that
61
+ // EndpointSlices for the Service have already been configured with
62
+ // LabelManagedBy. If this annotation is not set, all related EndpointSlices
63
+ // will have LabelManagedBy set to reference this controller if the label
64
+ // is not already set. Once all EndpointSlices are labeled, the Controller
65
+ // will set this annotation on the Service.
66
+ managedBySetupAnnotation = "endpointslice.kubernetes.io/managed-by-setup"
67
+ // managedBySetupCompleteValue represents the value of the
68
+ // managedBySetupAnnotation that indicates that the setup process has been
69
+ // completed for a Service.
70
+ managedBySetupCompleteValue = "true"
57
71
)
58
72
59
73
// NewController creates and initializes a new Controller
@@ -286,7 +300,28 @@ func (c *Controller) syncService(key string) error {
286
300
return err
287
301
}
288
302
289
- esLabelSelector := labels .Set (map [string ]string {discovery .LabelServiceName : service .Name }).AsSelectorPreValidated ()
303
+ // With the goal of different controllers being able to manage different
304
+ // subsets of EndpointSlices, LabelManagedBy has been added to indicate
305
+ // which controller or entity manages an EndpointSlice. As part of this
306
+ // v1.16->v1.17 change, EndpointSlices will initially be assumed to be
307
+ // managed by this controller unless a label is set to indicate otherwise.
308
+ // To ensure a seamless upgrade process, the managedBySetupAnnotation is
309
+ // used to indicate that LabelManagedBy has been set initially for related
310
+ // EndpointSlices. If it hasn't been set to the expected value here, we call
311
+ // ensureSetupManagedByAnnotation() to set up LabelManagedBy on each
312
+ // EndpointSlice.
313
+ // TODO(robscott): Remove this before v1.18.
314
+ err = c .ensureSetupManagedByAnnotation (service )
315
+ if err != nil {
316
+ c .eventRecorder .Eventf (service , v1 .EventTypeWarning , "FailedToSetEndpointSliceManagedByLabel" ,
317
+ "Error adding managed-by Label to Endpoint Slices for Service %s/%s: %v" , service .Namespace , service .Name , err )
318
+ return err
319
+ }
320
+
321
+ esLabelSelector := labels .Set (map [string ]string {
322
+ discovery .LabelServiceName : service .Name ,
323
+ discovery .LabelManagedBy : controllerName ,
324
+ }).AsSelectorPreValidated ()
290
325
endpointSlices , err := c .endpointSliceLister .EndpointSlices (service .Namespace ).List (esLabelSelector )
291
326
292
327
if err != nil {
@@ -337,6 +372,49 @@ func (c *Controller) onServiceDelete(obj interface{}) {
337
372
c .queue .Add (key )
338
373
}
339
374
375
+ // ensureSetupManagedByAnnotation selects all EndpointSlices for a Service and
376
+ // ensures they have LabelManagedBy set appropriately. This ensures that only
377
+ // one controller or entity is trying to manage a given EndpointSlice. This
378
+ // function provides backwards compatibility with the initial alpha release of
379
+ // EndpointSlices that did not include these labels.
380
+ // TODO(robscott): Remove this in time for v1.18.
381
+ func (c * Controller ) ensureSetupManagedByAnnotation (service * v1.Service ) error {
382
+ if managedBySetup , ok := service .Annotations [managedBySetupAnnotation ]; ok && managedBySetup == managedBySetupCompleteValue {
383
+ return nil
384
+ }
385
+
386
+ esLabelSelector := labels .Set (map [string ]string {discovery .LabelServiceName : service .Name }).AsSelectorPreValidated ()
387
+ endpointSlices , err := c .endpointSliceLister .EndpointSlices (service .Namespace ).List (esLabelSelector )
388
+
389
+ if err != nil {
390
+ c .eventRecorder .Eventf (service , v1 .EventTypeWarning , "FailedToListEndpointSlices" ,
391
+ "Error listing Endpoint Slices for Service %s/%s: %v" , service .Namespace , service .Name , err )
392
+ return err
393
+ }
394
+
395
+ for _ , endpointSlice := range endpointSlices {
396
+ if _ , ok := endpointSlice .Labels [discovery .LabelManagedBy ]; ! ok {
397
+ if endpointSlice .Labels == nil {
398
+ endpointSlice .Labels = make (map [string ]string )
399
+ }
400
+
401
+ endpointSlice .Labels [discovery .LabelManagedBy ] = controllerName
402
+ _ , err = c .client .DiscoveryV1alpha1 ().EndpointSlices (endpointSlice .Namespace ).Update (endpointSlice )
403
+ if err != nil {
404
+ return err
405
+ }
406
+ }
407
+ }
408
+
409
+ if service .Annotations == nil {
410
+ service .Annotations = make (map [string ]string )
411
+ }
412
+
413
+ service .Annotations [managedBySetupAnnotation ] = managedBySetupCompleteValue
414
+ _ , err = c .client .CoreV1 ().Services (service .Namespace ).Update (service )
415
+ return err
416
+ }
417
+
340
418
func (c * Controller ) addPod (obj interface {}) {
341
419
pod := obj .(* v1.Pod )
342
420
services , err := c .serviceSelectorCache .GetPodServiceMemberships (c .serviceLister , pod )
0 commit comments