mirror of https://github.com/k3s-io/k3s
Merge pull request #46514 from ravisantoshgudimetla/scheduler_taints_refactor
Automatic merge from submit-queue (batch tested with PRs 49420, 49296, 49299, 49371, 46514) Refactoring taint functions to reduce sprawl **What this PR does / why we need it**: **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes #45060 **Special notes for your reviewer**: @gmarek @timothysc @k82cn @jayunit100 - I moved some fn's to helpers and some to utils. LMK, if you are ok with this change. **Release note**: ```release-note NONE ```pull/6/head
commit
c1c7193b4d
|
@ -26,7 +26,6 @@ go_library(
|
|||
srcs = ["helpers.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/helper:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
|
|
|
@ -21,11 +21,9 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/helper"
|
||||
)
|
||||
|
||||
|
@ -269,34 +267,6 @@ func TolerationsTolerateTaintsWithFilter(tolerations []v1.Toleration, taints []v
|
|||
return true
|
||||
}
|
||||
|
||||
// DeleteTaintsByKey removes all the taints that have the same key to given taintKey
|
||||
func DeleteTaintsByKey(taints []v1.Taint, taintKey string) ([]v1.Taint, bool) {
|
||||
newTaints := []v1.Taint{}
|
||||
deleted := false
|
||||
for i := range taints {
|
||||
if taintKey == taints[i].Key {
|
||||
deleted = true
|
||||
continue
|
||||
}
|
||||
newTaints = append(newTaints, taints[i])
|
||||
}
|
||||
return newTaints, deleted
|
||||
}
|
||||
|
||||
// DeleteTaint removes all the the taints that have the same key and effect to given taintToDelete.
|
||||
func DeleteTaint(taints []v1.Taint, taintToDelete *v1.Taint) ([]v1.Taint, bool) {
|
||||
newTaints := []v1.Taint{}
|
||||
deleted := false
|
||||
for i := range taints {
|
||||
if taintToDelete.MatchTaint(&taints[i]) {
|
||||
deleted = true
|
||||
continue
|
||||
}
|
||||
newTaints = append(newTaints, taints[i])
|
||||
}
|
||||
return newTaints, deleted
|
||||
}
|
||||
|
||||
// Returns true and list of Tolerations matching all Taints if all are tolerated, or false otherwise.
|
||||
func GetMatchingTolerations(taints []v1.Taint, tolerations []v1.Toleration) (bool, []v1.Toleration) {
|
||||
if len(taints) == 0 {
|
||||
|
@ -381,70 +351,6 @@ func PodAnnotationsFromSysctls(sysctls []v1.Sysctl) string {
|
|||
return strings.Join(kvs, ",")
|
||||
}
|
||||
|
||||
// Tries to add a taint to annotations list. Returns a new copy of updated Node and true if something was updated
|
||||
// false otherwise.
|
||||
func AddOrUpdateTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
|
||||
objCopy, err := api.Scheme.DeepCopy(node)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newNode := objCopy.(*v1.Node)
|
||||
nodeTaints := newNode.Spec.Taints
|
||||
|
||||
var newTaints []v1.Taint
|
||||
updated := false
|
||||
for i := range nodeTaints {
|
||||
if taint.MatchTaint(&nodeTaints[i]) {
|
||||
if helper.Semantic.DeepEqual(taint, nodeTaints[i]) {
|
||||
return newNode, false, nil
|
||||
}
|
||||
newTaints = append(newTaints, *taint)
|
||||
updated = true
|
||||
continue
|
||||
}
|
||||
|
||||
newTaints = append(newTaints, nodeTaints[i])
|
||||
}
|
||||
|
||||
if !updated {
|
||||
newTaints = append(newTaints, *taint)
|
||||
}
|
||||
|
||||
newNode.Spec.Taints = newTaints
|
||||
return newNode, true, nil
|
||||
}
|
||||
|
||||
func TaintExists(taints []v1.Taint, taintToFind *v1.Taint) bool {
|
||||
for _, taint := range taints {
|
||||
if taint.MatchTaint(taintToFind) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Tries to remove a taint from annotations list. Returns a new copy of updated Node and true if something was updated
|
||||
// false otherwise.
|
||||
func RemoveTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
|
||||
objCopy, err := api.Scheme.DeepCopy(node)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newNode := objCopy.(*v1.Node)
|
||||
nodeTaints := newNode.Spec.Taints
|
||||
if len(nodeTaints) == 0 {
|
||||
return newNode, false, nil
|
||||
}
|
||||
|
||||
if !TaintExists(nodeTaints, taint) {
|
||||
return newNode, false, nil
|
||||
}
|
||||
|
||||
newTaints, _ := DeleteTaint(nodeTaints, taint)
|
||||
newNode.Spec.Taints = newTaints
|
||||
return newNode, true, nil
|
||||
}
|
||||
|
||||
// GetPersistentVolumeClass returns StorageClassName.
|
||||
func GetPersistentVolumeClass(volume *v1.PersistentVolume) string {
|
||||
// Use beta annotation first
|
||||
|
|
|
@ -8,6 +8,37 @@ load(
|
|||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"controller_ref_manager_test.go",
|
||||
"controller_utils_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/securitycontext:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
|
@ -21,12 +52,12 @@ go_library(
|
|||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/install:go_default_library",
|
||||
"//pkg/api/v1/helper:go_default_library",
|
||||
"//pkg/api/v1/pod:go_default_library",
|
||||
"//pkg/api/validation:go_default_library",
|
||||
"//pkg/client/retry:go_default_library",
|
||||
"//pkg/serviceaccount:go_default_library",
|
||||
"//pkg/util/hash:go_default_library",
|
||||
"//pkg/util/taints:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/golang/groupcache/lru:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
|
||||
|
@ -61,37 +92,6 @@ go_library(
|
|||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"controller_ref_manager_test.go",
|
||||
"controller_utils_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/testapi:go_default_library",
|
||||
"//pkg/securitycontext:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/clock:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/uuid:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/record:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/testing:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
|
|
|
@ -44,11 +44,11 @@ import (
|
|||
ref "k8s.io/client-go/tools/reference"
|
||||
"k8s.io/client-go/util/integer"
|
||||
_ "k8s.io/kubernetes/pkg/api/install"
|
||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
clientretry "k8s.io/kubernetes/pkg/client/retry"
|
||||
hashutil "k8s.io/kubernetes/pkg/util/hash"
|
||||
taintutils "k8s.io/kubernetes/pkg/util/taints"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
@ -901,7 +901,7 @@ func AddOrUpdateTaintOnNode(c clientset.Interface, nodeName string, taint *v1.Ta
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newNode, ok, err := v1helper.AddOrUpdateTaint(oldNode, taint)
|
||||
newNode, ok, err := taintutils.AddOrUpdateTaint(oldNode, taint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to update taint annotation!")
|
||||
}
|
||||
|
@ -945,7 +945,7 @@ func RemoveTaintOffNode(c clientset.Interface, nodeName string, taint *v1.Taint,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newNode, ok, err := v1helper.RemoveTaint(oldNode, taint)
|
||||
newNode, ok, err := taintutils.RemoveTaint(oldNode, taint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to update taint annotation!")
|
||||
}
|
||||
|
|
|
@ -8,6 +8,46 @@ load(
|
|||
"go_test",
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"cidr_allocator_test.go",
|
||||
"cidr_set_test.go",
|
||||
"nodecontroller_test.go",
|
||||
"rate_limited_queue_test.go",
|
||||
"taint_controller_test.go",
|
||||
"timed_workers_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/cloudprovider:go_default_library",
|
||||
"//pkg/cloudprovider/providers/fake:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/node/testutil:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/taints:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
|
@ -36,6 +76,7 @@ go_library(
|
|||
"//pkg/util/metrics:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//pkg/util/system:go_default_library",
|
||||
"//pkg/util/taints:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//plugin/pkg/scheduler/algorithm:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
|
@ -65,46 +106,6 @@ go_library(
|
|||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"cidr_allocator_test.go",
|
||||
"cidr_set_test.go",
|
||||
"nodecontroller_test.go",
|
||||
"rate_limited_queue_test.go",
|
||||
"taint_controller_test.go",
|
||||
"timed_workers_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api/v1/helper:go_default_library",
|
||||
"//pkg/cloudprovider:go_default_library",
|
||||
"//pkg/cloudprovider/providers/fake:go_default_library",
|
||||
"//pkg/controller:go_default_library",
|
||||
"//pkg/controller/node/testutil:go_default_library",
|
||||
"//pkg/kubelet/apis:go_default_library",
|
||||
"//pkg/util/node:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/informers/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
|
|
|
@ -45,13 +45,13 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
corelisters "k8s.io/client-go/listers/core/v1"
|
||||
extensionslisters "k8s.io/client-go/listers/extensions/v1beta1"
|
||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||
v1node "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/util/metrics"
|
||||
utilnode "k8s.io/kubernetes/pkg/util/node"
|
||||
"k8s.io/kubernetes/pkg/util/system"
|
||||
taintutils "k8s.io/kubernetes/pkg/util/taints"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
|
||||
|
||||
|
@ -604,7 +604,7 @@ func (nc *NodeController) monitorNodeStatus() error {
|
|||
if observedReadyCondition.Status == v1.ConditionFalse {
|
||||
if nc.useTaintBasedEvictions {
|
||||
// We want to update the taint straight away if Node is already tainted with the UnreachableTaint
|
||||
if v1helper.TaintExists(node.Spec.Taints, UnreachableTaintTemplate) {
|
||||
if taintutils.TaintExists(node.Spec.Taints, UnreachableTaintTemplate) {
|
||||
taintToAdd := *NotReadyTaintTemplate
|
||||
if !swapNodeControllerTaint(nc.kubeClient, &taintToAdd, UnreachableTaintTemplate, node) {
|
||||
glog.Errorf("Failed to instantly swap UnreachableTaint to NotReadyTaint. Will try again in the next cycle.")
|
||||
|
@ -631,7 +631,7 @@ func (nc *NodeController) monitorNodeStatus() error {
|
|||
if observedReadyCondition.Status == v1.ConditionUnknown {
|
||||
if nc.useTaintBasedEvictions {
|
||||
// We want to update the taint straight away if Node is already tainted with the UnreachableTaint
|
||||
if v1helper.TaintExists(node.Spec.Taints, NotReadyTaintTemplate) {
|
||||
if taintutils.TaintExists(node.Spec.Taints, NotReadyTaintTemplate) {
|
||||
taintToAdd := *UnreachableTaintTemplate
|
||||
if !swapNodeControllerTaint(nc.kubeClient, &taintToAdd, NotReadyTaintTemplate, node) {
|
||||
glog.Errorf("Failed to instantly swap UnreachableTaint to NotReadyTaint. Will try again in the next cycle.")
|
||||
|
|
|
@ -36,13 +36,13 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
testcore "k8s.io/client-go/testing"
|
||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||
fakecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/fake"
|
||||
"k8s.io/kubernetes/pkg/controller"
|
||||
"k8s.io/kubernetes/pkg/controller/node/testutil"
|
||||
kubeletapis "k8s.io/kubernetes/pkg/kubelet/apis"
|
||||
"k8s.io/kubernetes/pkg/util/node"
|
||||
taintutils "k8s.io/kubernetes/pkg/util/taints"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -1326,7 +1326,6 @@ func TestMonitorNodeStatusEvictPodsWithDisruption(t *testing.T) {
|
|||
break
|
||||
}
|
||||
}
|
||||
|
||||
if item.expectedEvictPods != podEvicted {
|
||||
t.Errorf("%v: expected pod eviction: %+v, got %+v", item.description, item.expectedEvictPods, podEvicted)
|
||||
}
|
||||
|
@ -2019,7 +2018,7 @@ func TestSwapUnreachableNotReadyTaints(t *testing.T) {
|
|||
return
|
||||
}
|
||||
|
||||
if originalTaint != nil && !v1helper.TaintExists(node0.Spec.Taints, originalTaint) {
|
||||
if originalTaint != nil && !taintutils.TaintExists(node0.Spec.Taints, originalTaint) {
|
||||
t.Errorf("Can't find taint %v in %v", originalTaint, node0.Spec.Taints)
|
||||
}
|
||||
|
||||
|
@ -2052,7 +2051,7 @@ func TestSwapUnreachableNotReadyTaints(t *testing.T) {
|
|||
return
|
||||
}
|
||||
if updatedTaint != nil {
|
||||
if !v1helper.TaintExists(node0.Spec.Taints, updatedTaint) {
|
||||
if !taintutils.TaintExists(node0.Spec.Taints, updatedTaint) {
|
||||
t.Errorf("Can't find taint %v in %v", updatedTaint, node0.Spec.Taints)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,6 @@ go_library(
|
|||
],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/v1/helper:go_default_library",
|
||||
"//pkg/api/validation:go_default_library",
|
||||
"//pkg/apis/certificates:go_default_library",
|
||||
"//pkg/apis/policy:go_default_library",
|
||||
|
|
|
@ -28,23 +28,14 @@ import (
|
|||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
utiltaints "k8s.io/kubernetes/pkg/util/taints"
|
||||
)
|
||||
|
||||
const (
|
||||
MODIFIED = "modified"
|
||||
TAINTED = "tainted"
|
||||
UNTAINTED = "untainted"
|
||||
taintutils "k8s.io/kubernetes/pkg/util/taints"
|
||||
)
|
||||
|
||||
// TaintOptions have the data required to perform the taint operation
|
||||
|
@ -121,95 +112,6 @@ func NewCmdTaint(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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 = v1helper.DeleteTaint(*newTaints, &taintToRemove)
|
||||
} else {
|
||||
*newTaints, removed = v1helper.DeleteTaintsByKey(*newTaints, taintToRemove.Key)
|
||||
}
|
||||
if !removed {
|
||||
allErrs = append(allErrs, fmt.Errorf("taint %q not found", taintToRemove.ToString()))
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
func parseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {
|
||||
var taints, taintsToRemove []v1.Taint
|
||||
uniqueTaints := map[v1.TaintEffect]sets.String{}
|
||||
|
||||
for _, taintSpec := range spec {
|
||||
if strings.Contains(taintSpec, "=") && strings.Contains(taintSpec, ":") {
|
||||
newTaint, err := utiltaints.ParseTaint(taintSpec)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// validate if taint is unique by <key, effect>
|
||||
if len(uniqueTaints[newTaint.Effect]) > 0 && uniqueTaints[newTaint.Effect].Has(newTaint.Key) {
|
||||
return nil, nil, fmt.Errorf("duplicated taints with the same key and effect: %v", newTaint)
|
||||
}
|
||||
// add taint to existingTaints for uniqueness check
|
||||
if len(uniqueTaints[newTaint.Effect]) == 0 {
|
||||
uniqueTaints[newTaint.Effect] = sets.String{}
|
||||
}
|
||||
uniqueTaints[newTaint.Effect].Insert(newTaint.Key)
|
||||
|
||||
taints = append(taints, newTaint)
|
||||
} else if strings.HasSuffix(taintSpec, "-") {
|
||||
taintKey := taintSpec[:len(taintSpec)-1]
|
||||
var effect v1.TaintEffect
|
||||
if strings.Contains(taintKey, ":") {
|
||||
parts := strings.Split(taintKey, ":")
|
||||
taintKey = parts[0]
|
||||
effect = v1.TaintEffect(parts[1])
|
||||
}
|
||||
taintsToRemove = append(taintsToRemove, v1.Taint{Key: taintKey, Effect: effect})
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("unknown taint spec: %v", taintSpec)
|
||||
}
|
||||
}
|
||||
return taints, taintsToRemove, nil
|
||||
}
|
||||
|
||||
// Complete adapts from the command line args and factory to the data required.
|
||||
func (o *TaintOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) (err error) {
|
||||
namespace, _, err := f.DefaultNamespace()
|
||||
|
@ -243,7 +145,7 @@ func (o *TaintOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
|
|||
return fmt.Errorf("at least one taint update is required")
|
||||
}
|
||||
|
||||
if o.taintsToAdd, o.taintsToRemove, err = parseTaints(taintArgs); err != nil {
|
||||
if o.taintsToAdd, o.taintsToRemove, err = taintutils.ParseTaints(taintArgs); err != nil {
|
||||
return cmdutil.UsageErrorf(cmd, err.Error())
|
||||
}
|
||||
o.builder = f.NewBuilder(true).
|
||||
|
@ -380,21 +282,6 @@ func (o TaintOptions) RunTaint() error {
|
|||
})
|
||||
}
|
||||
|
||||
// validateNoTaintOverwrites validates that when overwrite is false, to-be-updated taints don't exist in the node taint list (yet)
|
||||
func validateNoTaintOverwrites(node *v1.Node, taints []v1.Taint) error {
|
||||
allErrs := []error{}
|
||||
oldTaints := node.Spec.Taints
|
||||
for _, taint := range taints {
|
||||
for _, oldTaint := range oldTaints {
|
||||
if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect {
|
||||
allErrs = append(allErrs, fmt.Errorf("Node '%s' already has a taint with key (%s) and effect (%v), and --overwrite is false", node.Name, taint.Key, taint.Effect))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
@ -402,11 +289,11 @@ func (o TaintOptions) updateTaints(obj runtime.Object) (string, error) {
|
|||
return "", fmt.Errorf("unexpected type %T, expected Node", obj)
|
||||
}
|
||||
if !o.overwrite {
|
||||
if err := validateNoTaintOverwrites(node, o.taintsToAdd); err != nil {
|
||||
return "", err
|
||||
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 := reorganizeTaints(node, o.overwrite, o.taintsToAdd, o.taintsToRemove)
|
||||
operation, newTaints, err := taintutils.ReorganizeTaints(node, o.overwrite, o.taintsToAdd, o.taintsToRemove)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -14,7 +14,10 @@ go_library(
|
|||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//pkg/api:go_default_library",
|
||||
"//pkg/api/helper:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -14,20 +14,29 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// package taints implements uitilites for working with taints
|
||||
// package taints implements utilites for working with taints
|
||||
package taints
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/helper"
|
||||
)
|
||||
|
||||
// ParseTaint parses a taint from a string. Taint must be of the format '<key>=<value>:<effect>'.
|
||||
func ParseTaint(st string) (v1.Taint, error) {
|
||||
const (
|
||||
MODIFIED = "modified"
|
||||
TAINTED = "tainted"
|
||||
UNTAINTED = "untainted"
|
||||
)
|
||||
|
||||
// parseTaint parses a taint from a string. Taint must be off the format '<key>=<value>:<effect>'.
|
||||
func parseTaint(st string) (v1.Taint, error) {
|
||||
var taint v1.Taint
|
||||
parts := strings.Split(st, "=")
|
||||
if len(parts) != 2 || len(parts[1]) == 0 || len(validation.IsQualifiedName(parts[0])) > 0 {
|
||||
|
@ -70,7 +79,7 @@ func (t taintsVar) Set(s string) error {
|
|||
sts := strings.Split(s, ",")
|
||||
var taints []api.Taint
|
||||
for _, st := range sts {
|
||||
taint, err := ParseTaint(st)
|
||||
taint, err := parseTaint(st)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -94,3 +103,199 @@ func (t taintsVar) String() string {
|
|||
func (t taintsVar) Type() string {
|
||||
return "[]api.Taint"
|
||||
}
|
||||
|
||||
// ParseTaints takes a spec which is an array and creates slices for new taints to be added, taints to be deleted.
|
||||
func ParseTaints(spec []string) ([]v1.Taint, []v1.Taint, error) {
|
||||
var taints, taintsToRemove []v1.Taint
|
||||
uniqueTaints := map[v1.TaintEffect]sets.String{}
|
||||
|
||||
for _, taintSpec := range spec {
|
||||
if strings.Index(taintSpec, "=") != -1 && strings.Index(taintSpec, ":") != -1 {
|
||||
newTaint, err := parseTaint(taintSpec)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// validate if taint is unique by <key, effect>
|
||||
if len(uniqueTaints[newTaint.Effect]) > 0 && uniqueTaints[newTaint.Effect].Has(newTaint.Key) {
|
||||
return nil, nil, fmt.Errorf("duplicated taints with the same key and effect: %v", newTaint)
|
||||
}
|
||||
// add taint to existingTaints for uniqueness check
|
||||
if len(uniqueTaints[newTaint.Effect]) == 0 {
|
||||
uniqueTaints[newTaint.Effect] = sets.String{}
|
||||
}
|
||||
uniqueTaints[newTaint.Effect].Insert(newTaint.Key)
|
||||
|
||||
taints = append(taints, newTaint)
|
||||
} else if strings.HasSuffix(taintSpec, "-") {
|
||||
taintKey := taintSpec[:len(taintSpec)-1]
|
||||
var effect v1.TaintEffect
|
||||
if strings.Index(taintKey, ":") != -1 {
|
||||
parts := strings.Split(taintKey, ":")
|
||||
taintKey = parts[0]
|
||||
effect = v1.TaintEffect(parts[1])
|
||||
}
|
||||
taintsToRemove = append(taintsToRemove, v1.Taint{Key: taintKey, Effect: effect})
|
||||
} else {
|
||||
return nil, nil, fmt.Errorf("unknown taint spec: %v", taintSpec)
|
||||
}
|
||||
}
|
||||
return taints, taintsToRemove, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// CheckIfTaintsAlreadyExists checks if the node already has taints that we want to add and returns a string with taint keys.
|
||||
func CheckIfTaintsAlreadyExists(oldTaints []v1.Taint, taints []v1.Taint) string {
|
||||
var existingTaintList = make([]string, 0)
|
||||
for _, taint := range taints {
|
||||
for _, oldTaint := range oldTaints {
|
||||
if taint.Key == oldTaint.Key && taint.Effect == oldTaint.Effect {
|
||||
existingTaintList = append(existingTaintList, taint.Key)
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.Join(existingTaintList, ",")
|
||||
}
|
||||
|
||||
// DeleteTaintsByKey removes all the taints that have the same key to given taintKey
|
||||
func DeleteTaintsByKey(taints []v1.Taint, taintKey string) ([]v1.Taint, bool) {
|
||||
newTaints := []v1.Taint{}
|
||||
deleted := false
|
||||
for i := range taints {
|
||||
if taintKey == taints[i].Key {
|
||||
deleted = true
|
||||
continue
|
||||
}
|
||||
newTaints = append(newTaints, taints[i])
|
||||
}
|
||||
return newTaints, deleted
|
||||
}
|
||||
|
||||
// DeleteTaint removes all the the taints that have the same key and effect to given taintToDelete.
|
||||
func DeleteTaint(taints []v1.Taint, taintToDelete *v1.Taint) ([]v1.Taint, bool) {
|
||||
newTaints := []v1.Taint{}
|
||||
deleted := false
|
||||
for i := range taints {
|
||||
if taintToDelete.MatchTaint(&taints[i]) {
|
||||
deleted = true
|
||||
continue
|
||||
}
|
||||
newTaints = append(newTaints, taints[i])
|
||||
}
|
||||
return newTaints, deleted
|
||||
}
|
||||
|
||||
// RemoveTaint tries to remove a taint from annotations list. Returns a new copy of updated Node and true if something was updated
|
||||
// false otherwise.
|
||||
func RemoveTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
|
||||
objCopy, err := api.Scheme.DeepCopy(node)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newNode := objCopy.(*v1.Node)
|
||||
nodeTaints := newNode.Spec.Taints
|
||||
if len(nodeTaints) == 0 {
|
||||
return newNode, false, nil
|
||||
}
|
||||
|
||||
if !TaintExists(nodeTaints, taint) {
|
||||
return newNode, false, nil
|
||||
}
|
||||
|
||||
newTaints, _ := DeleteTaint(nodeTaints, taint)
|
||||
newNode.Spec.Taints = newTaints
|
||||
return newNode, true, nil
|
||||
}
|
||||
|
||||
// AddOrUpdateTaint tries to add a taint to annotations list. Returns a new copy of updated Node and true if something was updated
|
||||
// false otherwise.
|
||||
func AddOrUpdateTaint(node *v1.Node, taint *v1.Taint) (*v1.Node, bool, error) {
|
||||
objCopy, err := api.Scheme.DeepCopy(node)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
newNode := objCopy.(*v1.Node)
|
||||
nodeTaints := newNode.Spec.Taints
|
||||
|
||||
var newTaints []v1.Taint
|
||||
updated := false
|
||||
for i := range nodeTaints {
|
||||
if taint.MatchTaint(&nodeTaints[i]) {
|
||||
if helper.Semantic.DeepEqual(taint, nodeTaints[i]) {
|
||||
return newNode, false, nil
|
||||
}
|
||||
newTaints = append(newTaints, *taint)
|
||||
updated = true
|
||||
continue
|
||||
}
|
||||
|
||||
newTaints = append(newTaints, nodeTaints[i])
|
||||
}
|
||||
|
||||
if !updated {
|
||||
newTaints = append(newTaints, *taint)
|
||||
}
|
||||
|
||||
newNode.Spec.Taints = newTaints
|
||||
return newNode, true, nil
|
||||
}
|
||||
|
||||
// TaintExists checks if the given taint exists in list of taints. Returns true if exists false otherwise.
|
||||
func TaintExists(taints []v1.Taint, taintToFind *v1.Taint) bool {
|
||||
for _, taint := range taints {
|
||||
if taint.MatchTaint(taintToFind) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ go_library(
|
|||
"//pkg/util/file:go_default_library",
|
||||
"//pkg/util/labels:go_default_library",
|
||||
"//pkg/util/system:go_default_library",
|
||||
"//pkg/util/taints:go_default_library",
|
||||
"//pkg/util/version:go_default_library",
|
||||
"//pkg/volume/util/volumehelper:go_default_library",
|
||||
"//plugin/pkg/scheduler/algorithm/predicates:go_default_library",
|
||||
|
|
|
@ -75,7 +75,6 @@ import (
|
|||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
|
||||
nodeutil "k8s.io/kubernetes/pkg/api/v1/node"
|
||||
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
|
||||
batchinternal "k8s.io/kubernetes/pkg/apis/batch"
|
||||
|
@ -91,6 +90,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/master/ports"
|
||||
sshutil "k8s.io/kubernetes/pkg/ssh"
|
||||
"k8s.io/kubernetes/pkg/util/system"
|
||||
taintutils "k8s.io/kubernetes/pkg/util/taints"
|
||||
utilversion "k8s.io/kubernetes/pkg/util/version"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
|
||||
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
|
||||
|
@ -2507,7 +2507,7 @@ func VerifyThatTaintIsGone(c clientset.Interface, nodeName string, taint *v1.Tai
|
|||
By("verifying the node doesn't have the taint " + taint.ToString())
|
||||
nodeUpdated, err := c.Core().Nodes().Get(nodeName, metav1.GetOptions{})
|
||||
ExpectNoError(err)
|
||||
if v1helper.TaintExists(nodeUpdated.Spec.Taints, taint) {
|
||||
if taintutils.TaintExists(nodeUpdated.Spec.Taints, taint) {
|
||||
Failf("Failed removing taint " + taint.ToString() + " of the node " + nodeName)
|
||||
}
|
||||
}
|
||||
|
@ -2528,7 +2528,7 @@ func NodeHasTaint(c clientset.Interface, nodeName string, taint *v1.Taint) (bool
|
|||
|
||||
nodeTaints := node.Spec.Taints
|
||||
|
||||
if len(nodeTaints) == 0 || !v1helper.TaintExists(nodeTaints, taint) {
|
||||
if len(nodeTaints) == 0 || !taintutils.TaintExists(nodeTaints, taint) {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
|
|
Loading…
Reference in New Issue