k8s污点(taints)操作源码
目录开启kubectl命令进行taint操作对taints操作的检查运行执行具体污点操作返回更新后的污点集添加污点删除污点附:能否调度DaemonSet到节点的代码开启kubectl命令进行taint操作func NewCmdTaint(f cmdutil.Factory, streams genericclioptions.IOStreams) *...
·
目录
开启kubectl命令进行taint操作
func NewCmdTaint(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
options := &TaintOptions{
PrintFlags: genericclioptions.NewPrintFlags("tainted").WithTypeSetter(scheme.Scheme),
IOStreams: streams,
}
validArgs := []string{"node"}
cmd := &cobra.Command{
Use: "taint NODE NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N",
DisableFlagsInUseLine: true,
Short: i18n.T("Update the taints on one or more nodes"),
Long: fmt.Sprintf(taintLong, validation.DNS1123SubdomainMaxLength, validation.LabelValueMaxLength),
Example: taintExample,
Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(f, cmd, args); err != nil {
cmdutil.CheckErr(err)
}
if err := options.Validate(); err != nil {
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
}
if err := options.RunTaint(); err != nil {
cmdutil.CheckErr(err)
}
},
ValidArgs: validArgs,
}
options.PrintFlags.AddFlags(cmd)
cmdutil.AddValidateFlags(cmd)
cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow taints to be overwritten, otherwise reject taint updates that overwrite existing taints.")
cmd.Flags().BoolVar(&options.all, "all", options.all, "Select all nodes in the cluster")
return cmd
}
命令以IOStreams的形式传入。
对taints操作的检查
// Validate checks to the TaintOptions to see if there is sufficient information run the command.
func (o TaintOptions) Validate() error {
resourceType := strings.ToLower(o.resources[0])
validResources, isValidResource := []string{"node", "nodes"}, false
for _, validResource := range validResources {
if resourceType == validResource {
isValidResource = true
break
}
}
if !isValidResource {
return fmt.Errorf("invalid resource type %s, only %q are supported", o.resources[0], validResources)
}
// check the format of taint args and checks removed taints aren't in the new taints list
var conflictTaints []string
for _, taintAdd := range o.taintsToAdd {
for _, taintRemove := range o.taintsToRemove {
if taintAdd.Key != taintRemove.Key {
continue
}
if len(taintRemove.Effect) == 0 || taintAdd.Effect == taintRemove.Effect {
conflictTaint := fmt.Sprintf("{\"%s\":\"%s\"}", taintRemove.Key, taintRemove.Effect)
conflictTaints = append(conflictTaints, conflictTaint)
}
}
}
if len(conflictTaints) > 0 {
return fmt.Errorf("can not both modify and remove the following taint(s) in the same command: %s", strings.Join(conflictTaints, ", "))
}
return o.validateFlags()
}
运行
// RunTaint does the work
func (o TaintOptions) RunTaint() error {
r := o.builder.Do()
if err := r.Err(); err != nil {
return err
}
return r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
obj := info.Object
name, namespace := info.Name, info.Namespace
oldData, err := json.Marshal(obj)
if err != nil {
return err
}
operation, err := o.updateTaints(obj)
if err != nil {
return err
}
newData, err := json.Marshal(obj)
if err != nil {
return err
}
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
createdPatch := err == nil
if err != nil {
glog.V(2).Infof("couldn't compute patch: %v", err)
}
mapping := info.ResourceMapping()
client, err := o.ClientForMapping(mapping)
if err != nil {
return err
}
helper := resource.NewHelper(client, mapping)
var outputObj runtime.Object
if createdPatch {
outputObj, err = helper.Patch(namespace, name, types.StrategicMergePatchType, patchBytes, nil)
} else {
outputObj, err = helper.Replace(namespace, name, false, obj)
}
if err != nil {
return err
}
outputObj = cmdutil.AsDefaultVersionedOrOriginal(outputObj, mapping)
printer, err := o.ToPrinter(operation)
if err != nil {
return err
}
return printer.PrintObj(outputObj, o.Out)
})
}
执行具体污点操作
运行操作的方法中实际调用了updateTaints方法来
// updateTaints applies a taint option(o) to a node in cluster after computing the net effect of operation(i.e. does it result in an overwrite?), it reports back the end result in a way that user can easily interpret.
func (o TaintOptions) updateTaints(obj runtime.Object) (string, error) {
node, ok := obj.(*v1.Node)
if !ok {
return "", fmt.Errorf("unexpected type %T, expected Node", obj)
}
if !o.overwrite {
if exists := taintutils.CheckIfTaintsAlreadyExists(node.Spec.Taints, o.taintsToAdd); len(exists) != 0 {
return "", fmt.Errorf("Node %s already has %v taint(s) with same effect(s) and --overwrite is false", node.Name, exists)
}
}
operation, newTaints, err := taintutils.ReorganizeTaints(node, o.overwrite, o.taintsToAdd, o.taintsToRemove)
if err != nil {
return "", err
}
node.Spec.Taints = newTaints
return operation, nil
}
返回更新后的污点集
ReorganizeTaints方法用于返回更新后的污点集
// 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)
}
添加污点
// 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)
}
删除污点
// 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
}
附:能否调度DaemonSet到节点的代码
func schedulableNodes(c clientset.Interface, ds *apps.DaemonSet) []string {
nodeList, err := c.CoreV1().Nodes().List(metav1.ListOptions{})
framework.ExpectNoError(err)
nodeNames := make([]string, 0)
for _, node := range nodeList.Items {
if !canScheduleOnNode(node, ds) {
framework.Logf("DaemonSet pods can't tolerate node %s with taints %+v, skip checking this node", node.Name, node.Spec.Taints)
continue
}
nodeNames = append(nodeNames, node.Name)
}
return nodeNames
}
更多推荐
已为社区贡献4条内容
所有评论(0)