@@ -23,8 +23,8 @@ import (
23
23
"time"
24
24
25
25
v1 "k8s.io/api/core/v1"
26
- "k8s.io/apimachinery/pkg/api/resource"
27
26
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
+ "k8s.io/apimachinery/pkg/util/sets"
28
28
"k8s.io/apimachinery/pkg/util/uuid"
29
29
"k8s.io/apimachinery/pkg/util/wait"
30
30
"k8s.io/client-go/kubernetes"
@@ -34,137 +34,166 @@ import (
34
34
st "k8s.io/kubernetes/pkg/scheduler/testing"
35
35
imageutils "k8s.io/kubernetes/test/utils/image"
36
36
37
+ schedconfig "sigs.k8s.io/scheduler-plugins/apis/config"
37
38
"sigs.k8s.io/scheduler-plugins/pkg/noderesources"
38
39
"sigs.k8s.io/scheduler-plugins/test/util"
39
40
)
40
41
41
42
func TestAllocatablePlugin (t * testing.T ) {
42
- testCtx := & testContext {}
43
- testCtx .Ctx , testCtx .CancelFn = context .WithCancel (context .Background ())
44
43
45
- cs := kubernetes .NewForConfigOrDie (globalKubeConfig )
46
- testCtx .ClientSet = cs
47
- testCtx .KubeConfig = globalKubeConfig
48
-
49
- cfg , err := util .NewDefaultSchedulerComponentConfig ()
50
- if err != nil {
51
- t .Fatal (err )
44
+ smallNodeCapacity := map [v1.ResourceName ]string {
45
+ v1 .ResourcePods : "32" ,
46
+ v1 .ResourceCPU : "500m" ,
47
+ v1 .ResourceMemory : "500" ,
52
48
}
53
- // Work around https://github.com/kubernetes/kubernetes/issues/121630.
54
- cfg .Profiles [0 ].Plugins .PreScore = schedapi.PluginSet {
55
- Disabled : []schedapi.Plugin {{Name : "*" }},
49
+ bigNodeCapacity := map [v1.ResourceName ]string {
50
+ v1 .ResourcePods : "32" ,
51
+ v1 .ResourceCPU : "500m" ,
52
+ v1 .ResourceMemory : "5000" ,
56
53
}
57
- cfg .Profiles [0 ].Plugins .Score = schedapi.PluginSet {
58
- Enabled : []schedapi.Plugin {{Name : noderesources .AllocatableName , Weight : 50000 }},
59
- Disabled : []schedapi.Plugin {{Name : "*" }},
54
+ smallPodReq := map [v1.ResourceName ]string {
55
+ v1 .ResourceMemory : "100" ,
60
56
}
61
-
62
- ns := fmt .Sprintf ("integration-test-%v" , string (uuid .NewUUID ()))
63
- createNamespace (t , testCtx , ns )
64
-
65
- testCtx = initTestSchedulerWithOptions (
66
- t ,
67
- testCtx ,
68
- scheduler .WithProfiles (cfg .Profiles ... ),
69
- scheduler .WithFrameworkOutOfTreeRegistry (fwkruntime.Registry {noderesources .AllocatableName : noderesources .NewAllocatable }),
70
- )
71
- syncInformerFactory (testCtx )
72
- go testCtx .Scheduler .Run (testCtx .Ctx )
73
- defer cleanupTest (t , testCtx )
74
-
75
- // Create nodes. First two are small nodes.
76
- bigNodeName := "fake-node-big"
77
- nodeNames := []string {"fake-node-small-1" , "fake-node-small-2" , bigNodeName }
78
- for _ , nodeName := range nodeNames {
79
- var memory int64 = 200
80
- if nodeName == bigNodeName {
81
- memory = 5000
82
- }
83
- node := st .MakeNode ().Name (nodeName ).Label ("node" , nodeName ).Obj ()
84
- node .Status .Allocatable = v1.ResourceList {
85
- v1 .ResourcePods : * resource .NewQuantity (32 , resource .DecimalSI ),
86
- v1 .ResourceCPU : * resource .NewMilliQuantity (500 , resource .DecimalSI ),
87
- v1 .ResourceMemory : * resource .NewQuantity (memory , resource .DecimalSI ),
88
- }
89
- node .Status .Capacity = v1.ResourceList {
90
- v1 .ResourcePods : * resource .NewQuantity (32 , resource .DecimalSI ),
91
- v1 .ResourceCPU : * resource .NewMilliQuantity (500 , resource .DecimalSI ),
92
- v1 .ResourceMemory : * resource .NewQuantity (memory , resource .DecimalSI ),
93
- }
94
- node , err := cs .CoreV1 ().Nodes ().Create (testCtx .Ctx , node , metav1.CreateOptions {})
95
- if err != nil {
96
- t .Fatalf ("Failed to create Node %q: %v" , nodeName , err )
97
- }
57
+ bigPodReq := map [v1.ResourceName ]string {
58
+ v1 .ResourceMemory : "2000" ,
98
59
}
99
60
100
- // Create Pods.
101
- var pods []* v1.Pod
102
- podNames := []string {"small-1" , "small-2" , "small-3" , "small-4" }
103
- pause := imageutils .GetPauseImageName ()
104
- for i := 0 ; i < len (podNames ); i ++ {
105
- pod := st .MakePod ().Namespace (ns ).Name (podNames [i ]).Container (pause ).Obj ()
106
- pod .Spec .Containers [0 ].Resources = v1.ResourceRequirements {
107
- Requests : v1.ResourceList {
108
- v1 .ResourceMemory : * resource .NewQuantity (100 , resource .DecimalSI ),
61
+ testCases := []struct {
62
+ name string
63
+ pods []* v1.Pod
64
+ nodes []* v1.Node
65
+ modeType schedconfig.ModeType
66
+ expectedNodes map [string ]sets.Set [string ] // pod name to expected node name mapping
67
+ }{
68
+ {
69
+ name : "least modeType the small pods should land on the small nodes and the big pod should land on the big node" ,
70
+ pods : []* v1.Pod {
71
+ st .MakePod ().Name ("small-1" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
72
+ st .MakePod ().Name ("small-2" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
73
+ st .MakePod ().Name ("small-3" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
74
+ st .MakePod ().Name ("small-4" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
75
+ st .MakePod ().Name ("big-1" ).Container (imageutils .GetPauseImageName ()).Req (bigPodReq ).Obj (),
109
76
},
110
- }
111
- pods = append (pods , pod )
112
- }
113
-
114
- // Make a big pod.
115
- podNames = append (podNames , "big-1" )
116
- pod := st .MakePod ().Namespace (ns ).Name ("big-1" ).Container (pause ).Obj ()
117
- pod .Spec .Containers [0 ].Resources = v1.ResourceRequirements {
118
- Requests : v1.ResourceList {
119
- v1 .ResourceMemory : * resource .NewQuantity (5000 , resource .DecimalSI ),
77
+ nodes : []* v1.Node {
78
+ st .MakeNode ().Name ("fake-node-small-1" ).Label ("node" , "fake-node-small-1" ).Capacity (smallNodeCapacity ).Obj (),
79
+ st .MakeNode ().Name ("fake-node-small-2" ).Label ("node" , "fake-node-small-2" ).Capacity (smallNodeCapacity ).Obj (),
80
+ st .MakeNode ().Name ("fake-node-big" ).Label ("node" , "fake-node-big" ).Capacity (bigNodeCapacity ).Obj (),
81
+ },
82
+ expectedNodes : map [string ]sets.Set [string ]{
83
+ "small-1" : sets .New ("fake-node-small-1" , "fake-node-small-2" ),
84
+ "small-2" : sets .New ("fake-node-small-1" , "fake-node-small-2" ),
85
+ "small-3" : sets .New ("fake-node-small-1" , "fake-node-small-2" ),
86
+ "small-4" : sets .New ("fake-node-small-1" , "fake-node-small-2" ),
87
+ "big-1" : sets .New ("fake-node-big" ),
88
+ },
89
+ modeType : schedconfig .Least ,
90
+ },
91
+ {
92
+ name : "most modeType the small pods should land on the big node and the big pod should also land on the big node" ,
93
+ pods : []* v1.Pod {
94
+ st .MakePod ().Name ("small-1" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
95
+ st .MakePod ().Name ("small-2" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
96
+ st .MakePod ().Name ("small-3" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
97
+ st .MakePod ().Name ("small-4" ).Container (imageutils .GetPauseImageName ()).Req (smallPodReq ).Obj (),
98
+ st .MakePod ().Name ("big-1" ).Container (imageutils .GetPauseImageName ()).Req (bigPodReq ).Obj (),
99
+ },
100
+ nodes : []* v1.Node {
101
+ st .MakeNode ().Name ("fake-node-small-1" ).Label ("node" , "fake-node-small-1" ).Capacity (smallNodeCapacity ).Obj (),
102
+ st .MakeNode ().Name ("fake-node-small-2" ).Label ("node" , "fake-node-small-2" ).Capacity (smallNodeCapacity ).Obj (),
103
+ st .MakeNode ().Name ("fake-node-big" ).Label ("node" , "fake-node-big" ).Capacity (bigNodeCapacity ).Obj (),
104
+ },
105
+ expectedNodes : map [string ]sets.Set [string ]{
106
+ "small-1" : sets .New ("fake-node-big" ),
107
+ "small-2" : sets .New ("fake-node-big" ),
108
+ "small-3" : sets .New ("fake-node-big" ),
109
+ "small-4" : sets .New ("fake-node-big" ),
110
+ "big-1" : sets .New ("fake-node-big" ),
111
+ },
112
+ modeType : schedconfig .Most ,
120
113
},
121
114
}
122
- pods = append (pods , pod )
123
-
124
- // Create the Pods. By default, the small pods should land on the small nodes.
125
- t .Logf ("Start to create 5 Pods." )
126
- for i := range pods {
127
- t .Logf ("Creating Pod %q" , pods [i ].Name )
128
- _ , err := cs .CoreV1 ().Pods (ns ).Create (testCtx .Ctx , pods [i ], metav1.CreateOptions {})
129
- if err != nil {
130
- t .Fatalf ("Failed to create Pod %q: %v" , pods [i ].Name , err )
131
- }
132
- }
133
- defer cleanupPods (t , testCtx , pods )
134
115
135
- for i := range pods {
136
- // Wait for the pod to be scheduled.
137
- err := wait .PollUntilContextTimeout (testCtx .Ctx , 1 * time .Second , 60 * time .Second , false , func (ctx context.Context ) (bool , error ) {
138
- return podScheduled (t , cs , pods [i ].Namespace , pods [i ].Name ), nil
139
- })
140
- if err != nil {
141
- t .Fatalf ("Waiting for pod %q to be scheduled, error: %v" , pods [i ].Name , err .Error ())
142
- }
143
-
144
- pod , err := cs .CoreV1 ().Pods (ns ).Get (testCtx .Ctx , pods [i ].Name , metav1.GetOptions {})
145
- if err != nil {
146
- t .Fatal (err )
147
- }
148
-
149
- // The big pod should be scheduled on the big node.
150
- if pod .Name == "big-1" {
151
- if pod .Spec .NodeName == bigNodeName {
152
- t .Logf ("Pod %q is on the big node as expected." , pod .Name )
153
- continue
154
- } else {
155
- t .Errorf ("Pod %q is expected on node %q, but found on node %q" ,
156
- pod .Name , bigNodeName , pod .Spec .NodeName )
116
+ for _ , tc := range testCases {
117
+ t .Run (tc .name , func (t * testing.T ) {
118
+ testCtx := & testContext {}
119
+ testCtx .Ctx , testCtx .CancelFn = context .WithCancel (context .Background ())
120
+
121
+ cs := kubernetes .NewForConfigOrDie (globalKubeConfig )
122
+ testCtx .ClientSet = cs
123
+ testCtx .KubeConfig = globalKubeConfig
124
+
125
+ cfg , err := util .NewDefaultSchedulerComponentConfig ()
126
+ if err != nil {
127
+ t .Fatal (err )
128
+ }
129
+ cfg .Profiles [0 ].Plugins .PreScore = schedapi.PluginSet {Disabled : []schedapi.Plugin {{Name : "*" }}}
130
+ cfg .Profiles [0 ].Plugins .Score = schedapi.PluginSet {
131
+ Enabled : []schedapi.Plugin {{Name : noderesources .AllocatableName , Weight : 50000 }},
132
+ Disabled : []schedapi.Plugin {{Name : "*" }},
133
+ }
134
+
135
+ cfg .Profiles [0 ].PluginConfig = append (cfg .Profiles [0 ].PluginConfig , schedapi.PluginConfig {
136
+ Name : noderesources .AllocatableName ,
137
+ Args : & schedconfig.NodeResourcesAllocatableArgs {
138
+ Mode : tc .modeType ,
139
+ Resources : []schedapi.ResourceSpec {
140
+ {Name : string (v1 .ResourceMemory ), Weight : 10 },
141
+ },
142
+ },
143
+ })
144
+
145
+ ns := fmt .Sprintf ("integration-test-%v" , string (uuid .NewUUID ()))
146
+ createNamespace (t , testCtx , ns )
147
+
148
+ testCtx = initTestSchedulerWithOptions (
149
+ t ,
150
+ testCtx ,
151
+ scheduler .WithProfiles (cfg .Profiles ... ),
152
+ scheduler .WithFrameworkOutOfTreeRegistry (fwkruntime.Registry {noderesources .AllocatableName : noderesources .NewAllocatable }),
153
+ )
154
+ syncInformerFactory (testCtx )
155
+ go testCtx .Scheduler .Run (testCtx .Ctx )
156
+ defer cleanupTest (t , testCtx )
157
+
158
+ // Create nodes.
159
+ for _ , node := range tc .nodes {
160
+ _ , err := cs .CoreV1 ().Nodes ().Create (testCtx .Ctx , node , metav1.CreateOptions {})
161
+ if err != nil {
162
+ t .Fatalf ("Failed to create Node %q: %v" , node .Name , err )
163
+ }
164
+ }
165
+
166
+ // Create the Pods.
167
+ for _ , pod := range tc .pods {
168
+ // set namespace to pods
169
+ pod .SetNamespace (ns )
170
+ _ , err := cs .CoreV1 ().Pods (ns ).Create (testCtx .Ctx , pod , metav1.CreateOptions {})
171
+ if err != nil {
172
+ t .Fatalf ("Failed to create Pod %q: %v" , pod .Name , err )
173
+ }
157
174
}
158
- }
159
-
160
- // The other pods should be scheduled on the small nodes.
161
- if pod .Spec .NodeName == nodeNames [0 ] ||
162
- pod .Spec .NodeName == nodeNames [1 ] {
163
- t .Logf ("Pod %q is on a small node as expected." , pod .Name )
164
- continue
165
- } else {
166
- t .Errorf ("Pod %q is on node %q when it was expected on a small node" ,
167
- pod .Name , pod .Spec .NodeName )
168
- }
175
+ defer cleanupPods (t , testCtx , tc .pods )
176
+
177
+ for _ , pod := range tc .pods {
178
+ err := wait .PollUntilContextTimeout (testCtx .Ctx , 1 * time .Second , 60 * time .Second , false , func (ctx context.Context ) (bool , error ) {
179
+ return podScheduled (t , cs , pod .Namespace , pod .Name ), nil
180
+ })
181
+ if err != nil {
182
+ t .Fatalf ("Waiting for pod %q to be scheduled, error: %v" , pod .Name , err .Error ())
183
+ }
184
+
185
+ scheduledPod , err := cs .CoreV1 ().Pods (ns ).Get (testCtx .Ctx , pod .Name , metav1.GetOptions {})
186
+ if err != nil {
187
+ t .Fatal (err )
188
+ }
189
+
190
+ expectedNodes , exists := tc .expectedNodes [pod .Name ]
191
+ if ! exists || ! expectedNodes .Has (scheduledPod .Spec .NodeName ) {
192
+ t .Errorf ("Pod %q is expected on node %q, but found on node %q" , pod .Name , expectedNodes .UnsortedList (), scheduledPod .Spec .NodeName )
193
+ } else {
194
+ t .Logf ("Pod %q is on node %q as expected." , pod .Name , scheduledPod .Spec .NodeName )
195
+ }
196
+ }
197
+ })
169
198
}
170
199
}
0 commit comments