github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/plugin/taint_plugin.go (about) 1 // Copyright © 2021 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plugin 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/alibaba/sealer/utils" 22 23 v1 "k8s.io/api/core/v1" 24 25 "github.com/alibaba/sealer/logger" 26 "github.com/alibaba/sealer/pkg/client/k8s" 27 ) 28 29 var TaintEffectValues = []v1.TaintEffect{v1.TaintEffectNoSchedule, v1.TaintEffectNoExecute, v1.TaintEffectPreferNoSchedule} 30 31 type TaintList map[string]*taintList //map[ip]taint 32 33 type Taint struct { 34 IPList []string 35 TaintList 36 } 37 38 type taintList struct { 39 DelTaintList []v1.Taint 40 AddTaintList []v1.Taint 41 } 42 43 func NewTaintPlugin() Interface { 44 return &Taint{TaintList: map[string]*taintList{}} 45 } 46 47 func init() { 48 Register(TaintPlugin, NewTaintPlugin()) 49 } 50 51 func newTaintStruct(key, value, effect string) v1.Taint { 52 return v1.Taint{Key: key, Value: value, Effect: v1.TaintEffect(effect)} 53 } 54 55 //Run taint_plugin file: 56 //apiVersion: sealer.aliyun.com/v1alpha1 57 //kind: Plugin 58 //metadata: 59 // name: taint 60 //spec: 61 // type: Taint 62 // action: PreGuest 63 // data: 192.168.56.3 key1=value1:NoSchedule ## add taint 64 // #data: 192.168.56.3 key1=value1:NoSchedule- ## del taint 65 66 func (l *Taint) Run(context Context, phase Phase) (err error) { 67 if phase != PhasePreGuest || context.Plugin.Spec.Type != TaintPlugin { 68 return nil 69 } 70 71 err = l.formatData(context.Plugin.Spec.Data) 72 if err != nil { 73 return fmt.Errorf("failed to format data from %s: %v", context.Plugin.Spec.Data, err) 74 } 75 76 k8sClient, err := k8s.Newk8sClient() 77 if err != nil { 78 return err 79 } 80 81 nodeList, err := k8sClient.ListNodes() 82 if err != nil { 83 return err 84 } 85 for _, n := range nodeList.Items { 86 node := n 87 for _, v := range node.Status.Addresses { 88 if !utils.InList(v.Address, l.IPList) { 89 continue 90 } 91 if utils.NotIn(v.Address, context.Host) { 92 continue 93 } 94 updateTaints := l.UpdateTaints(node.Spec.Taints, v.Address) 95 if updateTaints != nil { 96 node.Spec.Taints = updateTaints 97 _, err := k8sClient.UpdateNode(node) 98 if err != nil { 99 return err 100 } 101 logger.Info("successfully updated node %s taints to %v.", v.Address, updateTaints) 102 } 103 break 104 } 105 } 106 107 return nil 108 } 109 110 //key1=value1:NoSchedule;key1=value1:NoSchedule-;key1:NoSchedule;key1:NoSchedule-;key1=:NoSchedule-;key1=value1:NoSchedule 111 func (l *Taint) formatData(data string) error { 112 items := strings.Split(data, "\n") 113 for _, v := range items { 114 v = strings.TrimSpace(v) 115 if strings.HasPrefix(v, "#") || v == "" { 116 continue 117 } 118 temps := strings.Split(v, " ") 119 if len(temps) != 2 { 120 return fmt.Errorf("faild to split taint argument: %s", v) 121 } 122 ips := temps[0] 123 err := utils.AssemblyIPList(&ips) 124 if err != nil { 125 return err 126 } 127 l.IPList = append(l.IPList, ips) 128 //kubectl taint nodes xxx key- : remove all key related taints 129 if strings.HasSuffix(temps[1], DelSymbol) && !strings.Contains(temps[1], ColonSymbol) && !strings.Contains(temps[1], EqualSymbol) { 130 l.TaintList[ips].DelTaintList = append(l.TaintList[ips].DelTaintList, newTaintStruct(strings.TrimSuffix(temps[1], DelSymbol), "", "")) 131 continue 132 } 133 taintArgs := strings.Split(temps[1], ColonSymbol) 134 if len(taintArgs) != 2 { 135 return fmt.Errorf("error: invalid taint data: %s", v) 136 } 137 kv, effect := taintArgs[0], taintArgs[1] 138 effect = strings.TrimSuffix(effect, DelSymbol) 139 if NotInEffect(v1.TaintEffect(effect), TaintEffectValues) { 140 return fmt.Errorf("taint effect %s need in %v", v, TaintEffectValues) 141 } 142 kvList := strings.Split(kv, EqualSymbol) 143 key, value := kvList[0], "" 144 if len(kvList) > 2 || key == "" { 145 return fmt.Errorf("error: invalid taint data: %s", temps[1]) 146 } 147 if len(kvList) == 2 { 148 value = kvList[1] 149 } 150 taint := newTaintStruct(key, value, effect) 151 if _, ok := l.TaintList[ips]; !ok { 152 l.TaintList[ips] = &taintList{} 153 } 154 if strings.HasSuffix(temps[1], DelSymbol) { 155 l.TaintList[ips].DelTaintList = append(l.TaintList[ips].DelTaintList, taint) 156 continue 157 } 158 l.TaintList[ips].AddTaintList = append(l.TaintList[ips].AddTaintList, taint) 159 } 160 return nil 161 } 162 163 // UpdateTaints return nil mean's needn't update taint 164 func (l *Taint) UpdateTaints(taints []v1.Taint, ip string) []v1.Taint { 165 needDel := false 166 for k, v := range taints { 167 l.removePresenceTaint(v, ip) 168 if l.isDelTaint(v, ip) { 169 needDel = true 170 taints = append(taints[:k], taints[k+1:]...) 171 } 172 } 173 if len(l.TaintList[ip].AddTaintList) == 0 && !needDel { 174 return nil 175 } 176 return append(taints, l.TaintList[ip].AddTaintList...) 177 } 178 179 //Remove existing taint 180 func (l *Taint) removePresenceTaint(taint v1.Taint, ip string) { 181 for k, v := range l.TaintList[ip].AddTaintList { 182 if v.Key == taint.Key && v.Value == taint.Value && v.Effect == taint.Effect { 183 logger.Info("taint %s already exist", l.TaintList[ip].AddTaintList[k].String()) 184 l.TaintList[ip].AddTaintList = append(l.TaintList[ip].AddTaintList[:k], l.TaintList[ip].AddTaintList[k+1:]...) 185 } 186 } 187 } 188 189 func (l *Taint) isDelTaint(taint v1.Taint, ip string) bool { 190 for _, v := range l.TaintList[ip].AddTaintList { 191 if v.Key == taint.Key && (v.Effect == taint.Effect || v.Effect == "") { 192 return true 193 } 194 } 195 return false 196 } 197 198 func NotInEffect(effect v1.TaintEffect, effects []v1.TaintEffect) bool { 199 for _, e := range effects { 200 if e == effect { 201 return false 202 } 203 } 204 return true 205 }