@@ -35,6 +35,8 @@ import (
35
35
"k8s.io/klog/v2"
36
36
"k8s.io/kubernetes/pkg/scheduler"
37
37
schedapi "k8s.io/kubernetes/pkg/scheduler/apis/config"
38
+ "k8s.io/kubernetes/pkg/scheduler/framework/plugins/defaultbinder"
39
+ "k8s.io/kubernetes/pkg/scheduler/framework/plugins/queuesort"
38
40
fwkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
39
41
st "k8s.io/kubernetes/pkg/scheduler/testing"
40
42
@@ -50,24 +52,26 @@ import (
50
52
const (
51
53
defaultCacheResyncPeriodSeconds int64 = 5
52
54
anyNode = "*"
55
+ discardReservedSchedulerName = "discardReserved"
53
56
)
54
57
55
58
var (
56
59
schedVerbose = "0"
57
60
)
58
61
59
62
type podDesc struct {
60
- podName string
61
- isGuaranteed bool
62
- isDelete bool
63
- resourcesMap map [string ]string
64
- expectedNode string
63
+ schedulerName string
64
+ podName string
65
+ isGuaranteed bool
66
+ isDelete bool
67
+ resourcesMap map [string ]string
68
+ expectedNode string
65
69
// autogenerated
66
70
pod * corev1.Pod
67
71
}
68
72
69
73
func (p * podDesc ) SetupPod (ns string , initContainer bool ) {
70
- pt := st .MakePod ().Namespace (ns ).Name (p .podName )
74
+ pt := st .MakePod ().Namespace (ns ).Name (p .podName ). SchedulerName ( p . schedulerName )
71
75
if p .isGuaranteed {
72
76
p .pod = util .WithLimits (pt , p .resourcesMap , initContainer ).Obj ()
73
77
} else {
@@ -264,6 +268,109 @@ func TestTopologyCachePluginWithoutUpdates(t *testing.T) {
264
268
}).Obj (),
265
269
},
266
270
},
271
+ {
272
+ name : "GU pod: DiscardReservedNodes: allows scheduling on both Zones" ,
273
+ podDescs : []podDesc {
274
+ {
275
+ podName : "nrt-pod-1000" ,
276
+ isGuaranteed : true ,
277
+ resourcesMap : map [string ]string {
278
+ string (corev1 .ResourceCPU ): "16" ,
279
+ string (corev1 .ResourceMemory ): "24Gi" ,
280
+ },
281
+ expectedNode : "fake-node-cache-1" ,
282
+ schedulerName : discardReservedSchedulerName ,
283
+ },
284
+ {
285
+ podName : "nrt-pod-2000" ,
286
+ isGuaranteed : true ,
287
+ resourcesMap : map [string ]string {
288
+ string (corev1 .ResourceCPU ): "16" ,
289
+ string (corev1 .ResourceMemory ): "24Gi" ,
290
+ },
291
+ schedulerName : discardReservedSchedulerName ,
292
+ expectedNode : "fake-node-cache-1" ,
293
+ },
294
+ },
295
+ nodeResourceTopologies : []* topologyv1alpha2.NodeResourceTopology {
296
+ MakeNRT ().Name ("fake-node-cache-1" ).Policy (topologyv1alpha2 .SingleNUMANodeContainerLevel ).
297
+ Zone (
298
+ topologyv1alpha2.ResourceInfoList {
299
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "30" ),
300
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "60Gi" ),
301
+ }).
302
+ Zone (
303
+ topologyv1alpha2.ResourceInfoList {
304
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "30" ),
305
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "62Gi" ),
306
+ }).Obj (),
307
+ MakeNRT ().Name ("fake-node-cache-2" ).Policy (topologyv1alpha2 .SingleNUMANodeContainerLevel ).
308
+ Zone (
309
+ topologyv1alpha2.ResourceInfoList {
310
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "10" ),
311
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "14Gi" ),
312
+ }).
313
+ Zone (
314
+ topologyv1alpha2.ResourceInfoList {
315
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "8" ),
316
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "10Gi" ),
317
+ }).Obj (),
318
+ },
319
+ },
320
+ {
321
+ name : "GU pod: DiscardReservedNodes: new pod is successfully scheduled on the node, after deleting pod consuming most resources" ,
322
+ podDescs : []podDesc {
323
+ {
324
+ podName : "nrt-pod-3000" ,
325
+ isGuaranteed : true ,
326
+ resourcesMap : map [string ]string {
327
+ string (corev1 .ResourceCPU ): "30" ,
328
+ string (corev1 .ResourceMemory ): "60Gi" ,
329
+ },
330
+ schedulerName : discardReservedSchedulerName ,
331
+ expectedNode : "fake-node-cache-1" ,
332
+ },
333
+ {
334
+ podName : "nrt-pod-3000" ,
335
+ isDelete : true ,
336
+ schedulerName : "discardReserved" ,
337
+ },
338
+ {
339
+ podName : "nrt-pod-4000" ,
340
+ isGuaranteed : true ,
341
+ resourcesMap : map [string ]string {
342
+ string (corev1 .ResourceCPU ): "16" ,
343
+ string (corev1 .ResourceMemory ): "24Gi" ,
344
+ },
345
+ schedulerName : discardReservedSchedulerName ,
346
+ expectedNode : "fake-node-cache-1" ,
347
+ },
348
+ },
349
+ nodeResourceTopologies : []* topologyv1alpha2.NodeResourceTopology {
350
+ MakeNRT ().Name ("fake-node-cache-1" ).Policy (topologyv1alpha2 .SingleNUMANodeContainerLevel ).
351
+ Zone (
352
+ topologyv1alpha2.ResourceInfoList {
353
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "30" ),
354
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "60Gi" ),
355
+ }).
356
+ Zone (
357
+ topologyv1alpha2.ResourceInfoList {
358
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "30" ),
359
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "62Gi" ),
360
+ }).Obj (),
361
+ MakeNRT ().Name ("fake-node-cache-2" ).Policy (topologyv1alpha2 .SingleNUMANodeContainerLevel ).
362
+ Zone (
363
+ topologyv1alpha2.ResourceInfoList {
364
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "10" ),
365
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "14Gi" ),
366
+ }).
367
+ Zone (
368
+ topologyv1alpha2.ResourceInfoList {
369
+ noderesourcetopology .MakeTopologyResInfo (cpu , "32" , "8" ),
370
+ noderesourcetopology .MakeTopologyResInfo (memory , "64Gi" , "10Gi" ),
371
+ }).Obj (),
372
+ },
373
+ },
267
374
} {
268
375
t .Run (tt .name , func (t * testing.T ) {
269
376
// because caching, each testcase needs to run from a clean slate
@@ -297,6 +404,8 @@ func TestTopologyCachePluginWithoutUpdates(t *testing.T) {
297
404
},
298
405
})
299
406
407
+ cfg .Profiles = append (cfg .Profiles , discardReservedSchedulerProfile ())
408
+
300
409
defer func () {
301
410
cleanupTest (t , testCtx )
302
411
klog .Infof ("test environment cleaned up" )
@@ -356,7 +465,7 @@ func TestTopologyCachePluginWithoutUpdates(t *testing.T) {
356
465
t .Fatalf ("Failed to delete Pod %q: %v" , p .podName , err )
357
466
}
358
467
} else {
359
- klog .Infof ("Creating Pod %q" , p .pod .Name )
468
+ klog .Infof ("Creating Pod %q: scheduler: %q " , p .pod .Name , p . pod . Spec . SchedulerName )
360
469
_ , err := cs .CoreV1 ().Pods (ns ).Create (testCtx .Ctx , p .pod , metav1.CreateOptions {})
361
470
if err != nil {
362
471
t .Fatalf ("Failed to create Pod %q: %v" , p .pod .Name , err )
@@ -698,3 +807,52 @@ func mkPFP(nodeName string, pods ...*corev1.Pod) string {
698
807
klog .Infof ("PFP for %q: %s" , nodeName , st .Repr ())
699
808
return pfp
700
809
}
810
+
811
+ func discardReservedSchedulerProfile () schedapi.KubeSchedulerProfile {
812
+ nodeLockingMatchArgs := schedconfig.NodeResourceTopologyMatchArgs {
813
+ ScoringStrategy : schedconfig.ScoringStrategy {Type : schedconfig .LeastAllocated },
814
+ DiscardReservedNodes : true ,
815
+ }
816
+
817
+ return schedapi.KubeSchedulerProfile {
818
+ SchedulerName : discardReservedSchedulerName ,
819
+ Plugins : & schedapi.Plugins {
820
+ QueueSort : schedapi.PluginSet {
821
+ Enabled : []schedapi.Plugin {
822
+ {Name : queuesort .Name },
823
+ },
824
+ },
825
+ Filter : schedapi.PluginSet {
826
+ Enabled : []schedapi.Plugin {
827
+ {Name : noderesourcetopology .Name },
828
+ },
829
+ },
830
+ Score : schedapi.PluginSet {
831
+ Enabled : []schedapi.Plugin {
832
+ {Name : noderesourcetopology .Name },
833
+ },
834
+ },
835
+ Reserve : schedapi.PluginSet {
836
+ Enabled : []schedapi.Plugin {
837
+ {Name : noderesourcetopology .Name },
838
+ },
839
+ },
840
+ PostBind : schedapi.PluginSet {
841
+ Enabled : []schedapi.Plugin {
842
+ {Name : noderesourcetopology .Name },
843
+ },
844
+ },
845
+ Bind : schedapi.PluginSet {
846
+ Enabled : []schedapi.Plugin {
847
+ {Name : defaultbinder .Name },
848
+ },
849
+ },
850
+ },
851
+ PluginConfig : []schedapi.PluginConfig {
852
+ {
853
+ Name : noderesourcetopology .Name ,
854
+ Args : & nodeLockingMatchArgs ,
855
+ },
856
+ },
857
+ }
858
+ }
0 commit comments