@@ -20,6 +20,7 @@ import (
20
20
"context"
21
21
"errors"
22
22
"fmt"
23
+ "reflect"
23
24
24
25
v1 "k8s.io/api/core/v1"
25
26
storage "k8s.io/api/storage/v1"
@@ -158,21 +159,7 @@ func (pl *VolumeZone) getPVbyPod(logger klog.Logger, pod *v1.Pod) ([]pvTopology,
158
159
if s := getErrorAsStatus (err ); ! s .IsSuccess () {
159
160
return nil , s
160
161
}
161
-
162
- for _ , key := range topologyLabels {
163
- if value , ok := pv .ObjectMeta .Labels [key ]; ok {
164
- volumeVSet , err := volumehelpers .LabelZonesToSet (value )
165
- if err != nil {
166
- logger .Info ("Failed to parse label, ignoring the label" , "label" , fmt .Sprintf ("%s:%s" , key , value ), "err" , err )
167
- continue
168
- }
169
- podPVTopologies = append (podPVTopologies , pvTopology {
170
- pvName : pv .Name ,
171
- key : key ,
172
- values : sets.Set [string ](volumeVSet ),
173
- })
174
- }
175
- }
162
+ podPVTopologies = append (podPVTopologies , pl .getPVTopologies (logger , pv )... )
176
163
}
177
164
return podPVTopologies , nil
178
165
}
@@ -292,7 +279,7 @@ func (pl *VolumeZone) EventsToRegister() []framework.ClusterEventWithHint {
292
279
// Also, if pvc's VolumeName is filled, that also could make a pod schedulable.
293
280
{Event : framework.ClusterEvent {Resource : framework .PersistentVolumeClaim , ActionType : framework .Add | framework .Update }, QueueingHintFn : pl .isSchedulableAfterPersistentVolumeClaimChange },
294
281
// A new pv or updating a pv's volume zone labels may make a pod schedulable.
295
- {Event : framework.ClusterEvent {Resource : framework .PersistentVolume , ActionType : framework .Add | framework .Update }},
282
+ {Event : framework.ClusterEvent {Resource : framework .PersistentVolume , ActionType : framework .Add | framework .Update }, QueueingHintFn : pl . isSchedulableAfterPersistentVolumeChange },
296
283
}
297
284
}
298
285
@@ -359,6 +346,52 @@ func (pl *VolumeZone) isSchedulableAfterStorageClassAdded(logger klog.Logger, po
359
346
return framework .Queue , nil
360
347
}
361
348
349
+ // isSchedulableAfterPersistentVolumeChange is invoked whenever a PersistentVolume added or updated.
350
+ // It checks whether the change of PV has made a previously unschedulable pod schedulable.
351
+ // Changing the PV topology labels could cause the pod to become schedulable.
352
+ func (pl * VolumeZone ) isSchedulableAfterPersistentVolumeChange (logger klog.Logger , pod * v1.Pod , oldObj , newObj interface {}) (framework.QueueingHint , error ) {
353
+ originalPV , modifiedPV , err := util .As [* v1.PersistentVolume ](oldObj , newObj )
354
+ if err != nil {
355
+ return framework .Queue , fmt .Errorf ("unexpected objects in isSchedulableAfterPersistentVolumeChange: %w" , err )
356
+ }
357
+ if originalPV == nil {
358
+ logger .V (5 ).Info ("PV is newly created, which might make the pod schedulable" )
359
+ return framework .Queue , nil
360
+ }
361
+ originalPVTopologies := pl .getPVTopologies (logger , originalPV )
362
+ modifiedPVTopologies := pl .getPVTopologies (logger , modifiedPV )
363
+ if ! reflect .DeepEqual (originalPVTopologies , modifiedPVTopologies ) {
364
+ logger .V (5 ).Info ("PV's topology was updated, which might make the pod schedulable." , "pod" , klog .KObj (pod ), "PV" , klog .KObj (modifiedPV ))
365
+ return framework .Queue , nil
366
+ }
367
+
368
+ logger .V (5 ).Info ("PV was updated, but the topology is unchanged, which it doesn't make the pod schedulable" , "pod" , klog .KObj (pod ), "PV" , klog .KObj (modifiedPV ))
369
+ return framework .QueueSkip , nil
370
+ }
371
+
372
+ // getPVTopologies retrieves pvTopology from a given PV and returns the array
373
+ // This function doesn't check spec.nodeAffinity
374
+ // because it's read-only after creation and thus cannot be updated
375
+ // and nodeAffinity is being handled in node affinity plugin
376
+ func (pl * VolumeZone ) getPVTopologies (logger klog.Logger , pv * v1.PersistentVolume ) []pvTopology {
377
+ podPVTopologies := make ([]pvTopology , 0 )
378
+ for _ , key := range topologyLabels {
379
+ if value , ok := pv .ObjectMeta .Labels [key ]; ok {
380
+ labelZonesSet , err := volumehelpers .LabelZonesToSet (value )
381
+ if err != nil {
382
+ logger .V (5 ).Info ("failed to parse PV's topology label, ignoring the label" , "label" , fmt .Sprintf ("%s:%s" , key , value ), "err" , err )
383
+ continue
384
+ }
385
+ podPVTopologies = append (podPVTopologies , pvTopology {
386
+ pvName : pv .Name ,
387
+ key : key ,
388
+ values : sets.Set [string ](labelZonesSet ),
389
+ })
390
+ }
391
+ }
392
+ return podPVTopologies
393
+ }
394
+
362
395
// New initializes a new plugin and returns it.
363
396
func New (_ context.Context , _ runtime.Object , handle framework.Handle ) (framework.Plugin , error ) {
364
397
informerFactory := handle .SharedInformerFactory ()
0 commit comments