1
16
17 package tainttoleration
18
19 import (
20 "context"
21 "fmt"
22
23 v1 "k8s.io/api/core/v1"
24 "k8s.io/apimachinery/pkg/runtime"
25 v1helper "k8s.io/component-helpers/scheduling/corev1"
26 "k8s.io/kubernetes/pkg/scheduler/framework"
27 "k8s.io/kubernetes/pkg/scheduler/framework/plugins/helper"
28 "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
29 )
30
31
32 type TaintToleration struct {
33 handle framework.Handle
34 }
35
36 var _ framework.FilterPlugin = &TaintToleration{}
37 var _ framework.PreScorePlugin = &TaintToleration{}
38 var _ framework.ScorePlugin = &TaintToleration{}
39 var _ framework.EnqueueExtensions = &TaintToleration{}
40
41 const (
42
43 Name = names.TaintToleration
44
45 preScoreStateKey = "PreScore" + Name
46
47 ErrReasonNotMatch = "node(s) had taints that the pod didn't tolerate"
48 )
49
50
51 func (pl *TaintToleration) Name() string {
52 return Name
53 }
54
55
56
57 func (pl *TaintToleration) EventsToRegister() []framework.ClusterEventWithHint {
58 return []framework.ClusterEventWithHint{
59 {Event: framework.ClusterEvent{Resource: framework.Node, ActionType: framework.Add | framework.Update}},
60 }
61 }
62
63
64 func (pl *TaintToleration) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
65 node := nodeInfo.Node()
66
67 taint, isUntolerated := v1helper.FindMatchingUntoleratedTaint(node.Spec.Taints, pod.Spec.Tolerations, helper.DoNotScheduleTaintsFilterFunc())
68 if !isUntolerated {
69 return nil
70 }
71
72 errReason := fmt.Sprintf("node(s) had untolerated taint {%s: %s}", taint.Key, taint.Value)
73 return framework.NewStatus(framework.UnschedulableAndUnresolvable, errReason)
74 }
75
76
77 type preScoreState struct {
78 tolerationsPreferNoSchedule []v1.Toleration
79 }
80
81
82
83 func (s *preScoreState) Clone() framework.StateData {
84 return s
85 }
86
87
88 func getAllTolerationPreferNoSchedule(tolerations []v1.Toleration) (tolerationList []v1.Toleration) {
89 for _, toleration := range tolerations {
90
91 if len(toleration.Effect) == 0 || toleration.Effect == v1.TaintEffectPreferNoSchedule {
92 tolerationList = append(tolerationList, toleration)
93 }
94 }
95 return
96 }
97
98
99 func (pl *TaintToleration) PreScore(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodes []*framework.NodeInfo) *framework.Status {
100 if len(nodes) == 0 {
101 return nil
102 }
103 tolerationsPreferNoSchedule := getAllTolerationPreferNoSchedule(pod.Spec.Tolerations)
104 state := &preScoreState{
105 tolerationsPreferNoSchedule: tolerationsPreferNoSchedule,
106 }
107 cycleState.Write(preScoreStateKey, state)
108 return nil
109 }
110
111 func getPreScoreState(cycleState *framework.CycleState) (*preScoreState, error) {
112 c, err := cycleState.Read(preScoreStateKey)
113 if err != nil {
114 return nil, fmt.Errorf("failed to read %q from cycleState: %w", preScoreStateKey, err)
115 }
116
117 s, ok := c.(*preScoreState)
118 if !ok {
119 return nil, fmt.Errorf("%+v convert to tainttoleration.preScoreState error", c)
120 }
121 return s, nil
122 }
123
124
125 func countIntolerableTaintsPreferNoSchedule(taints []v1.Taint, tolerations []v1.Toleration) (intolerableTaints int) {
126 for _, taint := range taints {
127
128 if taint.Effect != v1.TaintEffectPreferNoSchedule {
129 continue
130 }
131
132 if !v1helper.TolerationsTolerateTaint(tolerations, &taint) {
133 intolerableTaints++
134 }
135 }
136 return
137 }
138
139
140 func (pl *TaintToleration) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
141 nodeInfo, err := pl.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
142 if err != nil {
143 return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err))
144 }
145 node := nodeInfo.Node()
146
147 s, err := getPreScoreState(state)
148 if err != nil {
149 return 0, framework.AsStatus(err)
150 }
151
152 score := int64(countIntolerableTaintsPreferNoSchedule(node.Spec.Taints, s.tolerationsPreferNoSchedule))
153 return score, nil
154 }
155
156
157 func (pl *TaintToleration) NormalizeScore(ctx context.Context, _ *framework.CycleState, pod *v1.Pod, scores framework.NodeScoreList) *framework.Status {
158 return helper.DefaultNormalizeScore(framework.MaxNodeScore, true, scores)
159 }
160
161
162 func (pl *TaintToleration) ScoreExtensions() framework.ScoreExtensions {
163 return pl
164 }
165
166
167 func New(_ context.Context, _ runtime.Object, h framework.Handle) (framework.Plugin, error) {
168 return &TaintToleration{handle: h}, nil
169 }
170
View as plain text