Skip to content

Commit 7f23ebe

Browse files
authored
Merge pull request kubernetes#124996 from Gekko0114/volumezone_hint_storageclass
volumezone: scheduler queueing hints: storageclass
2 parents c21aabf + ac15717 commit 7f23ebe

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

pkg/scheduler/framework/plugins/volumezone/volume_zone.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ func (pl *VolumeZone) EventsToRegister() []framework.ClusterEventWithHint {
276276
return []framework.ClusterEventWithHint{
277277
// New storageClass with bind mode `VolumeBindingWaitForFirstConsumer` will make a pod schedulable.
278278
// Due to immutable field `storageClass.volumeBindingMode`, storageClass update events are ignored.
279-
{Event: framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Add}},
279+
{Event: framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Add}, QueueingHintFn: pl.isSchedulableAfterStorageClassAdded},
280280
// A new node or updating a node's volume zone labels may make a pod schedulable.
281281
//
282282
// A note about UpdateNodeTaint event:
@@ -342,6 +342,23 @@ func (pl *VolumeZone) isPVCRequestedFromPod(logger klog.Logger, pvc *v1.Persiste
342342
return false
343343
}
344344

345+
// isSchedulableAfterStorageClassAdded is invoked whenever a StorageClass is added.
346+
// It checks whether the addition of StorageClass has made a previously unschedulable pod schedulable.
347+
// Only a new StorageClass with WaitForFirstConsumer will cause a pod to become schedulable.
348+
func (pl *VolumeZone) isSchedulableAfterStorageClassAdded(logger klog.Logger, pod *v1.Pod, oldObj, newObj interface{}) (framework.QueueingHint, error) {
349+
_, addedStorageClass, err := util.As[*storage.StorageClass](nil, newObj)
350+
if err != nil {
351+
return framework.Queue, fmt.Errorf("unexpected objects in isSchedulableAfterStorageClassAdded: %w", err)
352+
}
353+
if (addedStorageClass.VolumeBindingMode == nil) || (*addedStorageClass.VolumeBindingMode != storage.VolumeBindingWaitForFirstConsumer) {
354+
logger.V(5).Info("StorageClass is created, but its VolumeBindingMode is not waitForFirstConsumer, which doesn't make the pod schedulable", "storageClass", klog.KObj(addedStorageClass), "pod", klog.KObj(pod))
355+
return framework.QueueSkip, nil
356+
}
357+
358+
logger.V(5).Info("StorageClass with waitForFirstConsumer mode was created and it might make this pod schedulable", "pod", klog.KObj(pod), "StorageClass", klog.KObj(addedStorageClass))
359+
return framework.Queue, nil
360+
}
361+
345362
// New initializes a new plugin and returns it.
346363
func New(_ context.Context, _ runtime.Object, handle framework.Handle) (framework.Plugin, error) {
347364
informerFactory := handle.SharedInformerFactory()

pkg/scheduler/framework/plugins/volumezone/volume_zone_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,54 @@ func TestIsSchedulableAfterPersistentVolumeClaimAdded(t *testing.T) {
627627
}
628628
}
629629

630+
func TestIsSchedulableAfterStorageClassAdded(t *testing.T) {
631+
var modeWait = storagev1.VolumeBindingWaitForFirstConsumer
632+
633+
testcases := map[string]struct {
634+
pod *v1.Pod
635+
oldObj, newObj interface{}
636+
expectedHint framework.QueueingHint
637+
expectedErr bool
638+
}{
639+
"error-wrong-new-object": {
640+
pod: createPodWithVolume("pod_1", "PVC_1"),
641+
newObj: "not-a-storageclass",
642+
expectedHint: framework.Queue,
643+
expectedErr: true,
644+
},
645+
"sc-doesn't-have-volume-binding-mode": {
646+
pod: createPodWithVolume("pod_1", "PVC_1"),
647+
newObj: &storagev1.StorageClass{
648+
ObjectMeta: metav1.ObjectMeta{Name: "SC_1"},
649+
},
650+
expectedHint: framework.QueueSkip,
651+
},
652+
"new-sc-is-wait-for-first-consumer-mode": {
653+
pod: createPodWithVolume("pod_1", "PVC_1"),
654+
newObj: &storagev1.StorageClass{
655+
ObjectMeta: metav1.ObjectMeta{Name: "SC_1"},
656+
VolumeBindingMode: &modeWait,
657+
},
658+
expectedHint: framework.Queue,
659+
},
660+
}
661+
662+
for name, tc := range testcases {
663+
t.Run(name, func(t *testing.T) {
664+
logger, _ := ktesting.NewTestContext(t)
665+
p := &VolumeZone{}
666+
667+
got, err := p.isSchedulableAfterStorageClassAdded(logger, tc.pod, tc.oldObj, tc.newObj)
668+
if err != nil && !tc.expectedErr {
669+
t.Errorf("unexpected error: %v", err)
670+
}
671+
if got != tc.expectedHint {
672+
t.Errorf("isSchedulableAfterStorageClassAdded() = %v, want %v", got, tc.expectedHint)
673+
}
674+
})
675+
}
676+
}
677+
630678
func BenchmarkVolumeZone(b *testing.B) {
631679
tests := []struct {
632680
Name string

0 commit comments

Comments
 (0)