Skip to content

Commit 8873c7e

Browse files
authored
Merge pull request kubernetes#130564 from danwinship/label-endpoints
Add "endpoints.kubernetes.io/managed-by" label to Endpoints
2 parents 2b025e6 + c4ea350 commit 8873c7e

File tree

2 files changed

+66
-12
lines changed

2 files changed

+66
-12
lines changed

pkg/controller/endpoint/endpoints_controller.go

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"time"
2424

2525
v1 "k8s.io/api/core/v1"
26-
apiequality "k8s.io/apimachinery/pkg/api/equality"
2726
"k8s.io/apimachinery/pkg/api/errors"
2827
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2928
"k8s.io/apimachinery/pkg/conversion"
@@ -67,13 +66,19 @@ const (
6766
// endpoint resource and indicates that the number of endpoints have been truncated to
6867
// maxCapacity
6968
truncated = "truncated"
69+
70+
// labelManagedBy is a label for recognizing Endpoints managed by this controller.
71+
labelManagedBy = "endpoints.kubernetes.io/managed-by"
72+
73+
// controllerName is the name of this controller
74+
controllerName = "endpoint-controller"
7075
)
7176

7277
// NewEndpointController returns a new *Controller.
7378
func NewEndpointController(ctx context.Context, podInformer coreinformers.PodInformer, serviceInformer coreinformers.ServiceInformer,
7479
endpointsInformer coreinformers.EndpointsInformer, client clientset.Interface, endpointUpdatesBatchPeriod time.Duration) *Controller {
7580
broadcaster := record.NewBroadcaster(record.WithContext(ctx))
76-
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "endpoint-controller"})
81+
recorder := broadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: controllerName})
7782

7883
e := &Controller{
7984
client: client,
@@ -460,19 +465,11 @@ func (e *Controller) syncService(ctx context.Context, key string) error {
460465
createEndpoints := len(currentEndpoints.ResourceVersion) == 0
461466

462467
// Compare the sorted subsets and labels
463-
// Remove the HeadlessService label from the endpoints if it exists,
464-
// as this won't be set on the service itself
465-
// and will cause a false negative in this diff check.
466-
// But first check if it has that label to avoid expensive copies.
467-
compareLabels := currentEndpoints.Labels
468-
if _, ok := currentEndpoints.Labels[v1.IsHeadlessService]; ok {
469-
compareLabels = utillabels.CloneAndRemoveLabel(currentEndpoints.Labels, v1.IsHeadlessService)
470-
}
471468
// When comparing the subsets, we ignore the difference in ResourceVersion of Pod to avoid unnecessary Endpoints
472469
// updates caused by Pod updates that we don't care, e.g. annotation update.
473470
if !createEndpoints &&
474471
endpointSubsetsEqualIgnoreResourceVersion(currentEndpoints.Subsets, subsets) &&
475-
apiequality.Semantic.DeepEqual(compareLabels, service.Labels) &&
472+
labelsCorrectForEndpoints(currentEndpoints.Labels, service.Labels) &&
476473
capacityAnnotationSetCorrectly(currentEndpoints.Annotations, currentEndpoints.Subsets) {
477474
logger.V(5).Info("endpoints are equal, skipping update", "service", klog.KObj(service))
478475
return nil
@@ -506,6 +503,7 @@ func (e *Controller) syncService(ctx context.Context, key string) error {
506503
} else {
507504
newEndpoints.Labels = utillabels.CloneAndRemoveLabel(newEndpoints.Labels, v1.IsHeadlessService)
508505
}
506+
newEndpoints.Labels[labelManagedBy] = controllerName
509507

510508
logger.V(4).Info("Update endpoints", "service", klog.KObj(service), "readyEndpoints", totalReadyEps, "notreadyEndpoints", totalNotReadyEps)
511509
var updatedEndpoints *v1.Endpoints
@@ -718,3 +716,24 @@ var semanticIgnoreResourceVersion = conversion.EqualitiesOrDie(
718716
func endpointSubsetsEqualIgnoreResourceVersion(subsets1, subsets2 []v1.EndpointSubset) bool {
719717
return semanticIgnoreResourceVersion.DeepEqual(subsets1, subsets2)
720718
}
719+
720+
// labelsCorrectForEndpoints tests that epLabels is correctly derived from svcLabels
721+
// (ignoring the v1.IsHeadlessService label).
722+
func labelsCorrectForEndpoints(epLabels, svcLabels map[string]string) bool {
723+
if epLabels[labelManagedBy] != controllerName {
724+
return false
725+
}
726+
727+
// Every label in epLabels except v1.IsHeadlessService and labelManagedBy should
728+
// correspond to a label in svcLabels, and svcLabels should not have any other
729+
// labels that aren't in epLabels.
730+
skipped := 0
731+
for k, v := range epLabels {
732+
if k == v1.IsHeadlessService || k == labelManagedBy {
733+
skipped++
734+
} else if sv, exists := svcLabels[k]; !exists || sv != v {
735+
return false
736+
}
737+
}
738+
return len(svcLabels) == len(epLabels)-skipped
739+
}

pkg/controller/endpoint/endpoints_controller_test.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,9 @@ func TestSyncEndpointsExistingNilSubsets(t *testing.T) {
317317
Name: "foo",
318318
Namespace: ns,
319319
ResourceVersion: "1",
320+
Labels: map[string]string{
321+
labelManagedBy: controllerName,
322+
},
320323
},
321324
Subsets: nil,
322325
})
@@ -346,6 +349,9 @@ func TestSyncEndpointsExistingEmptySubsets(t *testing.T) {
346349
Name: "foo",
347350
Namespace: ns,
348351
ResourceVersion: "1",
352+
Labels: map[string]string{
353+
labelManagedBy: controllerName,
354+
},
349355
},
350356
Subsets: []v1.EndpointSubset{},
351357
})
@@ -376,6 +382,9 @@ func TestSyncEndpointsWithPodResourceVersionUpdateOnly(t *testing.T) {
376382
Name: "foo",
377383
Namespace: ns,
378384
ResourceVersion: "1",
385+
Labels: map[string]string{
386+
labelManagedBy: controllerName,
387+
},
379388
},
380389
Subsets: []v1.EndpointSubset{{
381390
Addresses: []v1.EndpointAddress{
@@ -501,6 +510,7 @@ func TestSyncEndpointsProtocolTCP(t *testing.T) {
501510
Namespace: ns,
502511
ResourceVersion: "1",
503512
Labels: map[string]string{
513+
labelManagedBy: controllerName,
504514
v1.IsHeadlessService: "",
505515
},
506516
},
@@ -524,6 +534,7 @@ func TestSyncEndpointsHeadlessServiceLabel(t *testing.T) {
524534
Namespace: ns,
525535
ResourceVersion: "1",
526536
Labels: map[string]string{
537+
labelManagedBy: controllerName,
527538
v1.IsHeadlessService: "",
528539
},
529540
},
@@ -652,6 +663,7 @@ func TestSyncEndpointsProtocolUDP(t *testing.T) {
652663
Namespace: ns,
653664
ResourceVersion: "1",
654665
Labels: map[string]string{
666+
labelManagedBy: controllerName,
655667
v1.IsHeadlessService: "",
656668
},
657669
},
@@ -701,6 +713,7 @@ func TestSyncEndpointsProtocolSCTP(t *testing.T) {
701713
Namespace: ns,
702714
ResourceVersion: "1",
703715
Labels: map[string]string{
716+
labelManagedBy: controllerName,
704717
v1.IsHeadlessService: "",
705718
},
706719
},
@@ -746,6 +759,7 @@ func TestSyncEndpointsItemsEmptySelectorSelectsAll(t *testing.T) {
746759
Namespace: ns,
747760
ResourceVersion: "1",
748761
Labels: map[string]string{
762+
labelManagedBy: controllerName,
749763
v1.IsHeadlessService: "",
750764
},
751765
},
@@ -792,6 +806,7 @@ func TestSyncEndpointsItemsEmptySelectorSelectsAllNotReady(t *testing.T) {
792806
Namespace: ns,
793807
ResourceVersion: "1",
794808
Labels: map[string]string{
809+
labelManagedBy: controllerName,
795810
v1.IsHeadlessService: "",
796811
},
797812
},
@@ -838,6 +853,7 @@ func TestSyncEndpointsItemsEmptySelectorSelectsAllMixed(t *testing.T) {
838853
Namespace: ns,
839854
ResourceVersion: "1",
840855
Labels: map[string]string{
856+
labelManagedBy: controllerName,
841857
v1.IsHeadlessService: "",
842858
},
843859
},
@@ -861,6 +877,9 @@ func TestSyncEndpointsItemsPreexisting(t *testing.T) {
861877
Name: "foo",
862878
Namespace: ns,
863879
ResourceVersion: "1",
880+
Labels: map[string]string{
881+
labelManagedBy: controllerName,
882+
},
864883
},
865884
Subsets: []v1.EndpointSubset{{
866885
Addresses: []v1.EndpointAddress{{IP: "6.7.8.9", NodeName: &emptyNodeName}},
@@ -887,6 +906,7 @@ func TestSyncEndpointsItemsPreexisting(t *testing.T) {
887906
Namespace: ns,
888907
ResourceVersion: "1",
889908
Labels: map[string]string{
909+
labelManagedBy: controllerName,
890910
v1.IsHeadlessService: "",
891911
},
892912
},
@@ -909,6 +929,9 @@ func TestSyncEndpointsItemsPreexistingIdentical(t *testing.T) {
909929
ResourceVersion: "1",
910930
Name: "foo",
911931
Namespace: ns,
932+
Labels: map[string]string{
933+
labelManagedBy: controllerName,
934+
},
912935
},
913936
Subsets: []v1.EndpointSubset{{
914937
Addresses: []v1.EndpointAddress{{IP: "1.2.3.4", NodeName: &emptyNodeName, TargetRef: &v1.ObjectReference{Kind: "Pod", Name: "pod0", Namespace: ns}}},
@@ -972,6 +995,7 @@ func TestSyncEndpointsItems(t *testing.T) {
972995
ResourceVersion: "",
973996
Name: "foo",
974997
Labels: map[string]string{
998+
labelManagedBy: controllerName,
975999
v1.IsHeadlessService: "",
9761000
},
9771001
},
@@ -1022,6 +1046,7 @@ func TestSyncEndpointsItemsWithLabels(t *testing.T) {
10221046
}}
10231047

10241048
serviceLabels[v1.IsHeadlessService] = ""
1049+
serviceLabels[labelManagedBy] = controllerName
10251050
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
10261051
ObjectMeta: metav1.ObjectMeta{
10271052
ResourceVersion: "",
@@ -1074,6 +1099,7 @@ func TestSyncEndpointsItemsPreexistingLabelsChange(t *testing.T) {
10741099
}
10751100

10761101
serviceLabels[v1.IsHeadlessService] = ""
1102+
serviceLabels[labelManagedBy] = controllerName
10771103
data := runtime.EncodeOrDie(clientscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), &v1.Endpoints{
10781104
ObjectMeta: metav1.ObjectMeta{
10791105
Name: "foo",
@@ -1183,6 +1209,7 @@ func TestSyncEndpointsHeadlessService(t *testing.T) {
11831209
Namespace: ns,
11841210
ResourceVersion: "1",
11851211
Labels: map[string]string{
1212+
labelManagedBy: controllerName,
11861213
"a": "b",
11871214
v1.IsHeadlessService: "",
11881215
},
@@ -1212,7 +1239,8 @@ func TestSyncEndpointsItemsExcludeNotReadyPodsWithRestartPolicyNeverAndPhaseFail
12121239
Namespace: ns,
12131240
ResourceVersion: "1",
12141241
Labels: map[string]string{
1215-
"foo": "bar",
1242+
labelManagedBy: controllerName,
1243+
"foo": "bar",
12161244
},
12171245
},
12181246
Subsets: []v1.EndpointSubset{},
@@ -1236,6 +1264,7 @@ func TestSyncEndpointsItemsExcludeNotReadyPodsWithRestartPolicyNeverAndPhaseFail
12361264
Namespace: ns,
12371265
ResourceVersion: "1",
12381266
Labels: map[string]string{
1267+
labelManagedBy: controllerName,
12391268
v1.IsHeadlessService: "",
12401269
},
12411270
},
@@ -1281,6 +1310,7 @@ func TestSyncEndpointsItemsExcludeNotReadyPodsWithRestartPolicyNeverAndPhaseSucc
12811310
Namespace: ns,
12821311
ResourceVersion: "1",
12831312
Labels: map[string]string{
1313+
labelManagedBy: controllerName,
12841314
v1.IsHeadlessService: "",
12851315
},
12861316
},
@@ -1327,6 +1357,7 @@ func TestSyncEndpointsItemsExcludeNotReadyPodsWithRestartPolicyOnFailureAndPhase
13271357
Namespace: ns,
13281358
ResourceVersion: "1",
13291359
Labels: map[string]string{
1360+
labelManagedBy: controllerName,
13301361
v1.IsHeadlessService: "",
13311362
},
13321363
},
@@ -1361,6 +1392,7 @@ func TestSyncEndpointsHeadlessWithoutPort(t *testing.T) {
13611392
ObjectMeta: metav1.ObjectMeta{
13621393
Name: "foo",
13631394
Labels: map[string]string{
1395+
labelManagedBy: controllerName,
13641396
v1.IsHeadlessService: "",
13651397
},
13661398
},
@@ -1580,6 +1612,7 @@ func TestLastTriggerChangeTimeAnnotation(t *testing.T) {
15801612
v1.EndpointsLastChangeTriggerTime: triggerTimeString,
15811613
},
15821614
Labels: map[string]string{
1615+
labelManagedBy: controllerName,
15831616
v1.IsHeadlessService: "",
15841617
},
15851618
},
@@ -1636,6 +1669,7 @@ func TestLastTriggerChangeTimeAnnotation_AnnotationOverridden(t *testing.T) {
16361669
v1.EndpointsLastChangeTriggerTime: triggerTimeString,
16371670
},
16381671
Labels: map[string]string{
1672+
labelManagedBy: controllerName,
16391673
v1.IsHeadlessService: "",
16401674
},
16411675
},
@@ -1690,6 +1724,7 @@ func TestLastTriggerChangeTimeAnnotation_AnnotationCleared(t *testing.T) {
16901724
Namespace: ns,
16911725
ResourceVersion: "1",
16921726
Labels: map[string]string{
1727+
labelManagedBy: controllerName,
16931728
v1.IsHeadlessService: "",
16941729
}, // Annotation not set anymore.
16951730
},

0 commit comments

Comments
 (0)