1
16
17
18 package taints
19
20 import (
21 "fmt"
22 "strings"
23
24 v1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/util/sets"
26 "k8s.io/apimachinery/pkg/util/validation"
27 "k8s.io/kubernetes/pkg/apis/core/helper"
28 )
29
30 const (
31 MODIFIED = "modified"
32 TAINTED = "tainted"
33 UNTAINTED = "untainted"
34 )
35
36
37
38 func parseTaint(st string) (v1.Taint, error) {
39 var taint v1.Taint
40
41 var key string
42 var value string
43 var effect v1.TaintEffect
44
45 parts := strings.Split(st, ":")
46 switch len(parts) {
47 case 1:
48 key = parts[0]
49 case 2:
50 effect = v1.TaintEffect(parts[1])
51 if err := validateTaintEffect(effect); err != nil {
52 return taint, err
53 }
54
55 partsKV := strings.Split(parts[0], "=")
56 if len(partsKV) > 2 {
57 return taint, fmt.Errorf("invalid taint spec: %v", st)
58 }
59 key = partsKV[0]
60 if len(partsKV) == 2 {
61 value = partsKV[1]
62 if errs := validation.IsValidLabelValue(value); len(errs) > 0 {
63 return taint, fmt.Errorf("invalid taint spec: %v, %s", st, strings.Join(errs, "; "))
64 }
65 }
66 default:
67 return taint, fmt.Errorf("invalid taint spec: %v", st)
68 }
69
70 if errs := validation.IsQualifiedName(key); len(errs) > 0 {
71 return taint, fmt.Errorf("invalid taint spec: %v, %s", st, strings.Join(errs, "; "))
72 }
73
74 taint.Key = key
75 taint.Value = value
76 taint.Effect = effect
77
78 return taint, nil
79 }
80
81 func validateTaintEffect(effect v1.TaintEffect) error {
82 if effect != v1.TaintEffectNoSchedule && effect != v1.TaintEffectPreferNoSchedule && effect != v1.TaintEffectNoExecute {
83 return fmt.Errorf("invalid taint effect: %v, unsupported taint effect", effect)
84 }
85
86 return nil
87 }
88
89
90
91 func ParseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {
92 var taints, taintsToRemove []v1.Taint
93 uniqueTaints := map[v1.TaintEffect]sets.String{}
94
95 for _, taintSpec := range spec {
96 if strings.HasSuffix(taintSpec, "-") {
97 taintToRemove, err := parseTaint(strings.TrimSuffix(taintSpec, "-"))
98 if err != nil {
99 return nil, nil, err
100 }
101 taintsToRemove = append(taintsToRemove, v1.Taint{Key: taintToRemove.Key, Effect: taintToRemove.Effect})
102 } else {
103 newTaint, err := parseTaint(taintSpec)
104 if err != nil {
105 return nil, nil, err
106 }
107
108 if len(newTaint.Effect) == 0 {
109 return nil, nil, fmt.Errorf("invalid taint spec: %v", taintSpec)
110 }
111
112 if len(uniqueTaints[newTaint.Effect]) > 0 && uniqueTaints[newTaint.Effect].Has(newTaint.Key) {
113 return nil, nil, fmt.Errorf("duplicated taints with the same key and effect: %v", newTaint)
114 }
115
116 if len(uniqueTaints[newTaint.Effect]) == 0 {
117 uniqueTaints[newTaint.Effect] = sets.String{}
118 }
119 uniqueTaints[newTaint.Effect].Insert(newTaint.Key)
120
121 taints = append(taints, newTaint)
122 }
123 }
124 return taints, taintsToRemove, nil
125 }
126
127
128 func CheckIfTaintsAlreadyExists(oldTaints []v1.Taint, taints []v1.Taint) string {
129 var existingTaintList = make([]string, 0)
130 for _, taint := range taints {
131 for _, oldTaint := range oldTaints {
132 if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect {
133 existingTaintList = append(existingTaintList, taint.Key)
134 }
135 }
136 }
137 return strings.Join(existingTaintList, ",")
138 }
139
140
141 func DeleteTaintsByKey(taints []v1.Taint, taintKey string) ([]v1.Taint, bool) {
142 newTaints := []v1.Taint{}
143 deleted := false
144 for i := range taints {
145 if taintKey == taints[i].Key {
146 deleted = true
147 continue
148 }
149 newTaints = append(newTaints, taints[i])
150 }
151 return newTaints, deleted
152 }
153
154
155 func DeleteTaint(taints []v1.Taint, taintToDelete *v1.Taint) ([]v1.Taint, bool) {
156 newTaints := []v1.Taint{}
157 deleted := false
158 for i := range taints {
159 if taintToDelete.MatchTaint(&taints[i]) {
160 deleted = true
161 continue
162 }
163 newTaints = append(newTaints, taints[i])
164 }
165 return newTaints, deleted
166 }
167
168
169
170 func RemoveTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
171 newNode := node.DeepCopy()
172 nodeTaints := newNode.Spec.Taints
173 if len(nodeTaints) == 0 {
174 return newNode, false, nil
175 }
176
177 if !TaintExists(nodeTaints, taint) {
178 return newNode, false, nil
179 }
180
181 newTaints, _ := DeleteTaint(nodeTaints, taint)
182 newNode.Spec.Taints = newTaints
183 return newNode, true, nil
184 }
185
186
187
188 func AddOrUpdateTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
189 newNode := node.DeepCopy()
190 nodeTaints := newNode.Spec.Taints
191
192 var newTaints []v1.Taint
193 updated := false
194 for i := range nodeTaints {
195 if taint.MatchTaint(&nodeTaints[i]) {
196 if helper.Semantic.DeepEqual(*taint, nodeTaints[i]) {
197 return newNode, false, nil
198 }
199 newTaints = append(newTaints, *taint)
200 updated = true
201 continue
202 }
203
204 newTaints = append(newTaints, nodeTaints[i])
205 }
206
207 if !updated {
208 newTaints = append(newTaints, *taint)
209 }
210
211 newNode.Spec.Taints = newTaints
212 return newNode, true, nil
213 }
214
215
216 func TaintExists(taints []v1.Taint, taintToFind *v1.Taint) bool {
217 for _, taint := range taints {
218 if taint.MatchTaint(taintToFind) {
219 return true
220 }
221 }
222 return false
223 }
224
225
226 func TaintKeyExists(taints []v1.Taint, taintKeyToMatch string) bool {
227 for _, taint := range taints {
228 if taint.Key == taintKeyToMatch {
229 return true
230 }
231 }
232 return false
233 }
234
235
236
237
238
239
240 func TaintSetDiff(taintsNew, taintsOld []v1.Taint) (taintsToAdd []*v1.Taint, taintsToRemove []*v1.Taint) {
241 for _, taint := range taintsNew {
242 if !TaintExists(taintsOld, &taint) {
243 t := taint
244 taintsToAdd = append(taintsToAdd, &t)
245 }
246 }
247
248 for _, taint := range taintsOld {
249 if !TaintExists(taintsNew, &taint) {
250 t := taint
251 taintsToRemove = append(taintsToRemove, &t)
252 }
253 }
254
255 return
256 }
257
258
259 func TaintSetFilter(taints []v1.Taint, fn func(*v1.Taint) bool) []v1.Taint {
260 res := []v1.Taint{}
261
262 for _, taint := range taints {
263 if fn(&taint) {
264 res = append(res, taint)
265 }
266 }
267
268 return res
269 }
270
271
272
273 func CheckTaintValidation(taint v1.Taint) error {
274 if errs := validation.IsQualifiedName(taint.Key); len(errs) > 0 {
275 return fmt.Errorf("invalid taint key: %s", strings.Join(errs, "; "))
276 }
277 if taint.Value != "" {
278 if errs := validation.IsValidLabelValue(taint.Value); len(errs) > 0 {
279 return fmt.Errorf("invalid taint value: %s", strings.Join(errs, "; "))
280 }
281 }
282 if taint.Effect != "" {
283 if err := validateTaintEffect(taint.Effect); err != nil {
284 return err
285 }
286 }
287
288 return nil
289 }
290
View as plain text