Merge pull request #98445 from damemi/taint-toleration-internal-helpers

Move Taint/Toleration helpers to component-helpers repo
This commit is contained in:
Kubernetes Prow Robot 2021-02-01 17:50:27 -08:00 committed by GitHub
commit f27318c0da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 177 additions and 181 deletions

View File

@ -316,53 +316,6 @@ func AddOrUpdateTolerationInPod(pod *v1.Pod, toleration *v1.Toleration) bool {
return AddOrUpdateTolerationInPodSpec(&pod.Spec, toleration)
}
// TolerationsTolerateTaint checks if taint is tolerated by any of the tolerations.
func TolerationsTolerateTaint(tolerations []v1.Toleration, taint *v1.Taint) bool {
for i := range tolerations {
if tolerations[i].ToleratesTaint(taint) {
return true
}
}
return false
}
type taintsFilterFunc func(*v1.Taint) bool
// TolerationsTolerateTaintsWithFilter checks if given tolerations tolerates
// all the taints that apply to the filter in given taint list.
// DEPRECATED: Please use FindMatchingUntoleratedTaint instead.
func TolerationsTolerateTaintsWithFilter(tolerations []v1.Toleration, taints []v1.Taint, applyFilter taintsFilterFunc) bool {
_, isUntolerated := FindMatchingUntoleratedTaint(taints, tolerations, applyFilter)
return !isUntolerated
}
// FindMatchingUntoleratedTaint checks if the given tolerations tolerates
// all the filtered taints, and returns the first taint without a toleration
func FindMatchingUntoleratedTaint(taints []v1.Taint, tolerations []v1.Toleration, inclusionFilter taintsFilterFunc) (v1.Taint, bool) {
filteredTaints := getFilteredTaints(taints, inclusionFilter)
for _, taint := range filteredTaints {
if !TolerationsTolerateTaint(tolerations, &taint) {
return taint, true
}
}
return v1.Taint{}, false
}
// getFilteredTaints returns a list of taints satisfying the filter predicate
func getFilteredTaints(taints []v1.Taint, inclusionFilter taintsFilterFunc) []v1.Taint {
if inclusionFilter == nil {
return taints
}
filteredTaints := []v1.Taint{}
for _, taint := range taints {
if !inclusionFilter(&taint) {
continue
}
filteredTaints = append(filteredTaints, taint)
}
return filteredTaints
}
// GetMatchingTolerations 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 {

View File

@ -309,126 +309,6 @@ func TestTopologySelectorRequirementsAsSelector(t *testing.T) {
}
}
func TestTolerationsTolerateTaintsWithFilter(t *testing.T) {
testCases := []struct {
description string
tolerations []v1.Toleration
taints []v1.Taint
applyFilter taintsFilterFunc
expectTolerated bool
}{
{
description: "empty tolerations tolerate empty taints",
tolerations: []v1.Toleration{},
taints: []v1.Taint{},
applyFilter: func(t *v1.Taint) bool { return true },
expectTolerated: true,
},
{
description: "non-empty tolerations tolerate empty taints",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{},
applyFilter: func(t *v1.Taint) bool { return true },
expectTolerated: true,
},
{
description: "tolerations match all taints, expect tolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{
{
Key: "foo",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: func(t *v1.Taint) bool { return true },
expectTolerated: true,
},
{
description: "tolerations don't match taints, but no taints apply to the filter, expect tolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{
{
Key: "bar",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: func(t *v1.Taint) bool { return false },
expectTolerated: true,
},
{
description: "no filterFunc indicated, means all taints apply to the filter, tolerations don't match taints, expect untolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{
{
Key: "bar",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: nil,
expectTolerated: false,
},
{
description: "tolerations match taints, expect tolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoExecute,
},
},
taints: []v1.Taint{
{
Key: "foo",
Effect: v1.TaintEffectNoExecute,
},
{
Key: "bar",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: func(t *v1.Taint) bool { return t.Effect == v1.TaintEffectNoExecute },
expectTolerated: true,
},
}
for _, tc := range testCases {
if tc.expectTolerated != TolerationsTolerateTaintsWithFilter(tc.tolerations, tc.taints, tc.applyFilter) {
filteredTaints := []v1.Taint{}
for _, taint := range tc.taints {
if tc.applyFilter != nil && !tc.applyFilter(&taint) {
continue
}
filteredTaints = append(filteredTaints, taint)
}
t.Errorf("[%s] expect tolerations %+v tolerate filtered taints %+v in taints %+v", tc.description, tc.tolerations, filteredTaints, tc.taints)
}
}
}
func TestMatchTopologySelectorTerms(t *testing.T) {
type args struct {
topologySelectorTerms []v1.TopologySelectorTerm

View File

@ -16,7 +16,6 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/controller/daemon",
deps = [
"//pkg/api/v1/pod:go_default_library",
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/controller:go_default_library",
"//pkg/controller/daemon/util:go_default_library",
"//pkg/scheduler/framework/plugins/helper:go_default_library",
@ -46,6 +45,7 @@ go_library(
"//staging/src/k8s.io/client-go/util/flowcontrol:go_default_library",
"//staging/src/k8s.io/client-go/util/workqueue:go_default_library",
"//staging/src/k8s.io/component-base/metrics/prometheus/ratelimiter:go_default_library",
"//staging/src/k8s.io/component-helpers/scheduling/corev1:go_default_library",
"//vendor/k8s.io/klog/v2:go_default_library",
"//vendor/k8s.io/utils/integer:go_default_library",
],

View File

@ -49,8 +49,8 @@ import (
"k8s.io/client-go/util/flowcontrol"
"k8s.io/client-go/util/workqueue"
"k8s.io/component-base/metrics/prometheus/ratelimiter"
v1helper "k8s.io/component-helpers/scheduling/corev1"
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
"k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/controller/daemon/util"
pluginhelper "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper"
@ -1238,10 +1238,10 @@ func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *v1.Node, ds *apps.
if !fitsTaints {
// Scheduled daemon pods should continue running if they tolerate NoExecute taint.
shouldContinueRunning := v1helper.TolerationsTolerateTaintsWithFilter(pod.Spec.Tolerations, taints, func(t *v1.Taint) bool {
_, untolerated := v1helper.FindMatchingUntoleratedTaint(taints, pod.Spec.Tolerations, func(t *v1.Taint) bool {
return t.Effect == v1.TaintEffectNoExecute
})
return false, shouldContinueRunning, nil
return false, !untolerated, nil
}
return true, true, nil
@ -1251,9 +1251,10 @@ func (dsc *DaemonSetsController) nodeShouldRunDaemonPod(node *v1.Node, ds *apps.
func Predicates(pod *v1.Pod, node *v1.Node, taints []v1.Taint) (fitsNodeName, fitsNodeAffinity, fitsTaints bool) {
fitsNodeName = len(pod.Spec.NodeName) == 0 || pod.Spec.NodeName == node.Name
fitsNodeAffinity = pluginhelper.PodMatchesNodeSelectorAndAffinityTerms(pod, node)
fitsTaints = v1helper.TolerationsTolerateTaintsWithFilter(pod.Spec.Tolerations, taints, func(t *v1.Taint) bool {
_, untolerated := v1helper.FindMatchingUntoleratedTaint(taints, pod.Spec.Tolerations, func(t *v1.Taint) bool {
return t.Effect == v1.TaintEffectNoExecute || t.Effect == v1.TaintEffectNoSchedule
})
fitsTaints = !untolerated
return
}

View File

@ -49,7 +49,6 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/kubelet/eviction",
deps = [
"//pkg/api/v1/resource:go_default_library",
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/apis/core/v1/helper/qos:go_default_library",
"//pkg/features:go_default_library",
"//pkg/kubelet/cm:go_default_library",

View File

@ -29,9 +29,9 @@ import (
"k8s.io/apimachinery/pkg/util/clock"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/record"
v1helper "k8s.io/component-helpers/scheduling/corev1"
statsapi "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
apiv1resource "k8s.io/kubernetes/pkg/api/v1/resource"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
v1qos "k8s.io/kubernetes/pkg/apis/core/v1/helper/qos"
"k8s.io/kubernetes/pkg/features"
evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"

View File

@ -6,10 +6,10 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeunschedulable",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/scheduler/framework:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/component-helpers/scheduling/corev1:go_default_library",
],
)

View File

@ -21,7 +21,7 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
v1helper "k8s.io/component-helpers/scheduling/corev1"
"k8s.io/kubernetes/pkg/scheduler/framework"
)

View File

@ -6,11 +6,11 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration",
visibility = ["//visibility:public"],
deps = [
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/scheduler/framework:go_default_library",
"//pkg/scheduler/framework/plugins/helper:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//staging/src/k8s.io/component-helpers/scheduling/corev1:go_default_library",
],
)

View File

@ -22,7 +22,7 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
v1helper "k8s.io/component-helpers/scheduling/corev1"
"k8s.io/kubernetes/pkg/scheduler/framework"
pluginhelper "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper"
)

View File

@ -58,3 +58,44 @@ func GetAvoidPodsFromNodeAnnotations(annotations map[string]string) (v1.AvoidPod
}
return avoidPods, nil
}
// TolerationsTolerateTaint checks if taint is tolerated by any of the tolerations.
func TolerationsTolerateTaint(tolerations []v1.Toleration, taint *v1.Taint) bool {
for i := range tolerations {
if tolerations[i].ToleratesTaint(taint) {
return true
}
}
return false
}
type taintsFilterFunc func(*v1.Taint) bool
// FindMatchingUntoleratedTaint checks if the given tolerations tolerates
// all the filtered taints, and returns the first taint without a toleration
// Returns true if there is an untolerated taint
// Returns false if all taints are tolerated
func FindMatchingUntoleratedTaint(taints []v1.Taint, tolerations []v1.Toleration, inclusionFilter taintsFilterFunc) (v1.Taint, bool) {
filteredTaints := getFilteredTaints(taints, inclusionFilter)
for _, taint := range filteredTaints {
if !TolerationsTolerateTaint(tolerations, &taint) {
return taint, true
}
}
return v1.Taint{}, false
}
// getFilteredTaints returns a list of taints satisfying the filter predicate
func getFilteredTaints(taints []v1.Taint, inclusionFilter taintsFilterFunc) []v1.Taint {
if inclusionFilter == nil {
return taints
}
filteredTaints := []v1.Taint{}
for _, taint := range taints {
if !inclusionFilter(&taint) {
continue
}
filteredTaints = append(filteredTaints, taint)
}
return filteredTaints
}

View File

@ -642,3 +642,124 @@ func TestGetAvoidPodsFromNode(t *testing.T) {
}
}
}
func TestFindMatchingUntoleratedTaint(t *testing.T) {
testCases := []struct {
description string
tolerations []v1.Toleration
taints []v1.Taint
applyFilter taintsFilterFunc
expectTolerated bool
}{
{
description: "empty tolerations tolerate empty taints",
tolerations: []v1.Toleration{},
taints: []v1.Taint{},
applyFilter: func(t *v1.Taint) bool { return true },
expectTolerated: true,
},
{
description: "non-empty tolerations tolerate empty taints",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{},
applyFilter: func(t *v1.Taint) bool { return true },
expectTolerated: true,
},
{
description: "tolerations match all taints, expect tolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{
{
Key: "foo",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: func(t *v1.Taint) bool { return true },
expectTolerated: true,
},
{
description: "tolerations don't match taints, but no taints apply to the filter, expect tolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{
{
Key: "bar",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: func(t *v1.Taint) bool { return false },
expectTolerated: true,
},
{
description: "no filterFunc indicated, means all taints apply to the filter, tolerations don't match taints, expect untolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoSchedule,
},
},
taints: []v1.Taint{
{
Key: "bar",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: nil,
expectTolerated: false,
},
{
description: "tolerations match taints, expect tolerated",
tolerations: []v1.Toleration{
{
Key: "foo",
Operator: "Exists",
Effect: v1.TaintEffectNoExecute,
},
},
taints: []v1.Taint{
{
Key: "foo",
Effect: v1.TaintEffectNoExecute,
},
{
Key: "bar",
Effect: v1.TaintEffectNoSchedule,
},
},
applyFilter: func(t *v1.Taint) bool { return t.Effect == v1.TaintEffectNoExecute },
expectTolerated: true,
},
}
for _, tc := range testCases {
_, untolerated := FindMatchingUntoleratedTaint(tc.taints, tc.tolerations, tc.applyFilter)
if tc.expectTolerated != !untolerated {
filteredTaints := []v1.Taint{}
for _, taint := range tc.taints {
if tc.applyFilter != nil && !tc.applyFilter(&taint) {
continue
}
filteredTaints = append(filteredTaints, taint)
}
t.Errorf("[%s] expect tolerations %+v tolerate filtered taints %+v in taints %+v", tc.description, tc.tolerations, filteredTaints, tc.taints)
}
}
}

View File

@ -38,7 +38,6 @@ go_library(
"//cmd/kube-apiserver/app:go_default_library",
"//cmd/kube-apiserver/app/options:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core/v1/helper:go_default_library",
"//pkg/controller/nodelifecycle:go_default_library",
"//pkg/controlplane:go_default_library",
"//pkg/generated/openapi:go_default_library",
@ -73,6 +72,7 @@ go_library(
"//staging/src/k8s.io/client-go/rest:go_default_library",
"//staging/src/k8s.io/client-go/util/cert:go_default_library",
"//staging/src/k8s.io/component-base/version:go_default_library",
"//staging/src/k8s.io/component-helpers/scheduling/corev1:go_default_library",
"//test/utils:go_default_library",
"//vendor/github.com/go-openapi/spec:go_default_library",
"//vendor/github.com/google/uuid:go_default_library",

View File

@ -31,8 +31,8 @@ import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/util/wait"
clientset "k8s.io/client-go/kubernetes"
v1helper "k8s.io/component-helpers/scheduling/corev1"
"k8s.io/klog/v2"
v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
nodectlr "k8s.io/kubernetes/pkg/controller/nodelifecycle"
)
@ -266,7 +266,8 @@ func isNodeUntainted(node *v1.Node) bool {
n = nodeCopy
}
return v1helper.TolerationsTolerateTaintsWithFilter(fakePod.Spec.Tolerations, n.Spec.Taints, func(t *v1.Taint) bool {
_, tolerated := v1helper.FindMatchingUntoleratedTaint(n.Spec.Taints, fakePod.Spec.Tolerations, func(t *v1.Taint) bool {
return t.Effect == v1.TaintEffectNoExecute || t.Effect == v1.TaintEffectNoSchedule
})
return tolerated
}