diff --git a/pkg/scheduler/eventhandlers.go b/pkg/scheduler/eventhandlers.go index 3d9ae24234e..ead032b6081 100644 --- a/pkg/scheduler/eventhandlers.go +++ b/pkg/scheduler/eventhandlers.go @@ -362,6 +362,14 @@ func addAllEventHandlers( informerFactory.Storage().V1().CSINodes().Informer().AddEventHandler( buildEvtResHandler(at, framework.CSINode, "CSINode"), ) + case framework.CSIDriver: + informerFactory.Storage().V1().CSIDrivers().Informer().AddEventHandler( + buildEvtResHandler(at, framework.CSIDriver, "CSIDriver"), + ) + case framework.CSIStorageCapacity: + informerFactory.Storage().V1beta1().CSIStorageCapacities().Informer().AddEventHandler( + buildEvtResHandler(at, framework.CSIStorageCapacity, "CSIStorageCapacity"), + ) case framework.PersistentVolume: // MaxPDVolumeCountPredicate: since it relies on the counts of PV. // @@ -392,6 +400,15 @@ func addAllEventHandlers( }, ) } + if at&framework.Update != 0 { + informerFactory.Storage().V1().StorageClasses().Informer().AddEventHandler( + cache.ResourceEventHandlerFuncs{ + UpdateFunc: func(_, _ interface{}) { + sched.SchedulingQueue.MoveAllToActiveOrBackoffQueue(queue.StorageClassUpdate, nil) + }, + }, + ) + } case framework.Service: // ServiceAffinity: affected by the selector of the service is updated. // Also, if new service is added, equivalence cache will also become invalid since diff --git a/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go b/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go index 9b9e9b19a32..d4da8b6c0b7 100644 --- a/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go +++ b/pkg/scheduler/framework/plugins/volumebinding/volume_binding.go @@ -81,6 +81,7 @@ var _ framework.FilterPlugin = &VolumeBinding{} var _ framework.ReservePlugin = &VolumeBinding{} var _ framework.PreBindPlugin = &VolumeBinding{} var _ framework.ScorePlugin = &VolumeBinding{} +var _ framework.EnqueueExtensions = &VolumeBinding{} // Name is the name of the plugin used in Registry and configurations. const Name = names.VolumeBinding @@ -90,6 +91,35 @@ func (pl *VolumeBinding) Name() string { return Name } +// EventsToRegister returns the possible events that may make a Pod +// failed by this plugin schedulable. +func (pl *VolumeBinding) EventsToRegister() []framework.ClusterEvent { + events := []framework.ClusterEvent{ + // Pods may fail because of missing or mis-configured storage class + // (e.g., allowedTopologies, volumeBindingMode), and hence may become + // schedulable upon StorageClass Add or Update events. + {Resource: framework.StorageClass, ActionType: framework.Add | framework.Update}, + // We bind PVCs with PVs, so any changes may make the pods schedulable. + {Resource: framework.PersistentVolumeClaim, ActionType: framework.Add | framework.Update}, + {Resource: framework.PersistentVolume, ActionType: framework.Add | framework.Update}, + // Pods may fail to find available PVs because the node labels do not + // match the storage class's allowed topologies or PV's node affinity. + // A new or updated node may make pods schedulable. + {Resource: framework.Node, ActionType: framework.Add | framework.Update}, + // We rely on CSI node to translate in-tree PV to CSI. + {Resource: framework.CSINode, ActionType: framework.Add | framework.Update}, + } + if utilfeature.DefaultFeatureGate.Enabled(features.CSIStorageCapacity) { + // When CSIStorageCapacity is enabled, pods may become schedulable + // on CSI driver & storage capacity changes. + events = append(events, []framework.ClusterEvent{ + {Resource: framework.CSIDriver, ActionType: framework.Add | framework.Update}, + {Resource: framework.CSIStorageCapacity, ActionType: framework.Add | framework.Update}, + }...) + } + return events +} + // podHasPVCs returns 2 values: // - the first one to denote if the given "pod" has any PVC defined. // - the second one to return any error if the requested PVC is illegal. diff --git a/pkg/scheduler/framework/types.go b/pkg/scheduler/framework/types.go index a37b27b45ce..34c9dfb16e1 100644 --- a/pkg/scheduler/framework/types.go +++ b/pkg/scheduler/framework/types.go @@ -69,6 +69,8 @@ const ( Service GVK = "Service" StorageClass GVK = "storage.k8s.io/StorageClass" CSINode GVK = "storage.k8s.io/CSINode" + CSIDriver GVK = "storage.k8s.io/CSIDriver" + CSIStorageCapacity GVK = "storage.k8s.io/CSIStorageCapacity" WildCard GVK = "*" ) diff --git a/pkg/scheduler/internal/queue/events.go b/pkg/scheduler/internal/queue/events.go index 278d3d5de22..7954ee55e51 100644 --- a/pkg/scheduler/internal/queue/events.go +++ b/pkg/scheduler/internal/queue/events.go @@ -61,10 +61,20 @@ var ( PvcUpdate = framework.ClusterEvent{Resource: framework.PersistentVolumeClaim, ActionType: framework.Update, Label: "PvcUpdate"} // StorageClassAdd is the event when a StorageClass is added in the cluster. StorageClassAdd = framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Add, Label: "StorageClassAdd"} + // StorageClassUpdate is the event when a StorageClass is updated in the cluster. + StorageClassUpdate = framework.ClusterEvent{Resource: framework.StorageClass, ActionType: framework.Update, Label: "StorageClassUpdate"} // CSINodeAdd is the event when a CSI node is added in the cluster. CSINodeAdd = framework.ClusterEvent{Resource: framework.CSINode, ActionType: framework.Add, Label: "CSINodeAdd"} // CSINodeUpdate is the event when a CSI node is updated in the cluster. CSINodeUpdate = framework.ClusterEvent{Resource: framework.CSINode, ActionType: framework.Update, Label: "CSINodeUpdate"} + // CSIDriverAdd is the event when a CSI node is added in the cluster. + CSIDriverAdd = framework.ClusterEvent{Resource: framework.CSIDriver, ActionType: framework.Add, Label: "CSIDriverAdd"} + // CSIDriverUpdate is the event when a CSI node is updated in the cluster. + CSIDriverUpdate = framework.ClusterEvent{Resource: framework.CSIDriver, ActionType: framework.Update, Label: "CSIDriverUpdate"} + // CSIStorageCapacityAdd is the event when a CSI node is added in the cluster. + CSIStorageCapacityAdd = framework.ClusterEvent{Resource: framework.CSIStorageCapacity, ActionType: framework.Add, Label: "CSIStorageCapacityAdd"} + // CSIStorageCapacityUpdate is the event when a CSI node is updated in the cluster. + CSIStorageCapacityUpdate = framework.ClusterEvent{Resource: framework.CSIStorageCapacity, ActionType: framework.Update, Label: "CSIStorageCapacityUpdate"} // ServiceAdd is the event when a service is added in the cluster. ServiceAdd = framework.ClusterEvent{Resource: framework.Service, ActionType: framework.Add, Label: "ServiceAdd"} // ServiceUpdate is the event when a service is updated in the cluster. diff --git a/pkg/scheduler/internal/queue/scheduling_queue_test.go b/pkg/scheduler/internal/queue/scheduling_queue_test.go index 21a787bd224..84e4c386e1c 100644 --- a/pkg/scheduler/internal/queue/scheduling_queue_test.go +++ b/pkg/scheduler/internal/queue/scheduling_queue_test.go @@ -29,7 +29,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/clock" @@ -447,8 +447,13 @@ func BenchmarkMoveAllToActiveOrBackoffQueue(b *testing.B) { PvAdd, PvUpdate, StorageClassAdd, + StorageClassUpdate, CSINodeAdd, CSINodeUpdate, + CSIDriverAdd, + CSIDriverUpdate, + CSIStorageCapacityAdd, + CSIStorageCapacityUpdate, } pluginNum := 20