package helper import ( "time" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" ) // TaintExists checks if the given taint exists in list of taints. Returns true if exists false otherwise. func TaintExists(taints []corev1.Taint, taintToFind *corev1.Taint) bool { for _, taint := range taints { if taint.MatchTaint(taintToFind) { return true } } return false } // TolerationExists checks if the given toleration exists in list of tolerations. Returns true if exists false otherwise. func TolerationExists(tolerations []corev1.Toleration, tolerationToFind *corev1.Toleration) bool { for _, toleration := range tolerations { if toleration.MatchToleration(tolerationToFind) { return true } } return false } // SetCurrentClusterTaints sets current cluster taints which need to be updated. func SetCurrentClusterTaints(taintsToAdd, taintsToRemove []*corev1.Taint, cluster *clusterv1alpha1.Cluster) []corev1.Taint { taints := cluster.Spec.Taints var clusterTaintsToAdd, clusterTaintsToRemove []corev1.Taint // Find which taints need to be added. for _, taintToAdd := range taintsToAdd { if !TaintExists(taints, taintToAdd) { clusterTaintsToAdd = append(clusterTaintsToAdd, *taintToAdd) } } // Find which taints need to be removed. for _, taintToRemove := range taintsToRemove { if TaintExists(taints, taintToRemove) { clusterTaintsToRemove = append(clusterTaintsToRemove, *taintToRemove) } } // If no taints need to be added and removed, just return. if len(clusterTaintsToAdd) == 0 && len(clusterTaintsToRemove) == 0 { return taints } taints = make([]corev1.Taint, 0, len(taints)+len(clusterTaintsToAdd)-len(clusterTaintsToRemove)) // Remove taints which need to be removed. for i := range cluster.Spec.Taints { if !TaintExists(clusterTaintsToRemove, &cluster.Spec.Taints[i]) { taints = append(taints, cluster.Spec.Taints[i]) } } // Add taints. for _, taintToAdd := range clusterTaintsToAdd { now := metav1.Now() taintToAdd.TimeAdded = &now taints = append(taints, taintToAdd) } return taints } // AddTolerations add some tolerations if not existed. func AddTolerations(placement *policyv1alpha1.Placement, tolerationsToAdd ...*corev1.Toleration) { for _, tolerationToAdd := range tolerationsToAdd { if !TolerationExists(placement.ClusterTolerations, tolerationToAdd) { placement.ClusterTolerations = append(placement.ClusterTolerations, *tolerationToAdd) } } } // HasNoExecuteTaints check if NoExecute taints exist. func HasNoExecuteTaints(taints []corev1.Taint) bool { for i := range taints { if taints[i].Effect == corev1.TaintEffectNoExecute { return true } } return false } // GetNoExecuteTaints will get all NoExecute taints. func GetNoExecuteTaints(taints []corev1.Taint) []corev1.Taint { var result []corev1.Taint for i := range taints { if taints[i].Effect == corev1.TaintEffectNoExecute { result = append(result, taints[i]) } } return result } // GetMinTolerationTime returns minimal toleration time from the given slice, or -1 if it's infinite. func GetMinTolerationTime(noExecuteTaints []corev1.Taint, usedTolerations []corev1.Toleration) time.Duration { if len(noExecuteTaints) == 0 { return -1 } if len(usedTolerations) == 0 { return 0 } // Get all trigger time. var triggerTimes []time.Time for i := range usedTolerations { if usedTolerations[i].TolerationSeconds == nil { continue } tolerationSeconds := *(usedTolerations[i].TolerationSeconds) for j := range noExecuteTaints { // should not happen if noExecuteTaints[j].TimeAdded == nil { continue } timeAdded := *noExecuteTaints[j].TimeAdded if usedTolerations[i].ToleratesTaint(&noExecuteTaints[j]) { triggerTimes = append(triggerTimes, timeAdded.Add(time.Duration(tolerationSeconds)*time.Second)) } } } // If triggerTimes is empty, it means all taints would be tolerated forever. if len(triggerTimes) == 0 { return -1 } // Find the latest trigger time. t := triggerTimes[0] for i := 1; i < len(triggerTimes); i++ { if triggerTimes[i].Before(t) { t = triggerTimes[i] } } // If trigger time is up, don't tolerate. if t.Before(time.Now()) { return 0 } return time.Until(t) } // GetMatchingTolerations returns true and list of Tolerations matching all Taints if all are tolerated, or false otherwise. func GetMatchingTolerations(taints []corev1.Taint, tolerations []corev1.Toleration) (bool, []corev1.Toleration) { if len(taints) == 0 { return true, []corev1.Toleration{} } if len(tolerations) == 0 && len(taints) > 0 { return false, []corev1.Toleration{} } var result []corev1.Toleration for i := range taints { tolerated := false for j := range tolerations { if tolerations[j].ToleratesTaint(&taints[i]) { result = append(result, tolerations[j]) tolerated = true break } } if !tolerated { return false, []corev1.Toleration{} } } return true, result } // NewNotReadyToleration returns a default not ready toleration. func NewNotReadyToleration(tolerationSeconds int64) *corev1.Toleration { return &corev1.Toleration{ Key: clusterv1alpha1.TaintClusterNotReady, Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoExecute, TolerationSeconds: &tolerationSeconds, } } // NewUnreachableToleration returns a default unreachable toleration. func NewUnreachableToleration(tolerationSeconds int64) *corev1.Toleration { return &corev1.Toleration{ Key: clusterv1alpha1.TaintClusterUnreachable, Operator: corev1.TolerationOpExists, Effect: corev1.TaintEffectNoExecute, TolerationSeconds: &tolerationSeconds, } }