1
16
17
18 package taint
19
20 import (
21 "fmt"
22 "strings"
23
24 corev1 "k8s.io/api/core/v1"
25 utilerrors "k8s.io/apimachinery/pkg/util/errors"
26 "k8s.io/apimachinery/pkg/util/sets"
27 "k8s.io/apimachinery/pkg/util/validation"
28 )
29
30
31 const (
32 MODIFIED = "modified"
33 TAINTED = "tainted"
34 UNTAINTED = "untainted"
35 )
36
37
38
39 func parseTaints(spec []string) ([]corev1.Taint, []corev1.Taint, error) {
40 var taints, taintsToRemove []corev1.Taint
41 uniqueTaints := map[corev1.TaintEffect]sets.String{}
42
43 for _, taintSpec := range spec {
44 if strings.HasSuffix(taintSpec, "-") {
45 taintToRemove, err := parseTaint(strings.TrimSuffix(taintSpec, "-"))
46 if err != nil {
47 return nil, nil, err
48 }
49 taintsToRemove = append(taintsToRemove, corev1.Taint{Key: taintToRemove.Key, Effect: taintToRemove.Effect})
50 } else {
51 newTaint, err := parseTaint(taintSpec)
52 if err != nil {
53 return nil, nil, err
54 }
55
56 if len(newTaint.Effect) == 0 {
57 return nil, nil, fmt.Errorf("invalid taint spec: %v", taintSpec)
58 }
59
60 if len(uniqueTaints[newTaint.Effect]) > 0 && uniqueTaints[newTaint.Effect].Has(newTaint.Key) {
61 return nil, nil, fmt.Errorf("duplicated taints with the same key and effect: %v", newTaint)
62 }
63
64 if len(uniqueTaints[newTaint.Effect]) == 0 {
65 uniqueTaints[newTaint.Effect] = sets.String{}
66 }
67 uniqueTaints[newTaint.Effect].Insert(newTaint.Key)
68
69 taints = append(taints, newTaint)
70 }
71 }
72 return taints, taintsToRemove, nil
73 }
74
75
76
77 func parseTaint(st string) (corev1.Taint, error) {
78 var taint corev1.Taint
79
80 var key string
81 var value string
82 var effect corev1.TaintEffect
83
84 parts := strings.Split(st, ":")
85 switch len(parts) {
86 case 1:
87 key = parts[0]
88 case 2:
89 effect = corev1.TaintEffect(parts[1])
90 if err := validateTaintEffect(effect); err != nil {
91 return taint, err
92 }
93
94 partsKV := strings.Split(parts[0], "=")
95 if len(partsKV) > 2 {
96 return taint, fmt.Errorf("invalid taint spec: %v", st)
97 }
98 key = partsKV[0]
99 if len(partsKV) == 2 {
100 value = partsKV[1]
101 if errs := validation.IsValidLabelValue(value); len(errs) > 0 {
102 return taint, fmt.Errorf("invalid taint spec: %v, %s", st, strings.Join(errs, "; "))
103 }
104 }
105 default:
106 return taint, fmt.Errorf("invalid taint spec: %v", st)
107 }
108
109 if errs := validation.IsQualifiedName(key); len(errs) > 0 {
110 return taint, fmt.Errorf("invalid taint spec: %v, %s", st, strings.Join(errs, "; "))
111 }
112
113 taint.Key = key
114 taint.Value = value
115 taint.Effect = effect
116
117 return taint, nil
118 }
119
120 func validateTaintEffect(effect corev1.TaintEffect) error {
121 if effect != corev1.TaintEffectNoSchedule && effect != corev1.TaintEffectPreferNoSchedule && effect != corev1.TaintEffectNoExecute {
122 return fmt.Errorf("invalid taint effect: %v, unsupported taint effect", effect)
123 }
124
125 return nil
126 }
127
128
129
130 func reorganizeTaints(node *corev1.Node, overwrite bool, taintsToAdd []corev1.Taint, taintsToRemove []corev1.Taint) (string, []corev1.Taint, error) {
131 newTaints := append([]corev1.Taint{}, taintsToAdd...)
132 oldTaints := node.Spec.Taints
133
134 added := addTaints(oldTaints, &newTaints)
135 allErrs, deleted := deleteTaints(taintsToRemove, &newTaints)
136 if (added && deleted) || overwrite {
137 return MODIFIED, newTaints, utilerrors.NewAggregate(allErrs)
138 } else if added {
139 return TAINTED, newTaints, utilerrors.NewAggregate(allErrs)
140 }
141 return UNTAINTED, newTaints, utilerrors.NewAggregate(allErrs)
142 }
143
144
145 func deleteTaints(taintsToRemove []corev1.Taint, newTaints *[]corev1.Taint) ([]error, bool) {
146 allErrs := []error{}
147 var removed bool
148 for _, taintToRemove := range taintsToRemove {
149 if len(taintToRemove.Effect) > 0 {
150 *newTaints, removed = deleteTaint(*newTaints, &taintToRemove)
151 } else {
152 *newTaints, removed = deleteTaintsByKey(*newTaints, taintToRemove.Key)
153 }
154 if !removed {
155 allErrs = append(allErrs, fmt.Errorf("taint %q not found", taintToRemove.ToString()))
156 }
157 }
158 return allErrs, removed
159 }
160
161
162
163 func addTaints(oldTaints []corev1.Taint, newTaints *[]corev1.Taint) bool {
164 for _, oldTaint := range oldTaints {
165 existsInNew := false
166 for _, taint := range *newTaints {
167 if taint.MatchTaint(&oldTaint) {
168 existsInNew = true
169 break
170 }
171 }
172 if !existsInNew {
173 *newTaints = append(*newTaints, oldTaint)
174 }
175 }
176 return len(oldTaints) != len(*newTaints)
177 }
178
179
180 func checkIfTaintsAlreadyExists(oldTaints []corev1.Taint, taints []corev1.Taint) string {
181 var existingTaintList = make([]string, 0)
182 for _, taint := range taints {
183 for _, oldTaint := range oldTaints {
184 if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect {
185 existingTaintList = append(existingTaintList, taint.Key)
186 }
187 }
188 }
189 return strings.Join(existingTaintList, ",")
190 }
191
192
193 func deleteTaintsByKey(taints []corev1.Taint, taintKey string) ([]corev1.Taint, bool) {
194 newTaints := []corev1.Taint{}
195 for i := range taints {
196 if taintKey == taints[i].Key {
197 continue
198 }
199 newTaints = append(newTaints, taints[i])
200 }
201 return newTaints, len(taints) != len(newTaints)
202 }
203
204
205 func deleteTaint(taints []corev1.Taint, taintToDelete *corev1.Taint) ([]corev1.Taint, bool) {
206 newTaints := []corev1.Taint{}
207 for i := range taints {
208 if taintToDelete.MatchTaint(&taints[i]) {
209 continue
210 }
211 newTaints = append(newTaints, taints[i])
212 }
213 return newTaints, len(taints) != len(newTaints)
214 }
215
View as plain text