@@ -23,6 +23,7 @@ import (
23
23
v1 "k8s.io/api/core/v1"
24
24
storagev1 "k8s.io/api/storage/v1"
25
25
apierrors "k8s.io/apimachinery/pkg/api/errors"
26
+ "k8s.io/apimachinery/pkg/labels"
26
27
"k8s.io/apimachinery/pkg/runtime"
27
28
"k8s.io/apimachinery/pkg/util/rand"
28
29
corelisters "k8s.io/client-go/listers/core/v1"
@@ -56,6 +57,7 @@ type CSILimits struct {
56
57
pvLister corelisters.PersistentVolumeLister
57
58
pvcLister corelisters.PersistentVolumeClaimLister
58
59
scLister storagelisters.StorageClassLister
60
+ vaLister storagelisters.VolumeAttachmentLister
59
61
60
62
randomVolumeIDPrefix string
61
63
@@ -148,6 +150,7 @@ func (pl *CSILimits) Filter(ctx context.Context, _ *framework.CycleState, pod *v
148
150
logger .V (5 ).Info ("Could not get a CSINode object for the node" , "node" , klog .KObj (node ), "err" , err )
149
151
}
150
152
153
+ // Count CSI volumes from the new pod
151
154
newVolumes := make (map [string ]string )
152
155
if err := pl .filterAttachableVolumes (logger , pod , csiNode , true /* new pod */ , newVolumes ); err != nil {
153
156
if apierrors .IsNotFound (err ) {
@@ -168,6 +171,7 @@ func (pl *CSILimits) Filter(ctx context.Context, _ *framework.CycleState, pod *v
168
171
return nil
169
172
}
170
173
174
+ // Count CSI volumes from existing pods
171
175
attachedVolumes := make (map [string ]string )
172
176
for _ , existingPod := range nodeInfo .Pods {
173
177
if err := pl .filterAttachableVolumes (logger , existingPod .Pod , csiNode , false /* existing pod */ , attachedVolumes ); err != nil {
@@ -182,6 +186,19 @@ func (pl *CSILimits) Filter(ctx context.Context, _ *framework.CycleState, pod *v
182
186
attachedVolumeCount [volumeLimitKey ]++
183
187
}
184
188
189
+ // Count CSI volumes from VolumeAttachments
190
+ volumeAttachments , err := pl .getNodeVolumeAttachmentInfo (logger , node .Name )
191
+ if err != nil {
192
+ return framework .AsStatus (err )
193
+ }
194
+
195
+ for volumeUniqueName , driverName := range volumeAttachments {
196
+ // Avoid double-counting volumes already used by existing pods
197
+ if _ , exists := attachedVolumes [volumeUniqueName ]; ! exists {
198
+ attachedVolumeCount [driverName ]++
199
+ }
200
+ }
201
+
185
202
newVolumeCount := map [string ]int {}
186
203
for _ , volumeLimitKey := range newVolumes {
187
204
newVolumeCount [volumeLimitKey ]++
@@ -264,7 +281,7 @@ func (pl *CSILimits) filterAttachableVolumes(
264
281
continue
265
282
}
266
283
267
- volumeUniqueName := fmt . Sprintf ( "%s/%s" , driverName , volumeHandle )
284
+ volumeUniqueName := getVolumeUniqueName ( driverName , volumeHandle )
268
285
volumeLimitKey := volumeutil .GetCSIAttachLimitKey (driverName )
269
286
result [volumeUniqueName ] = volumeLimitKey
270
287
}
@@ -306,7 +323,7 @@ func (pl *CSILimits) checkAttachableInlineVolume(logger klog.Logger, vol *v1.Vol
306
323
if translatedPV .Spec .PersistentVolumeSource .CSI == nil {
307
324
return nil
308
325
}
309
- volumeUniqueName := fmt . Sprintf ( "%s/%s" , driverName , translatedPV .Spec .PersistentVolumeSource .CSI .VolumeHandle )
326
+ volumeUniqueName := getVolumeUniqueName ( driverName , translatedPV .Spec .PersistentVolumeSource .CSI .VolumeHandle )
310
327
volumeLimitKey := volumeutil .GetCSIAttachLimitKey (driverName )
311
328
result [volumeUniqueName ] = volumeLimitKey
312
329
return nil
@@ -416,13 +433,15 @@ func NewCSI(_ context.Context, _ runtime.Object, handle framework.Handle, fts fe
416
433
pvcLister := informerFactory .Core ().V1 ().PersistentVolumeClaims ().Lister ()
417
434
csiNodesLister := informerFactory .Storage ().V1 ().CSINodes ().Lister ()
418
435
scLister := informerFactory .Storage ().V1 ().StorageClasses ().Lister ()
436
+ vaLister := informerFactory .Storage ().V1 ().VolumeAttachments ().Lister ()
419
437
csiTranslator := csitrans .New ()
420
438
421
439
return & CSILimits {
422
440
csiNodeLister : csiNodesLister ,
423
441
pvLister : pvLister ,
424
442
pvcLister : pvcLister ,
425
443
scLister : scLister ,
444
+ vaLister : vaLister ,
426
445
randomVolumeIDPrefix : rand .String (32 ),
427
446
translator : csiTranslator ,
428
447
}, nil
@@ -443,3 +462,40 @@ func getVolumeLimits(nodeInfo *framework.NodeInfo, csiNode *storagev1.CSINode) m
443
462
}
444
463
return nodeVolumeLimits
445
464
}
465
+
466
+ // getNodeVolumeAttachmentInfo returns a map of volumeID to driver name for the given node.
467
+ func (pl * CSILimits ) getNodeVolumeAttachmentInfo (logger klog.Logger , nodeName string ) (map [string ]string , error ) {
468
+ volumeAttachments := make (map [string ]string )
469
+ vas , err := pl .vaLister .List (labels .Everything ())
470
+ if err != nil {
471
+ return nil , err
472
+ }
473
+ for _ , va := range vas {
474
+ if va .Spec .NodeName == nodeName {
475
+ if va .Spec .Attacher == "" {
476
+ logger .V (5 ).Info ("VolumeAttachment has no attacher" , "VolumeAttachment" , klog .KObj (va ))
477
+ continue
478
+ }
479
+ if va .Spec .Source .PersistentVolumeName == nil {
480
+ logger .V (5 ).Info ("VolumeAttachment has no PV name" , "VolumeAttachment" , klog .KObj (va ))
481
+ continue
482
+ }
483
+ pv , err := pl .pvLister .Get (* va .Spec .Source .PersistentVolumeName )
484
+ if err != nil {
485
+ logger .V (5 ).Info ("Unable to get PV for VolumeAttachment" , "VolumeAttachment" , klog .KObj (va ), "err" , err )
486
+ continue
487
+ }
488
+ if pv .Spec .CSI == nil {
489
+ logger .V (5 ).Info ("PV is not a CSI volume" , "PV" , klog .KObj (pv ))
490
+ continue
491
+ }
492
+ volumeID := getVolumeUniqueName (va .Spec .Attacher , pv .Spec .CSI .VolumeHandle )
493
+ volumeAttachments [volumeID ] = volumeutil .GetCSIAttachLimitKey (va .Spec .Attacher )
494
+ }
495
+ }
496
+ return volumeAttachments , nil
497
+ }
498
+
499
+ func getVolumeUniqueName (driverName , volumeHandle string ) string {
500
+ return fmt .Sprintf ("%s/%s" , driverName , volumeHandle )
501
+ }
0 commit comments