diff --git a/pkg/kubelet/lifecycle/predicate.go b/pkg/kubelet/lifecycle/predicate.go index 163daaa9740..2700b2d526e 100644 --- a/pkg/kubelet/lifecycle/predicate.go +++ b/pkg/kubelet/lifecycle/predicate.go @@ -21,10 +21,13 @@ import ( "runtime" v1 "k8s.io/api/core/v1" + "k8s.io/component-helpers/scheduling/corev1" "k8s.io/klog/v2" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/kubelet/types" "k8s.io/kubernetes/pkg/scheduler" schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration" ) type getNodeAnyWayFuncType func() (*v1.Node, error) @@ -270,5 +273,17 @@ func generalFilter(pod *v1.Pod, nodeInfo *schedulerframework.NodeInfo) []Predica reasons = append(reasons, &PredicateFailureError{r.Name, r.Reason}) } } + + // Check taint/toleration except for static pods + if !types.IsStaticPod(pod) { + _, isUntolerated := corev1.FindMatchingUntoleratedTaint(nodeInfo.Node().Spec.Taints, pod.Spec.Tolerations, func(t *v1.Taint) bool { + // Kubelet is only interested in the NoExecute taint. + return t.Effect == v1.TaintEffectNoExecute + }) + if isUntolerated { + reasons = append(reasons, &PredicateFailureError{tainttoleration.Name, tainttoleration.ErrReasonNotMatch}) + } + } + return reasons } diff --git a/pkg/kubelet/lifecycle/predicate_test.go b/pkg/kubelet/lifecycle/predicate_test.go index 14ad3754883..4efe35ab741 100644 --- a/pkg/kubelet/lifecycle/predicate_test.go +++ b/pkg/kubelet/lifecycle/predicate_test.go @@ -25,9 +25,11 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper" + "k8s.io/kubernetes/pkg/kubelet/types" schedulerframework "k8s.io/kubernetes/pkg/scheduler/framework" "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodename" "k8s.io/kubernetes/pkg/scheduler/framework/plugins/nodeports" + "k8s.io/kubernetes/pkg/scheduler/framework/plugins/tainttoleration" ) var ( @@ -240,6 +242,92 @@ func TestGeneralPredicates(t *testing.T) { reasons: []PredicateFailureReason{&PredicateFailureError{nodeports.Name, nodeports.ErrReason}}, name: "hostport conflict", }, + { + pod: &v1.Pod{ + Spec: v1.PodSpec{ + Tolerations: []v1.Toleration{ + {Key: "foo"}, + {Key: "bar"}, + }, + }, + }, + nodeInfo: schedulerframework.NewNodeInfo(), + node: &v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, + Spec: v1.NodeSpec{ + Taints: []v1.Taint{ + {Key: "foo", Effect: v1.TaintEffectNoSchedule}, + {Key: "bar", Effect: v1.TaintEffectNoExecute}, + }, + }, + Status: v1.NodeStatus{Capacity: makeResources(10, 20, 32, 0, 0, 0).Capacity, Allocatable: makeAllocatableResources(10, 20, 32, 0, 0, 0)}, + }, + name: "taint/toleration match", + }, + { + pod: &v1.Pod{}, + nodeInfo: schedulerframework.NewNodeInfo(), + node: &v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, + Spec: v1.NodeSpec{ + Taints: []v1.Taint{ + {Key: "foo", Effect: v1.TaintEffectNoSchedule}, + }, + }, + Status: v1.NodeStatus{Capacity: makeResources(10, 20, 32, 0, 0, 0).Capacity, Allocatable: makeAllocatableResources(10, 20, 32, 0, 0, 0)}, + }, + name: "NoSchedule taint/toleration not match", + }, + { + pod: &v1.Pod{}, + nodeInfo: schedulerframework.NewNodeInfo(), + node: &v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, + Spec: v1.NodeSpec{ + Taints: []v1.Taint{ + {Key: "bar", Effect: v1.TaintEffectNoExecute}, + }, + }, + Status: v1.NodeStatus{Capacity: makeResources(10, 20, 32, 0, 0, 0).Capacity, Allocatable: makeAllocatableResources(10, 20, 32, 0, 0, 0)}, + }, + reasons: []PredicateFailureReason{&PredicateFailureError{tainttoleration.Name, tainttoleration.ErrReasonNotMatch}}, + name: "NoExecute taint/toleration not match", + }, + { + pod: &v1.Pod{}, + nodeInfo: schedulerframework.NewNodeInfo(), + node: &v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, + Spec: v1.NodeSpec{ + Taints: []v1.Taint{ + {Key: "baz", Effect: v1.TaintEffectPreferNoSchedule}, + }, + }, + Status: v1.NodeStatus{Capacity: makeResources(10, 20, 32, 0, 0, 0).Capacity, Allocatable: makeAllocatableResources(10, 20, 32, 0, 0, 0)}, + }, + name: "PreferNoSchedule taint/toleration not match", + }, + { + pod: &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + types.ConfigSourceAnnotationKey: types.FileSource, + }, + }, + }, + nodeInfo: schedulerframework.NewNodeInfo(), + node: &v1.Node{ + ObjectMeta: metav1.ObjectMeta{Name: "machine1"}, + Spec: v1.NodeSpec{ + Taints: []v1.Taint{ + {Key: "foo", Effect: v1.TaintEffectNoSchedule}, + {Key: "bar", Effect: v1.TaintEffectNoExecute}, + }, + }, + Status: v1.NodeStatus{Capacity: makeResources(10, 20, 32, 0, 0, 0).Capacity, Allocatable: makeAllocatableResources(10, 20, 32, 0, 0, 0)}, + }, + name: "static pods ignore taints", + }, } for _, test := range resourceTests { t.Run(test.name, func(t *testing.T) {