Skip to content

Commit 30e90de

Browse files
committed
add drift & diffed placements to binding status from work status
1 parent 23065f8 commit 30e90de

File tree

2 files changed

+247
-0
lines changed

2 files changed

+247
-0
lines changed

pkg/controllers/workgenerator/controller.go

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ import (
5555
var (
5656
// maxFailedResourcePlacementLimit indicates the max number of failed resource placements to include in the status.
5757
maxFailedResourcePlacementLimit = 100
58+
// maxDriftedResourcePlacementLimit indicates the max number of drifted resource placements to include in the status.
59+
maxDriftedResourcePlacementLimit = 100
60+
// maxDiffedResourcePlacementLimit indicates the max number of diffed resource placements to include in the status.
61+
maxDiffedResourcePlacementLimit = 100
5862

5963
errResourceSnapshotNotFound = fmt.Errorf("the master resource snapshot is not found")
6064
)
@@ -775,6 +779,46 @@ func setBindingStatus(works map[string]*fleetv1beta1.Work, resourceBinding *flee
775779
klog.V(2).InfoS("Populated failed manifests", "clusterResourceBinding", bindingRef, "numberOfFailedPlacements", len(failedResourcePlacements))
776780
}
777781
}
782+
783+
resourceBinding.Status.DriftedPlacements = nil
784+
// collect and set the drifted resource placements to the binding
785+
driftedResourcePlacements := make([]fleetv1beta1.DriftedResourcePlacement, 0, maxDriftedResourcePlacementLimit) // preallocate the memory
786+
for _, w := range works {
787+
if w.DeletionTimestamp != nil {
788+
klog.V(2).InfoS("Ignoring the deleting work", "clusterResourceBinding", bindingRef, "work", klog.KObj(w))
789+
continue // ignore the deleting work
790+
}
791+
driftedManifests := extractDriftedResourcePlacementsFromWork(w)
792+
driftedResourcePlacements = append(driftedResourcePlacements, driftedManifests...)
793+
}
794+
// cut the list to keep only the max limit
795+
if len(driftedResourcePlacements) > maxDriftedResourcePlacementLimit {
796+
driftedResourcePlacements = driftedResourcePlacements[0:maxDriftedResourcePlacementLimit]
797+
}
798+
resourceBinding.Status.DriftedPlacements = driftedResourcePlacements
799+
if len(driftedResourcePlacements) > 0 {
800+
klog.V(2).InfoS("Populated drifted manifests", "clusterResourceBinding", bindingRef, "numberOfDriftedPlacements", len(driftedResourcePlacements))
801+
}
802+
803+
resourceBinding.Status.DiffedPlacements = nil
804+
// collect and set the diffed resource placements to the binding
805+
diffedResourcePlacements := make([]fleetv1beta1.DiffedResourcePlacement, 0, maxDiffedResourcePlacementLimit) // preallocate the memory
806+
for _, w := range works {
807+
if w.DeletionTimestamp != nil {
808+
klog.V(2).InfoS("Ignoring the deleting work", "clusterResourceBinding", bindingRef, "work", klog.KObj(w))
809+
continue // ignore the deleting work
810+
}
811+
diffedManifests := extractDiffedResourcePlacementsFromWork(w)
812+
diffedResourcePlacements = append(diffedResourcePlacements, diffedManifests...)
813+
}
814+
// cut the list to keep only the max limit
815+
if len(diffedResourcePlacements) > maxDiffedResourcePlacementLimit {
816+
diffedResourcePlacements = diffedResourcePlacements[0:maxDiffedResourcePlacementLimit]
817+
}
818+
resourceBinding.Status.DiffedPlacements = diffedResourcePlacements
819+
if len(diffedResourcePlacements) > 0 {
820+
klog.V(2).InfoS("Populated diffed manifests", "clusterResourceBinding", bindingRef, "numberOfDiffedPlacements", len(diffedResourcePlacements))
821+
}
778822
}
779823

780824
func buildAllWorkAppliedCondition(works map[string]*fleetv1beta1.Work, binding *fleetv1beta1.ClusterResourceBinding) metav1.Condition {
@@ -955,6 +999,92 @@ func extractFailedResourcePlacementsFromWork(work *fleetv1beta1.Work) []fleetv1b
955999
return res
9561000
}
9571001

1002+
// extractDriftedResourcePlacementsFromWork extracts the drifted placements from work
1003+
func extractDriftedResourcePlacementsFromWork(work *fleetv1beta1.Work) []fleetv1beta1.DriftedResourcePlacement {
1004+
// check if the work is generated by an enveloped object
1005+
envelopeType, isEnveloped := work.GetLabels()[fleetv1beta1.EnvelopeTypeLabel]
1006+
var envelopObjName, envelopObjNamespace string
1007+
if isEnveloped {
1008+
// If the work generated by an enveloped object, it must contain those labels.
1009+
envelopObjName = work.GetLabels()[fleetv1beta1.EnvelopeNameLabel]
1010+
envelopObjNamespace = work.GetLabels()[fleetv1beta1.EnvelopeNamespaceLabel]
1011+
}
1012+
res := make([]fleetv1beta1.DriftedResourcePlacement, 0, len(work.Status.ManifestConditions))
1013+
for _, manifestCondition := range work.Status.ManifestConditions {
1014+
driftedManifest := fleetv1beta1.DriftedResourcePlacement{
1015+
ResourceIdentifier: fleetv1beta1.ResourceIdentifier{
1016+
Group: manifestCondition.Identifier.Group,
1017+
Version: manifestCondition.Identifier.Version,
1018+
Kind: manifestCondition.Identifier.Kind,
1019+
Name: manifestCondition.Identifier.Name,
1020+
Namespace: manifestCondition.Identifier.Namespace,
1021+
},
1022+
ObservationTime: manifestCondition.DriftDetails.ObservationTime,
1023+
TargetClusterObservedGeneration: manifestCondition.DriftDetails.ObservedInMemberClusterGeneration,
1024+
FirstDriftedObservedTime: manifestCondition.DriftDetails.FirstDriftedObservedTime,
1025+
ObservedDrifts: manifestCondition.DriftDetails.ObservedDrifts,
1026+
}
1027+
1028+
if isEnveloped {
1029+
klog.V(2).InfoS("Found a drifted enveloped manifest",
1030+
"manifestName", manifestCondition.Identifier.Name,
1031+
"group", manifestCondition.Identifier.Group,
1032+
"version", manifestCondition.Identifier.Version, "kind", manifestCondition.Identifier.Kind,
1033+
"envelopeType", envelopeType, "envelopObjName", envelopObjName, "envelopObjNamespace", envelopObjNamespace)
1034+
} else {
1035+
klog.V(2).InfoS("Found a drifted manifest",
1036+
"manifestName", manifestCondition.Identifier.Name, "group", manifestCondition.Identifier.Group,
1037+
"version", manifestCondition.Identifier.Version, "kind", manifestCondition.Identifier.Kind)
1038+
}
1039+
res = append(res, driftedManifest)
1040+
continue //jump to the next manifest
1041+
}
1042+
return res
1043+
}
1044+
1045+
// extractDiffedResourcePlacementsFromWork extracts the diffed placements from work
1046+
func extractDiffedResourcePlacementsFromWork(work *fleetv1beta1.Work) []fleetv1beta1.DiffedResourcePlacement {
1047+
// check if the work is generated by an enveloped object
1048+
envelopeType, isEnveloped := work.GetLabels()[fleetv1beta1.EnvelopeTypeLabel]
1049+
var envelopObjName, envelopObjNamespace string
1050+
if isEnveloped {
1051+
// If the work generated by an enveloped object, it must contain those labels.
1052+
envelopObjName = work.GetLabels()[fleetv1beta1.EnvelopeNameLabel]
1053+
envelopObjNamespace = work.GetLabels()[fleetv1beta1.EnvelopeNamespaceLabel]
1054+
}
1055+
res := make([]fleetv1beta1.DiffedResourcePlacement, 0, len(work.Status.ManifestConditions))
1056+
for _, manifestCondition := range work.Status.ManifestConditions {
1057+
diffedManifest := fleetv1beta1.DiffedResourcePlacement{
1058+
ResourceIdentifier: fleetv1beta1.ResourceIdentifier{
1059+
Group: manifestCondition.Identifier.Group,
1060+
Version: manifestCondition.Identifier.Version,
1061+
Kind: manifestCondition.Identifier.Kind,
1062+
Name: manifestCondition.Identifier.Name,
1063+
Namespace: manifestCondition.Identifier.Namespace,
1064+
},
1065+
ObservationTime: manifestCondition.DiffDetails.ObservationTime,
1066+
TargetClusterObservedGeneration: manifestCondition.DiffDetails.ObservedInMemberClusterGeneration,
1067+
FirstDiffedObservedTime: manifestCondition.DiffDetails.FirstDiffedObservedTime,
1068+
ObservedDiffs: manifestCondition.DiffDetails.ObservedDiffs,
1069+
}
1070+
1071+
if isEnveloped {
1072+
klog.V(2).InfoS("Found a diffed enveloped manifest",
1073+
"manifestName", manifestCondition.Identifier.Name,
1074+
"group", manifestCondition.Identifier.Group,
1075+
"version", manifestCondition.Identifier.Version, "kind", manifestCondition.Identifier.Kind,
1076+
"envelopeType", envelopeType, "envelopObjName", envelopObjName, "envelopObjNamespace", envelopObjNamespace)
1077+
} else {
1078+
klog.V(2).InfoS("Found a diffed manifest",
1079+
"manifestName", manifestCondition.Identifier.Name, "group", manifestCondition.Identifier.Group,
1080+
"version", manifestCondition.Identifier.Version, "kind", manifestCondition.Identifier.Kind)
1081+
}
1082+
res = append(res, diffedManifest)
1083+
continue //jump to the next manifest
1084+
}
1085+
return res
1086+
}
1087+
9581088
// SetupWithManager sets up the controller with the Manager.
9591089
// It watches binding events and also update/delete events for work.
9601090
func (r *Reconciler) SetupWithManager(mgr controllerruntime.Manager) error {
@@ -1045,6 +1175,21 @@ func (r *Reconciler) SetupWithManager(mgr controllerruntime.Manager) error {
10451175
}
10461176
}
10471177
}
1178+
// we need to compare the drift placement
1179+
oldDriftedPlacements := extractDriftedResourcePlacementsFromWork(oldWork)
1180+
newDriftedPlacements := extractDriftedResourcePlacementsFromWork(newWork)
1181+
if utils.IsDriftedResourcePlacementsEqual(oldDriftedPlacements, newDriftedPlacements) {
1182+
klog.V(2).InfoS("The drifted placement list didn't change, no need to reconcile", "oldWork", klog.KObj(oldWork), "newWork", klog.KObj(newWork))
1183+
return
1184+
}
1185+
1186+
// we need to compare the diffed placement
1187+
oldDiffedPlacements := extractDiffedResourcePlacementsFromWork(oldWork)
1188+
newDiffedPlacements := extractDiffedResourcePlacementsFromWork(newWork)
1189+
if utils.IsDiffedResourcePlacementsEqual(oldDiffedPlacements, newDiffedPlacements) {
1190+
klog.V(2).InfoS("The diffed placement list didn't change, no need to reconcile", "oldWork", klog.KObj(oldWork), "newWork", klog.KObj(newWork))
1191+
return
1192+
}
10481193
// We need to update the binding status in this case
10491194
klog.V(2).InfoS("Received a work update event that we need to handle", "work", klog.KObj(newWork), "parentBindingName", parentBindingName)
10501195
queue.Add(reconcile.Request{NamespacedName: types.NamespacedName{

pkg/utils/common.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,108 @@ func IsFailedResourcePlacementsEqual(oldFailedResourcePlacements, newFailedResou
555555
return true
556556
}
557557

558+
// LessFuncDriftedResourcePlacements is a less function for sorting drifted resource placements
559+
var LessFuncDriftedResourcePlacements = func(a, b placementv1beta1.DriftedResourcePlacement) bool {
560+
var aStr, bStr string
561+
if a.Envelope != nil {
562+
aStr = fmt.Sprintf(ResourceIdentifierWithEnvelopeIdentifierStringFormat, a.Group, a.Version, a.Kind, a.Namespace, a.Name, a.Envelope.Type, a.Envelope.Namespace, a.Envelope.Name)
563+
} else {
564+
aStr = fmt.Sprintf(ResourceIdentifierStringFormat, a.Group, a.Version, a.Kind, a.Namespace, a.Name)
565+
}
566+
if b.Envelope != nil {
567+
bStr = fmt.Sprintf(ResourceIdentifierWithEnvelopeIdentifierStringFormat, b.Group, b.Version, b.Kind, b.Namespace, b.Name, b.Envelope.Type, b.Envelope.Namespace, b.Envelope.Name)
568+
} else {
569+
bStr = fmt.Sprintf(ResourceIdentifierStringFormat, b.Group, b.Version, b.Kind, b.Namespace, b.Name)
570+
571+
}
572+
return aStr < bStr
573+
}
574+
575+
func IsDriftedResourcePlacementsEqual(oldDriftedResourcePlacements, newDriftedResourcePlacements []placementv1beta1.DriftedResourcePlacement) bool {
576+
if len(oldDriftedResourcePlacements) != len(newDriftedResourcePlacements) {
577+
return false
578+
}
579+
sort.Slice(oldDriftedResourcePlacements, func(i, j int) bool {
580+
return LessFuncDriftedResourcePlacements(oldDriftedResourcePlacements[i], oldDriftedResourcePlacements[j])
581+
})
582+
sort.Slice(newDriftedResourcePlacements, func(i, j int) bool {
583+
return LessFuncDriftedResourcePlacements(newDriftedResourcePlacements[i], newDriftedResourcePlacements[j])
584+
})
585+
for i := range oldDriftedResourcePlacements {
586+
oldDriftedResourcePlacement := oldDriftedResourcePlacements[i]
587+
newDriftedResourcePlacement := newDriftedResourcePlacements[i]
588+
if !equality.Semantic.DeepEqual(oldDriftedResourcePlacement.ResourceIdentifier, newDriftedResourcePlacement.ResourceIdentifier) {
589+
return false
590+
}
591+
if !equality.Semantic.DeepEqual(oldDriftedResourcePlacement.ObservationTime, newDriftedResourcePlacement.ObservationTime) {
592+
return false
593+
}
594+
if oldDriftedResourcePlacement.TargetClusterObservedGeneration != newDriftedResourcePlacement.TargetClusterObservedGeneration {
595+
return false
596+
}
597+
if !equality.Semantic.DeepEqual(oldDriftedResourcePlacement.FirstDriftedObservedTime, newDriftedResourcePlacement.FirstDriftedObservedTime) {
598+
return false
599+
}
600+
for j := range oldDriftedResourcePlacement.ObservedDrifts {
601+
if !equality.Semantic.DeepEqual(oldDriftedResourcePlacement.ObservedDrifts[j], newDriftedResourcePlacement.ObservedDrifts[j]) {
602+
return false
603+
}
604+
}
605+
}
606+
return true
607+
}
608+
609+
// LessFuncDiffedResourcePlacements is a less function for sorting diffed resource placements
610+
var LessFuncDiffedResourcePlacements = func(a, b placementv1beta1.DiffedResourcePlacement) bool {
611+
var aStr, bStr string
612+
if a.Envelope != nil {
613+
aStr = fmt.Sprintf(ResourceIdentifierWithEnvelopeIdentifierStringFormat, a.Group, a.Version, a.Kind, a.Namespace, a.Name, a.Envelope.Type, a.Envelope.Namespace, a.Envelope.Name)
614+
} else {
615+
aStr = fmt.Sprintf(ResourceIdentifierStringFormat, a.Group, a.Version, a.Kind, a.Namespace, a.Name)
616+
}
617+
if b.Envelope != nil {
618+
bStr = fmt.Sprintf(ResourceIdentifierWithEnvelopeIdentifierStringFormat, b.Group, b.Version, b.Kind, b.Namespace, b.Name, b.Envelope.Type, b.Envelope.Namespace, b.Envelope.Name)
619+
} else {
620+
bStr = fmt.Sprintf(ResourceIdentifierStringFormat, b.Group, b.Version, b.Kind, b.Namespace, b.Name)
621+
622+
}
623+
return aStr < bStr
624+
}
625+
626+
func IsDiffedResourcePlacementsEqual(oldDiffedResourcePlacements, newDiffedResourcePlacements []placementv1beta1.DiffedResourcePlacement) bool {
627+
if len(oldDiffedResourcePlacements) != len(newDiffedResourcePlacements) {
628+
return false
629+
}
630+
sort.Slice(oldDiffedResourcePlacements, func(i, j int) bool {
631+
return LessFuncDiffedResourcePlacements(oldDiffedResourcePlacements[i], oldDiffedResourcePlacements[j])
632+
})
633+
sort.Slice(newDiffedResourcePlacements, func(i, j int) bool {
634+
return LessFuncDiffedResourcePlacements(newDiffedResourcePlacements[i], newDiffedResourcePlacements[j])
635+
})
636+
for i := range oldDiffedResourcePlacements {
637+
oldDiffedResourcePlacement := oldDiffedResourcePlacements[i]
638+
newDiffedResourcePlacement := newDiffedResourcePlacements[i]
639+
if !equality.Semantic.DeepEqual(oldDiffedResourcePlacement.ResourceIdentifier, newDiffedResourcePlacement.ResourceIdentifier) {
640+
return false
641+
}
642+
if !equality.Semantic.DeepEqual(oldDiffedResourcePlacement.ObservationTime, newDiffedResourcePlacement.ObservationTime) {
643+
return false
644+
}
645+
if oldDiffedResourcePlacement.TargetClusterObservedGeneration != newDiffedResourcePlacement.TargetClusterObservedGeneration {
646+
return false
647+
}
648+
if !equality.Semantic.DeepEqual(oldDiffedResourcePlacement.FirstDiffedObservedTime, newDiffedResourcePlacement.FirstDiffedObservedTime) {
649+
return false
650+
}
651+
for j := range oldDiffedResourcePlacement.ObservedDiffs {
652+
if !equality.Semantic.DeepEqual(oldDiffedResourcePlacement.ObservedDiffs[j], newDiffedResourcePlacement.ObservedDiffs[j]) {
653+
return false
654+
}
655+
}
656+
}
657+
return true
658+
}
659+
558660
// IsFleetAnnotationPresent returns true if a key with fleet prefix is present in the annotations map.
559661
func IsFleetAnnotationPresent(annotations map[string]string) bool {
560662
for k := range annotations {

0 commit comments

Comments
 (0)