func AnnotationsHaveEqualTaints(annotationA map[string]string, annotationB map[string]string) bool { taintsA, err := v1.GetTaintsFromNodeAnnotations(annotationA) if err != nil { return false } taintsB, err := v1.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 }
func addToBeDeletedTaint(node *apiv1.Node) (bool, error) { taints, err := apiv1.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { glog.Warningf("Error while getting Taints for node %v: %v", node.Name, err) return false, err } for _, taint := range taints { if taint.Key == ToBeDeletedTaint { glog.Infof("ToBeDeletedTaint already present on on node %v", taint, node.Name) return false, nil } } taints = append(taints, apiv1.Taint{ Key: ToBeDeletedTaint, Value: time.Now().String(), Effect: apiv1.TaintEffectNoSchedule, }) taintsJson, err := json.Marshal(taints) if err != nil { glog.Warningf("Error while adding taints on node %v: %v", node.Name, err) return false, err } if node.Annotations == nil { node.Annotations = make(map[string]string) } node.Annotations[apiv1.TaintsAnnotationKey] = string(taintsJson) return true, nil }
// 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 metav1.Object, overwrite bool, taintsToAdd []v1.Taint, taintsToRemove []v1.Taint) ([]v1.Taint, error) { newTaints := append([]v1.Taint{}, taintsToAdd...) var oldTaints []v1.Taint var err error annotations := accessor.GetAnnotations() if annotations != nil { if oldTaints, err = v1.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 PodToleratesNodeTaints(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.NodeInfo) (bool, []algorithm.PredicateFailureReason, error) { node := nodeInfo.Node() if node == nil { return false, nil, fmt.Errorf("node not found") } taints, err := v1.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { return false, nil, err } tolerations, err := v1.GetTolerationsFromPodAnnotations(pod.Annotations) if err != nil { return false, nil, err } if tolerationsToleratesTaints(tolerations, taints) { return true, nil, nil } return false, []algorithm.PredicateFailureReason{ErrTaintsTolerationsNotMatch}, nil }
// cleanToBeDeleted clean ToBeDeleted taints. func cleanToBeDeleted(nodes []*apiv1.Node, client kube_client.Interface, recorder kube_record.EventRecorder) error { for _, node := range nodes { taints, err := apiv1.GetTaintsFromNodeAnnotations(node.Annotations) if err != nil { glog.Warningf("Error while getting Taints for node %v: %v", node.Name, err) continue } newTaints := make([]apiv1.Taint, 0) for _, taint := range taints { if taint.Key == ToBeDeletedTaint { 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 } if node.Annotations == nil { node.Annotations = make(map[string]string) } node.Annotations[apiv1.TaintsAnnotationKey] = string(taintsJson) _, err = client.Core().Nodes().Update(node) if err != nil { glog.Warningf("Error while releasing taints on node %v: %v", node.Name, err) } else { glog.V(1).Infof("Successfully released toBeDeletedTaint on node %v", node.Name) recorder.Eventf(node, apiv1.EventTypeNormal, "ClusterAutoscalerCleanup", "marking the node as schedulable") } } } return nil }
// validateNoTaintOverwrites validates that when overwrite is false, to-be-updated taints don't exist in the node taint list (yet) func validateNoTaintOverwrites(accessor metav1.Object, taints []v1.Taint) error { annotations := accessor.GetAnnotations() if annotations == nil { return nil } allErrs := []error{} oldTaints, err := v1.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) }
// Sets the overall node information. func (n *NodeInfo) SetNode(node *v1.Node) error { n.node = node for rName, rQuant := range node.Status.Allocatable { switch rName { case v1.ResourceCPU: n.allocatableResource.MilliCPU = rQuant.MilliValue() case v1.ResourceMemory: n.allocatableResource.Memory = rQuant.Value() case v1.ResourceNvidiaGPU: n.allocatableResource.NvidiaGPU = rQuant.Value() case v1.ResourcePods: n.allowedPodNumber = int(rQuant.Value()) default: if v1.IsOpaqueIntResourceName(rName) { // Lazily allocate opaque resource map. if n.allocatableResource.OpaqueIntResources == nil { n.allocatableResource.OpaqueIntResources = map[v1.ResourceName]int64{} } n.allocatableResource.OpaqueIntResources[rName] = rQuant.Value() } } } n.taints, n.taintsErr = v1.GetTaintsFromNodeAnnotations(node.Annotations) for i := range node.Status.Conditions { cond := &node.Status.Conditions[i] switch cond.Type { case v1.NodeMemoryPressure: n.memoryPressureCondition = cond.Status case v1.NodeDiskPressure: n.diskPressureCondition = cond.Status default: // We ignore other conditions. } } n.generation++ return nil }