Code change:
// 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. <del> func reorganizeTaints(obj runtime.Object, overwrite bool, taintsToAdd []v1.Taint, taintsToRemove []v1.Taint) ([]v1.Taint, error) { node, ok := obj.(*v1.Node) if !ok { return nil, fmt.Errorf("unexpected type %T, expected Node", obj) } </del> <ins> func reorganizeTaints(node *v1.Node, overwrite bool, taintsToAdd []v1.Taint, taintsToRemove []v1.Taint) (string, []v1.Taint, error) { </ins> newTaints := append([]v1.Taint{}, taintsToAdd...) oldTaints := node.Spec.Taints // add taints that already existing but not updated to newTaints <del> for _, oldTaint := range oldTaints { existsInNew := false for _, taint := range newTaints { if taint.MatchTaint(&oldTaint) { existsInNew = true break } } if !existsInNew { newTaints = append(newTaints, oldTaint) } </del> <ins> 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) </ins> } <ins> 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) { </ins> allErrs := []error{} <ins> var removed bool </ins> for _, taintToRemove := range taintsToRemove { <del> removed := false </del> <ins> removed = false </ins> if len(taintToRemove.Effect) > 0 { <del> newTaints, removed = v1helper.DeleteTaint(newTaints, &taintToRemove) </del> <ins> *newTaints, removed = v1helper.DeleteTaint(*newTaints, &taintToRemove) </ins> } else { <del> newTaints, removed = v1helper.DeleteTaintsByKey(newTaints, taintToRemove.Key) </del> <ins> *newTaints, removed = v1helper.DeleteTaintsByKey(*newTaints, taintToRemove.Key) </ins> } if !removed { allErrs = append(allErrs, fmt.Errorf("taint %q not found", taintToRemove.ToString())) } } <del> return newTaints, utilerrors.NewAggregate(allErrs) </del> <ins> 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) </ins> } func parseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {

Related discussion:
text: Is this a BUG REPORT or FEATURE REQUEST? (choose one): BUG <!-- If this is a BUG REPORT, please: Fill in as much of the template below as you can. If you leave out information, we can't help you as well. If this is a FEATURE REQUEST, please: Describe in detail the feature/behavior/change you'd like to see. In both cases, be ready for followup questions, and please respond in a timely manner. If we can't reproduce a bug or think a feature already exists, we might close your issue. If we're wrong, PLEASE feel free to reopen it and explain why. --Kubernetes version (use ): Client Version: version.Info{Major:"1", Minor:"6+", GitVersion:"v1.6.0-alpha.3.1185+-dirty Server Version: version.Info{Major:"1", Minor:"6+", GitVersion:"v1.6.0-alpha.3.1185+-dirty" What happened: Kubectl is always reporting as node <XYZis tainted irrespective of operation when used with local cluster. taint nodes XYZ dedicated- node "XYZ" tainted What you expected to happen: It should have shown exact operation like tainted, untainted modified and overwritten but because of it is always returning tainted. How to reproduce it (as minimally and precisely as possible): taint nodes XYZ dedicated-
cc/
Regarding Yes I agree we should provide more clearer output/feedback. But providing something that makes output more confusing than existing is something would be even more concerning. So as I stated , it would be good to discuss/decide how the output/feedback should like for various operations for one and multi nodes scenarios.
I think having 1 return values is an exponential improvement on what we have now, even if they aren't perfect for all cases. Rather then a disproportionately long debate over a relatively simple improvement.... Could you guys suggest something simple that you're confident it will be easy to agree on, and we can implement it as a second pass ? we are happy to implement anything with n 1 return values :).
I think we'd be happy to consider any reasonable PR. I'm not sure why was closed; I didn't look at it though so I don't know if it solves the problem.
(hit close accidentally)
, I am not sure why was closed. But I raised a PR around 15 days ago() to address this.