func()

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)
}