Skip to content

Commit 29f3f0b

Browse files
authored
[cinder-csi-plugin] Refactor list volumes (#2766)
* refactor list volumes call * upgrade tests * comments improvements * fix imports and list options * token split * add more jointoken tests
1 parent d6196ca commit 29f3f0b

File tree

5 files changed

+251
-797
lines changed

5 files changed

+251
-797
lines changed

pkg/csi/cinder/controllerserver.go

+40-113
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ package cinder
1818

1919
import (
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-
411405
func (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

Comments
 (0)