1
16
17 package noderesources
18
19 import (
20 "context"
21 "fmt"
22 "math"
23
24 v1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/kubernetes/pkg/scheduler/apis/config"
27 "k8s.io/kubernetes/pkg/scheduler/apis/config/validation"
28 "k8s.io/kubernetes/pkg/scheduler/framework"
29 "k8s.io/kubernetes/pkg/scheduler/framework/plugins/feature"
30 "k8s.io/kubernetes/pkg/scheduler/framework/plugins/names"
31 )
32
33
34
35 type BalancedAllocation struct {
36 handle framework.Handle
37 resourceAllocationScorer
38 }
39
40 var _ framework.PreScorePlugin = &BalancedAllocation{}
41 var _ framework.ScorePlugin = &BalancedAllocation{}
42
43
44 const (
45 BalancedAllocationName = names.NodeResourcesBalancedAllocation
46
47
48 balancedAllocationPreScoreStateKey = "PreScore" + BalancedAllocationName
49 )
50
51
52 type balancedAllocationPreScoreState struct {
53
54
55 podRequests []int64
56 }
57
58
59
60 func (s *balancedAllocationPreScoreState) Clone() framework.StateData {
61 return s
62 }
63
64
65 func (ba *BalancedAllocation) PreScore(ctx context.Context, cycleState *framework.CycleState, pod *v1.Pod, nodes []*framework.NodeInfo) *framework.Status {
66 state := &balancedAllocationPreScoreState{
67 podRequests: ba.calculatePodResourceRequestList(pod, ba.resources),
68 }
69 cycleState.Write(balancedAllocationPreScoreStateKey, state)
70 return nil
71 }
72
73 func getBalancedAllocationPreScoreState(cycleState *framework.CycleState) (*balancedAllocationPreScoreState, error) {
74 c, err := cycleState.Read(balancedAllocationPreScoreStateKey)
75 if err != nil {
76 return nil, fmt.Errorf("reading %q from cycleState: %w", balancedAllocationPreScoreStateKey, err)
77 }
78
79 s, ok := c.(*balancedAllocationPreScoreState)
80 if !ok {
81 return nil, fmt.Errorf("invalid PreScore state, got type %T", c)
82 }
83 return s, nil
84 }
85
86
87 func (ba *BalancedAllocation) Name() string {
88 return BalancedAllocationName
89 }
90
91
92 func (ba *BalancedAllocation) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
93 nodeInfo, err := ba.handle.SnapshotSharedLister().NodeInfos().Get(nodeName)
94 if err != nil {
95 return 0, framework.AsStatus(fmt.Errorf("getting node %q from Snapshot: %w", nodeName, err))
96 }
97
98 s, err := getBalancedAllocationPreScoreState(state)
99 if err != nil {
100 s = &balancedAllocationPreScoreState{podRequests: ba.calculatePodResourceRequestList(pod, ba.resources)}
101 }
102
103
104
105
106
107
108 return ba.score(ctx, pod, nodeInfo, s.podRequests)
109 }
110
111
112 func (ba *BalancedAllocation) ScoreExtensions() framework.ScoreExtensions {
113 return nil
114 }
115
116
117 func NewBalancedAllocation(_ context.Context, baArgs runtime.Object, h framework.Handle, fts feature.Features) (framework.Plugin, error) {
118 args, ok := baArgs.(*config.NodeResourcesBalancedAllocationArgs)
119 if !ok {
120 return nil, fmt.Errorf("want args to be of type NodeResourcesBalancedAllocationArgs, got %T", baArgs)
121 }
122
123 if err := validation.ValidateNodeResourcesBalancedAllocationArgs(nil, args); err != nil {
124 return nil, err
125 }
126
127 return &BalancedAllocation{
128 handle: h,
129 resourceAllocationScorer: resourceAllocationScorer{
130 Name: BalancedAllocationName,
131 scorer: balancedResourceScorer,
132 useRequested: true,
133 resources: args.Resources,
134 },
135 }, nil
136 }
137
138 func balancedResourceScorer(requested, allocable []int64) int64 {
139 var resourceToFractions []float64
140 var totalFraction float64
141 for i := range requested {
142 if allocable[i] == 0 {
143 continue
144 }
145 fraction := float64(requested[i]) / float64(allocable[i])
146 if fraction > 1 {
147 fraction = 1
148 }
149 totalFraction += fraction
150 resourceToFractions = append(resourceToFractions, fraction)
151 }
152
153 std := 0.0
154
155
156
157
158 if len(resourceToFractions) == 2 {
159 std = math.Abs((resourceToFractions[0] - resourceToFractions[1]) / 2)
160
161 } else if len(resourceToFractions) > 2 {
162 mean := totalFraction / float64(len(resourceToFractions))
163 var sum float64
164 for _, fraction := range resourceToFractions {
165 sum = sum + (fraction-mean)*(fraction-mean)
166 }
167 std = math.Sqrt(sum / float64(len(resourceToFractions)))
168 }
169
170
171
172 return int64((1 - std) * float64(framework.MaxNodeScore))
173 }
174
View as plain text