@@ -18,8 +18,8 @@ package cinder
1818
1919import (
2020 "context"
21- "encoding/json"
2221 "fmt"
22+ "slices"
2323 "sort"
2424 "strconv"
2525
@@ -126,7 +126,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
126126
127127 // Volume Create
128128 properties := map [string ]string {cinderCSIClusterIDKey : cs .Driver .clusterID }
129- //Tag volume with metadata if present: https://github.com/kubernetes-csi/external-provisioner/pull/399
129+ // Tag volume with metadata if present: https://github.com/kubernetes-csi/external-provisioner/pull/399
130130 for _ , mKey := range sharedcsi .RecognizedCSIProvisionerParams {
131131 if v , ok := req .Parameters [mKey ]; ok {
132132 properties [mKey ] = v
@@ -161,7 +161,7 @@ func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
161161 var back * backups.Backup
162162 back , err = cloud .GetBackupByID (ctx , snapshotID )
163163 if err != nil {
164- //If there is an error getting the backup as well, fail.
164+ // If there is an error getting the backup as well, fail.
165165 return nil , status .Errorf (codes .NotFound , "VolumeContentSource Snapshot or Backup with ID %s not found" , snapshotID )
166166 }
167167 if back .Status != "available" {
@@ -402,12 +402,6 @@ func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *
402402 return & csi.ControllerUnpublishVolumeResponse {}, nil
403403}
404404
405- type CloudsStartingToken struct {
406- CloudName string `json:"cloud"`
407- Token string `json:"token"`
408- isEmpty bool
409- }
410-
411405func (cs * controllerServer ) extractNodeIDs (attachments []volumes.Attachment ) []string {
412406 nodeIDs := make ([]string , len (attachments ))
413407 for i , attachment := range attachments {
@@ -439,123 +433,56 @@ func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolume
439433 return nil , status .Errorf (codes .InvalidArgument , "[ListVolumes] Invalid max entries request %v, must not be negative " , req .MaxEntries )
440434 }
441435 maxEntries := int (req .MaxEntries )
442-
443436 var err error
444- var cloudsToken = CloudsStartingToken {
445- CloudName : "" ,
446- Token : "" ,
447- isEmpty : len (req .StartingToken ) == 0 ,
448- }
449437
450438 cloudsNames := maps .Keys (cs .Clouds )
451439 sort .Strings (cloudsNames )
452440
453- currentCloudName := cloudsNames [0 ]
441+ var (
442+ token string
443+ idx int
444+ cloudName = cloudsNames [0 ]
445+ )
454446 if req .StartingToken != "" {
455- err = json .Unmarshal ([]byte (req .StartingToken ), & cloudsToken )
456- if err != nil {
457- return nil , status .Errorf (codes .Aborted , "[ListVolumes] Invalid request: Token invalid" )
458- }
459- currentCloudName = cloudsToken .CloudName
460- }
461-
462- startingToken := cloudsToken .Token
463- var cloudsVentries []* csi.ListVolumesResponse_Entry
464- var vlist []volumes.Volume
465- var nextPageToken string
466-
467- if ! cloudsToken .isEmpty && startingToken == "" {
468- // previous call ended on last volumes from "currentCloudName" we should pass to next one
469- for i := range cloudsNames {
470- if cloudsNames [i ] == currentCloudName {
471- currentCloudName = cloudsNames [i + 1 ]
472- break
473- }
447+ token , cloudName = splitToken (req .StartingToken )
448+ idx = slices .Index (cloudsNames , cloudName )
449+ if idx < 0 {
450+ return nil , status .Errorf (codes .Internal , "[ListVolumes] Invalid request: %s" , fmt .Errorf ("unknown cloud specified in the request: %v" , cloudName ))
474451 }
475452 }
476453
477- startIdx := 0
478- for _ , cloudName := range cloudsNames {
479- if cloudName == currentCloudName {
480- break
481- }
482- startIdx ++
483- }
484- for idx := startIdx ; idx < len (cloudsNames ); idx ++ {
485- if maxEntries > 0 {
486- vlist , nextPageToken , err = cs.Clouds [cloudsNames [idx ]].ListVolumes (ctx , maxEntries - len (cloudsVentries ), startingToken )
487- } else {
488- vlist , nextPageToken , err = cs.Clouds [cloudsNames [idx ]].ListVolumes (ctx , maxEntries , startingToken )
489- }
490- startingToken = nextPageToken
491- if err != nil {
492- klog .Errorf ("Failed to ListVolumes: %v" , err )
493- if cpoerrors .IsInvalidError (err ) {
494- return nil , status .Errorf (codes .Aborted , "[ListVolumes] Invalid request: %v" , err )
495- }
496- return nil , status .Errorf (codes .Internal , "ListVolumes failed with error %v" , err )
497- }
498-
499- ventries := cs .createVolumeEntries (vlist )
500- klog .V (4 ).Infof ("ListVolumes: retrieved %d entries and %q next token from cloud %q" , len (ventries ), nextPageToken , cloudsNames [idx ])
501-
502- cloudsVentries = append (cloudsVentries , ventries ... )
503-
504- // Reach maxEntries setup nextToken with cloud identifier if needed
505- sendEmptyToken := false
506- if maxEntries > 0 && len (cloudsVentries ) == maxEntries {
507- if nextPageToken == "" {
508- if idx + 1 == len (cloudsNames ) {
509- // no more entries and no more clouds
510- // send no token its finished
511- klog .V (4 ).Infof ("ListVolumes: completed with %d entries and %q next token" , len (cloudsVentries ), "" )
512- return & csi.ListVolumesResponse {
513- Entries : cloudsVentries ,
514- NextToken : "" ,
515- }, nil
516- } else {
517- // still clouds to process
518- // set token to next non empty cloud
519- i := 0
520- for i = idx + 1 ; i < len (cloudsNames ); i ++ {
521- vlistTmp , _ , err := cs.Clouds [cloudsNames [i ]].ListVolumes (ctx , 1 , "" )
522- if err != nil {
523- klog .Errorf ("Failed to ListVolumes: %v" , err )
524- if cpoerrors .IsInvalidError (err ) {
525- return nil , status .Errorf (codes .Aborted , "[ListVolumes] Invalid request: %v" , err )
526- }
527- return nil , status .Errorf (codes .Internal , "ListVolumes failed with error %v" , err )
528- }
529- if len (vlistTmp ) > 0 {
530- cloudsToken .CloudName = cloudsNames [i ]
531- cloudsToken .isEmpty = false
532- break
533- }
534- }
535- if i == len (cloudsNames ) {
536- sendEmptyToken = true
537- }
538- }
539- }
540- cloudsToken .CloudName = cloudsNames [idx ]
541- cloudsToken .Token = nextPageToken
542- var data []byte
543- data , _ = json .Marshal (cloudsToken )
544- if sendEmptyToken {
545- data = []byte ("" )
546- }
547- klog .V (4 ).Infof ("ListVolumes: completed with %d entries and %q next token" , len (cloudsVentries ), string (data ))
548- return & csi.ListVolumesResponse {
549- Entries : cloudsVentries ,
550- NextToken : string (data ),
551- }, nil
454+ var volumeList []volumes.Volume
455+ volumeList , token , err = cs .Clouds [cloudName ].ListVolumes (ctx , maxEntries , token )
456+ if err != nil {
457+ klog .Errorf ("Failed to ListVolumes: %v" , err )
458+ if cpoerrors .IsInvalidError (err ) {
459+ return nil , status .Errorf (codes .Aborted , "[ListVolumes] Invalid request: %v" , err )
552460 }
461+ return nil , status .Errorf (codes .Internal , "ListVolumes failed with error %v" , err )
462+ }
463+ volumeEntries := cs .createVolumeEntries (volumeList )
464+ klog .V (4 ).Infof ("ListVolumes: retrieved %d entries and %q next token from cloud %q" , len (volumeEntries ), token , cloudName )
465+
466+ switch {
467+ // if we have not finished listing all volumes from this cloud, we will continue on next call.
468+ case token != "" :
469+ // if we listed all volumes from this cloud but more clouds exist, return a token of the next cloud.
470+ case idx + 1 < len (cloudsNames ):
471+ cloudName = cloudsNames [idx + 1 ]
472+ default :
473+ // work is done.
474+ klog .V (4 ).Infof ("ListVolumes: completed with %d entries and %q next token" , len (volumeEntries ), "" )
475+ return & csi.ListVolumesResponse {
476+ Entries : volumeEntries ,
477+ NextToken : "" ,
478+ }, nil
553479 }
554480
555- klog .V (4 ).Infof ("ListVolumes: completed with %d entries and %q next token" , len (cloudsVentries ), "" )
481+ nextToken := joinToken (token , cloudName )
482+ klog .V (4 ).Infof ("ListVolumes: completed with %d entries and %q next token" , len (volumeEntries ), nextToken )
556483 return & csi.ListVolumesResponse {
557- Entries : cloudsVentries ,
558- NextToken : "" ,
484+ Entries : volumeEntries ,
485+ NextToken : nextToken ,
559486 }, nil
560487}
561488
0 commit comments