diff options
Diffstat (limited to 'vendor/k8s.io/kubernetes/pkg/util/taints/taints.go')
-rw-r--r-- | vendor/k8s.io/kubernetes/pkg/util/taints/taints.go | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/vendor/k8s.io/kubernetes/pkg/util/taints/taints.go b/vendor/k8s.io/kubernetes/pkg/util/taints/taints.go new file mode 100644 index 000000000..76e4bb866 --- /dev/null +++ b/vendor/k8s.io/kubernetes/pkg/util/taints/taints.go @@ -0,0 +1,342 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// package taints implements utilites for working with taints +package taints + +import ( + "fmt" + "strings" + + "k8s.io/api/core/v1" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/apimachinery/pkg/util/validation" + api "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/apis/core/helper" +) + +const ( + MODIFIED = "modified" + TAINTED = "tainted" + UNTAINTED = "untainted" +) + +// parseTaint parses a taint from a string. Taint must be of the format '<key>=<value>:<effect>'. +func parseTaint(st string) (v1.Taint, error) { + var taint v1.Taint + parts := strings.Split(st, "=") + if len(parts) != 2 || len(parts[1]) == 0 || len(validation.IsQualifiedName(parts[0])) > 0 { + return taint, fmt.Errorf("invalid taint spec: %v", st) + } + + parts2 := strings.Split(parts[1], ":") + + errs := validation.IsValidLabelValue(parts2[0]) + if len(parts2) != 2 || len(errs) != 0 { + return taint, fmt.Errorf("invalid taint spec: %v, %s", st, strings.Join(errs, "; ")) + } + + effect := v1.TaintEffect(parts2[1]) + if err := validateTaintEffect(effect); err != nil { + return taint, err + } + + taint.Key = parts[0] + taint.Value = parts2[0] + taint.Effect = effect + + return taint, nil +} + +func validateTaintEffect(effect v1.TaintEffect) error { + if effect != v1.TaintEffectNoSchedule && effect != v1.TaintEffectPreferNoSchedule && effect != v1.TaintEffectNoExecute { + return fmt.Errorf("invalid taint effect: %v, unsupported taint effect", effect) + } + + return nil +} + +// NewTaintsVar wraps []api.Taint in a struct that implements flag.Value to allow taints to be +// bound to command line flags. +func NewTaintsVar(ptr *[]api.Taint) taintsVar { + return taintsVar{ + ptr: ptr, + } +} + +type taintsVar struct { + ptr *[]api.Taint +} + +func (t taintsVar) Set(s string) error { + if len(s) == 0 { + *t.ptr = nil + return nil + } + sts := strings.Split(s, ",") + var taints []api.Taint + for _, st := range sts { + taint, err := parseTaint(st) + if err != nil { + return err + } + taints = append(taints, api.Taint{Key: taint.Key, Value: taint.Value, Effect: api.TaintEffect(taint.Effect)}) + } + *t.ptr = taints + return nil +} + +func (t taintsVar) String() string { + if len(*t.ptr) == 0 { + return "" + } + var taints []string + for _, taint := range *t.ptr { + taints = append(taints, fmt.Sprintf("%s=%s:%s", taint.Key, taint.Value, taint.Effect)) + } + return strings.Join(taints, ",") +} + +func (t taintsVar) Type() string { + return "[]api.Taint" +} + +// ParseTaints takes a spec which is an array and creates slices for new taints to be added, taints to be deleted. +func ParseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) { + var taints, taintsToRemove []v1.Taint + uniqueTaints := map[v1.TaintEffect]sets.String{} + + for _, taintSpec := range spec { + if strings.Index(taintSpec, "=") != -1 && strings.Index(taintSpec, ":") != -1 { + newTaint, err := parseTaint(taintSpec) + if err != nil { + return nil, nil, err + } + // validate if taint is unique by <key, effect> + if len(uniqueTaints[newTaint.Effect]) > 0 && uniqueTaints[newTaint.Effect].Has(newTaint.Key) { + return nil, nil, fmt.Errorf("duplicated taints with the same key and effect: %v", newTaint) + } + // add taint to existingTaints for uniqueness check + if len(uniqueTaints[newTaint.Effect]) == 0 { + uniqueTaints[newTaint.Effect] = sets.String{} + } + uniqueTaints[newTaint.Effect].Insert(newTaint.Key) + + taints = append(taints, newTaint) + } else if strings.HasSuffix(taintSpec, "-") { + taintKey := taintSpec[:len(taintSpec)-1] + var effect v1.TaintEffect + if strings.Index(taintKey, ":") != -1 { + parts := strings.Split(taintKey, ":") + taintKey = parts[0] + effect = v1.TaintEffect(parts[1]) + } + + // If effect is specified, need to validate it. + if len(effect) > 0 { + err := validateTaintEffect(effect) + if err != nil { + return nil, nil, err + } + } + taintsToRemove = append(taintsToRemove, v1.Taint{Key: taintKey, Effect: effect}) + } else { + return nil, nil, fmt.Errorf("unknown taint spec: %v", taintSpec) + } + } + return taints, taintsToRemove, 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(node *v1.Node, overwrite bool, taintsToAdd []v1.Taint, taintsToRemove []v1.Taint) (string, []v1.Taint, error) { + newTaints := append([]v1.Taint{}, taintsToAdd...) + oldTaints := node.Spec.Taints + // add taints that already existing but not updated to newTaints + added := addTaints(oldTaints, &newTaints) + allErrs, deleted := deleteTaints(taintsToRemove, &newTaints) + if (added && deleted) || overwrite { + return MODIFIED, newTaints, utilerrors.NewAggregate(allErrs) + } else if added { + return TAINTED, newTaints, utilerrors.NewAggregate(allErrs) + } + return UNTAINTED, newTaints, utilerrors.NewAggregate(allErrs) +} + +// deleteTaints deletes the given taints from the node's taintlist. +func deleteTaints(taintsToRemove []v1.Taint, newTaints *[]v1.Taint) ([]error, bool) { + allErrs := []error{} + var removed bool + for _, taintToRemove := range taintsToRemove { + removed = false + if len(taintToRemove.Effect) > 0 { + *newTaints, removed = DeleteTaint(*newTaints, &taintToRemove) + } else { + *newTaints, removed = DeleteTaintsByKey(*newTaints, taintToRemove.Key) + } + if !removed { + allErrs = append(allErrs, fmt.Errorf("taint %q not found", taintToRemove.ToString())) + } + } + return allErrs, removed +} + +// addTaints adds the newTaints list to existing ones and updates the newTaints List. +// TODO: This needs a rewrite to take only the new values instead of appended newTaints list to be consistent. +func addTaints(oldTaints []v1.Taint, newTaints *[]v1.Taint) bool { + for _, oldTaint := range oldTaints { + existsInNew := false + for _, taint := range *newTaints { + if taint.MatchTaint(&oldTaint) { + existsInNew = true + break + } + } + if !existsInNew { + *newTaints = append(*newTaints, oldTaint) + } + } + return len(oldTaints) != len(*newTaints) +} + +// CheckIfTaintsAlreadyExists checks if the node already has taints that we want to add and returns a string with taint keys. +func CheckIfTaintsAlreadyExists(oldTaints []v1.Taint, taints []v1.Taint) string { + var existingTaintList = make([]string, 0) + for _, taint := range taints { + for _, oldTaint := range oldTaints { + if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect { + existingTaintList = append(existingTaintList, taint.Key) + } + } + } + return strings.Join(existingTaintList, ",") +} + +// DeleteTaintsByKey removes all the taints that have the same key to given taintKey +func DeleteTaintsByKey(taints []v1.Taint, taintKey string) ([]v1.Taint, bool) { + newTaints := []v1.Taint{} + deleted := false + for i := range taints { + if taintKey == taints[i].Key { + deleted = true + continue + } + newTaints = append(newTaints, taints[i]) + } + return newTaints, deleted +} + +// DeleteTaint removes all the the taints that have the same key and effect to given taintToDelete. +func DeleteTaint(taints []v1.Taint, taintToDelete *v1.Taint) ([]v1.Taint, bool) { + newTaints := []v1.Taint{} + deleted := false + for i := range taints { + if taintToDelete.MatchTaint(&taints[i]) { + deleted = true + continue + } + newTaints = append(newTaints, taints[i]) + } + return newTaints, deleted +} + +// RemoveTaint tries to remove a taint from annotations list. Returns a new copy of updated Node and true if something was updated +// false otherwise. +func RemoveTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) { + newNode := node.DeepCopy() + nodeTaints := newNode.Spec.Taints + if len(nodeTaints) == 0 { + return newNode, false, nil + } + + if !TaintExists(nodeTaints, taint) { + return newNode, false, nil + } + + newTaints, _ := DeleteTaint(nodeTaints, taint) + newNode.Spec.Taints = newTaints + return newNode, true, nil +} + +// AddOrUpdateTaint tries to add a taint to annotations list. Returns a new copy of updated Node and true if something was updated +// false otherwise. +func AddOrUpdateTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) { + newNode := node.DeepCopy() + nodeTaints := newNode.Spec.Taints + + var newTaints []v1.Taint + updated := false + for i := range nodeTaints { + if taint.MatchTaint(&nodeTaints[i]) { + if helper.Semantic.DeepEqual(*taint, nodeTaints[i]) { + return newNode, false, nil + } + newTaints = append(newTaints, *taint) + updated = true + continue + } + + newTaints = append(newTaints, nodeTaints[i]) + } + + if !updated { + newTaints = append(newTaints, *taint) + } + + newNode.Spec.Taints = newTaints + return newNode, true, nil +} + +// TaintExists checks if the given taint exists in list of taints. Returns true if exists false otherwise. +func TaintExists(taints []v1.Taint, taintToFind *v1.Taint) bool { + for _, taint := range taints { + if taint.MatchTaint(taintToFind) { + return true + } + } + return false +} + +func TaintSetDiff(t1, t2 []v1.Taint) (taintsToAdd []*v1.Taint, taintsToRemove []*v1.Taint) { + for _, taint := range t1 { + if !TaintExists(t2, &taint) { + t := taint + taintsToAdd = append(taintsToAdd, &t) + } + } + + for _, taint := range t2 { + if !TaintExists(t1, &taint) { + t := taint + taintsToRemove = append(taintsToRemove, &t) + } + } + + return +} + +func TaintSetFilter(taints []v1.Taint, fn func(*v1.Taint) bool) []v1.Taint { + res := []v1.Taint{} + + for _, taint := range taints { + if fn(&taint) { + res = append(res, taint) + } + } + + return res +} |