func AnnotationsHaveEqualTaints(annotationA map[string]string, annotationB map[string]string) bool { taintsA, err := api.GetTaintsFromNodeAnnotations(annotationA) if err != nil { return false } taintsB, err := api.GetTaintsFromNodeAnnotations(annotationB) if err != nil { return false } if len(taintsA) != len(taintsB) { return false } for _, taintA := range taintsA { found := false for _, taintB := range taintsB { if reflect.DeepEqual(taintA, taintB) { found = true break } } if !found { return false } } return true }
// reorganizeTaints returns the updated set of taints, taking into account old taints that were not updated, // old taints that were updated, old taints that were deleted, and new taints. func reorganizeTaints(accessor meta.Object, overwrite bool, taintsToAdd []api.Taint, taintsToRemove []api.Taint) ([]api.Taint, error) { newTaints := append([]api.Taint{}, taintsToAdd...) var oldTaints []api.Taint var err error annotations := accessor.GetAnnotations() if annotations != nil { if oldTaints, err = api.GetTaintsFromNodeAnnotations(annotations); err != nil { return nil, err } } // add taints that already existing but not updated to newTaints for _, oldTaint := range oldTaints { existsInNew := false for _, taint := range newTaints { if taint.MatchTaint(oldTaint) { existsInNew = true break } } if !existsInNew { newTaints = append(newTaints, oldTaint) } } allErrs := []error{} for _, taintToRemove := range taintsToRemove { newTaints, err = deleteTaint(newTaints, taintToRemove) if err != nil { allErrs = append(allErrs, err) } } return newTaints, utilerrors.NewAggregate(allErrs) }
func addTaint(client *kube_client.Client, node *kube_api.Node, value string) error { taints, err := kube_api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return err } taint := kube_api.Taint{ Key: criticalAddonsOnlyTaintKey, Value: value, Effect: kube_api.TaintEffectNoSchedule, } taints = append(taints, taint) taintsJson, err := json.Marshal(taints) if err != nil { return err } if node.Annotations == nil { node.Annotations = make(map[string]string) } node.Annotations[kube_api.TaintsAnnotationKey] = string(taintsJson) _, err = client.Nodes().Update(node) if err != nil { return err } return nil }
// ComputeTaintTolerationPriority prepares the priority list for all the nodes based on the number of intolerable taints on the node func ComputeTaintTolerationPriorityMap(pod *api.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (schedulerapi.HostPriority, error) { node := nodeInfo.Node() if node == nil { return schedulerapi.HostPriority{}, fmt.Errorf("node not found") } var tolerationList []api.Toleration if priorityMeta, ok := meta.(*priorityMetadata); ok { tolerationList = priorityMeta.podTolerations } else { var err error tolerationList, err = getTolerationListFromPod(pod) if err != nil { return schedulerapi.HostPriority{}, err } } taints, err := api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return schedulerapi.HostPriority{}, err } return schedulerapi.HostPriority{ Host: node.Name, Score: countIntolerableTaintsPreferNoSchedule(taints, tolerationList), }, nil }
// ComputeTaintTolerationPriority prepares the priority list for all the nodes based on the number of intolerable taints on the node func ComputeTaintTolerationPriority(pod *api.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodeLister algorithm.NodeLister) (schedulerapi.HostPriorityList, error) { nodes, err := nodeLister.List() if err != nil { return nil, err } // the max value of counts var maxCount float64 // counts hold the count of intolerable taints of a pod for a given node counts := make(map[string]float64, len(nodes)) tolerations, err := api.GetTolerationsFromPodAnnotations(pod.Annotations) if err != nil { return nil, err } // Fetch a list of all toleration with effect PreferNoSchedule tolerationList := getAllTolerationPreferNoSchedule(tolerations) // calculate the intolerable taints for all the nodes for _, node := range nodes { taints, err := api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return nil, err } count := countIntolerableTaintsPreferNoSchedule(taints, tolerationList) if count > 0 { // 0 is default value, so avoid unnecessary map operations. counts[node.Name] = count if count > maxCount { maxCount = count } } } // The maximum priority value to give to a node // Priority values range from 0 - maxPriority const maxPriority = float64(10) result := make(schedulerapi.HostPriorityList, 0, len(nodes)) for _, node := range nodes { fScore := maxPriority if maxCount > 0 { fScore = (1.0 - counts[node.Name]/maxCount) * 10 } if glog.V(10) { // We explicitly don't do glog.V(10).Infof() to avoid computing all the parameters if this is // not logged. There is visible performance gain from it. glog.Infof("%v -> %v: Taint Toleration Priority, Score: (%d)", pod.Name, node.Name, int(fScore)) } result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: int(fScore)}) } return result, nil }
func checkTaints(node *kube_api.Node) error { taints, err := kube_api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return fmt.Errorf("error while getting taints: %v", err) } for _, taint := range taints { if taint.Key == criticalAddonsOnlyTaintKey { return fmt.Errorf("CriticalAddonsOnly taint with value: %v", taint.Value) } } return nil }
// ComputeTaintTolerationPriority prepares the priority list for all the nodes based on the number of intolerable taints on the node func (s *TaintToleration) ComputeTaintTolerationPriority(pod *api.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodeLister algorithm.NodeLister) (schedulerapi.HostPriorityList, error) { // counts hold the count of intolerable taints of a pod for a given node counts := make(map[string]int) // the max value of counts var maxCount int nodes, err := nodeLister.List() if err != nil { return nil, err } tolerations, err := api.GetTolerationsFromPodAnnotations(pod.Annotations) if err != nil { return nil, err } // Fetch a list of all toleration with effect PreferNoSchedule tolerationList := getAllTolerationPreferNoSchedule(tolerations) // calculate the intolerable taints for all the nodes for i := range nodes.Items { node := &nodes.Items[i] taints, err := api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return nil, err } count := countIntolerableTaintsPreferNoSchedule(taints, tolerationList) counts[node.Name] = count if count > maxCount { maxCount = count } } // The maximum priority value to give to a node // Priority values range from 0 - maxPriority const maxPriority = 10 result := make(schedulerapi.HostPriorityList, 0, len(nodes.Items)) for _, node := range nodes.Items { fScore := float64(maxPriority) if maxCount > 0 { fScore = (1.0 - float64(counts[node.Name])/float64(maxCount)) * 10 } glog.V(10).Infof("%v -> %v: Taint Toleration Priority, Score: (%d)", pod.Name, node.Name, int(fScore)) result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: int(fScore)}) } return result, nil }
func (t *TolerationMatch) PodToleratesNodeTaints(pod *api.Pod, nodeInfo *schedulercache.NodeInfo) (bool, error) { node := nodeInfo.Node() taints, err := api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return false, err } tolerations, err := api.GetTolerationsFromPodAnnotations(pod.Annotations) if err != nil { return false, err } if tolerationsToleratesTaints(tolerations, taints) { return true, nil } return false, ErrTaintsTolerationsNotMatch }
func PodToleratesNodeTaints(pod *api.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (bool, error) { node := nodeInfo.Node() if node == nil { return false, fmt.Errorf("node not found") } taints, err := api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return false, err } tolerations, err := api.GetTolerationsFromPodAnnotations(pod.Annotations) if err != nil { return false, err } if tolerationsToleratesTaints(tolerations, taints) { return true, nil } return false, ErrTaintsTolerationsNotMatch }
func releaseAllTaints(client *kube_client.Client, nodeLister *kube_utils.ReadyNodeLister, podsBeingProcessed *podSet) { nodes, err := nodeLister.List() if err != nil { glog.Warningf("Cannot release taints - error while listing nodes: %v", err) return } for _, node := range nodes { taints, err := kube_api.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { glog.Warningf("Error while getting Taints for node %v: %v", node.Name, err) continue } newTaints := make([]kube_api.Taint, 0) for _, taint := range taints { if taint.Key == criticalAddonsOnlyTaintKey && !podsBeingProcessed.HasId(taint.Value) { glog.Infof("Releasing taint %+v on node %v", taint, node.Name) } else { newTaints = append(newTaints, taint) } } if len(newTaints) != len(taints) { taintsJson, err := json.Marshal(newTaints) if err != nil { glog.Warningf("Error while releasing taints on node %v: %v", node.Name, err) continue } node.Annotations[kube_api.TaintsAnnotationKey] = string(taintsJson) _, err = client.Nodes().Update(node) if err != nil { glog.Warningf("Error while releasing taints on node %v: %v", node.Name, err) } else { glog.Infof("Successfully released all taints on node %v", node.Name) } } } }
// validateNoTaintOverwrites validates that when overwrite is false, to-be-updated taints don't exist in the node taint list (yet) func validateNoTaintOverwrites(accessor meta.Object, taints []api.Taint) error { annotations := accessor.GetAnnotations() if annotations == nil { return nil } allErrs := []error{} oldTaints, err := api.GetTaintsFromNodeAnnotations(annotations) if err != nil { allErrs = append(allErrs, err) return utilerrors.NewAggregate(allErrs) } for _, taint := range taints { for _, oldTaint := range oldTaints { if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect { allErrs = append(allErrs, fmt.Errorf("Node '%s' already has a taint with key (%s) and effect (%v), and --overwrite is false", accessor.GetName(), taint.Key, taint.Effect)) break } } } return utilerrors.NewAggregate(allErrs) }