in pkg/scheduler/watchers/membercluster/watcher.go [173:286]
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
customPredicate := predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
// Normally it is safe to ignore newly created cluster objects, as they are not yet
// ready for scheduling; when the clusters do become ready, the controller will catch
// an update event.
//
// Furthermore, when the controller restarts, the scheduler is set to reconcile all
// CRPs anyway, which will account for any missing updates on the cluster side
// during the downtime; in other words, notifications from this controller is not
// necessary.
klog.V(3).InfoS("Ignoring create events for member cluster objects", "eventObject", klog.KObj(e.Object))
return false
},
DeleteFunc: func(e event.DeleteEvent) bool {
// Ignore deletion events; the removal of a cluster is first signaled by adding a deleteTimeStamp,
// which is an update event
klog.V(3).InfoS("Ignoring delete events for member cluster objects", "eventObject", klog.KObj(e.Object))
return false
},
UpdateFunc: func(e event.UpdateEvent) bool {
// Check if the update event is valid.
if e.ObjectOld == nil || e.ObjectNew == nil {
err := controller.NewUnexpectedBehaviorError(fmt.Errorf("update event is invalid"))
klog.ErrorS(err, "Failed to process update event")
return false
}
oldCluster, oldOk := e.ObjectOld.(*clusterv1beta1.MemberCluster)
newCluster, newOk := e.ObjectNew.(*clusterv1beta1.MemberCluster)
if !oldOk || !newOk {
err := controller.NewUnexpectedBehaviorError(fmt.Errorf("failed to cast runtime objects in update event to member cluster objects"))
klog.ErrorS(err, "Failed to process update event")
return false
}
clusterKObj := klog.KObj(newCluster)
// The cluster is being deleted.
if oldCluster.GetDeletionTimestamp().IsZero() && !newCluster.GetDeletionTimestamp().IsZero() {
klog.V(2).InfoS("A member cluster is leaving the fleet", "memberCluster", clusterKObj)
return true
}
// Capture label changes.
//
// Note that the controller runs only when label changes happen on joined clusters.
if !reflect.DeepEqual(oldCluster.Labels, newCluster.Labels) {
klog.V(2).InfoS("A member cluster label change has been detected", "memberCluster", clusterKObj)
return true
}
// Capture taint update/delete changes.
if isTaintsUpdatedOrDeleted(oldCluster.Spec.Taints, newCluster.Spec.Taints) {
klog.V(2).InfoS("A member cluster taint update/delete has been detected", "memberCluster", clusterKObj)
return true
}
// Capture non-resource property changes.
//
// Observation time refreshes is not considered as a change.
oldProperties := oldCluster.Status.Properties
newProperties := newCluster.Status.Properties
if len(oldProperties) != len(newProperties) {
return true
}
for oldK, oldV := range oldProperties {
newV, ok := newProperties[oldK]
if !ok || oldV.Value != newV.Value {
return true
}
}
// Capture resource usage changes.
oldCapacity := oldCluster.Status.ResourceUsage.Capacity
newCapacity := newCluster.Status.ResourceUsage.Capacity
if !equality.Semantic.DeepEqual(oldCapacity, newCapacity) {
return true
}
oldAllocatable := oldCluster.Status.ResourceUsage.Allocatable
newAllocatable := newCluster.Status.ResourceUsage.Allocatable
if !equality.Semantic.DeepEqual(oldAllocatable, newAllocatable) {
return true
}
oldAvailable := oldCluster.Status.ResourceUsage.Available
newAvailable := newCluster.Status.ResourceUsage.Available
if !equality.Semantic.DeepEqual(oldAvailable, newAvailable) {
return true
}
// Check the resource placement eligibility for the old and new cluster object.
oldEligible, _ := r.ClusterEligibilityChecker.IsEligible(oldCluster)
newEligible, _ := r.ClusterEligibilityChecker.IsEligible(newCluster)
if !oldEligible && newEligible {
// The cluster becomes eligible for resource placement, i.e., match for case 1b).
//
// The reverse, i.e., eligible -> ineligible, is ignored (case 2b)).
klog.V(2).InfoS("A member cluster may become eligible for resource placement", "memberCluster", clusterKObj)
return true
}
// All the other changes are ignored.
klog.V(3).InfoS("Ignoring update events that are irrelevant to the scheduler", "memberCluster", clusterKObj)
return false
},
}
return ctrl.NewControllerManagedBy(mgr).Named("membercluster-scheduler-watcher").
For(&clusterv1beta1.MemberCluster{}).
WithEventFilter(customPredicate).
Complete(r)
}