66 "errors"
77 "fmt"
88 "math/rand"
9+ "strconv"
910 "time"
1011
1112 "github.com/container-storage-interface/spec/lib/go/csi"
@@ -338,15 +339,6 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
338339 return nil , status .Error (codes .InvalidArgument , "SourceVolumeId missing in request" )
339340 }
340341
341- // Check for existing snapshot with same name but different source volume ID
342- if req .GetName () != "" {
343- // check if the name matches and volumeID differs
344- existingSnap , err := cs .connector .GetSnapshotByName (ctx , req .GetName ())
345- if err == nil && existingSnap .VolumeID != volumeID {
346- return nil , status .Errorf (codes .AlreadyExists , "Snapshot with name %s already exists for a different source volume" , req .GetName ())
347- }
348- }
349-
350342 volume , err := cs .connector .GetVolumeByID (ctx , volumeID )
351343 if err != nil {
352344 if err .Error () == "invalid volume ID: empty string" {
@@ -355,12 +347,13 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
355347 if errors .Is (err , cloud .ErrNotFound ) {
356348 return nil , status .Errorf (codes .NotFound , "Volume %v not found" , volumeID )
357349 }
358- // Error with CloudStack
359350 return nil , status .Errorf (codes .Internal , "Error %v" , err )
360351 }
361352 klog .V (4 ).Infof ("CreateSnapshot of volume: %s" , volume .ID )
362- snapshot , err := cs .connector .CreateSnapshot (ctx , volume .ID )
363- if err != nil {
353+ snapshot , err := cs .connector .CreateSnapshot (ctx , volume .ID , req .GetName ())
354+ if errors .Is (err , cloud .ErrAlreadyExists ) {
355+ return nil , status .Errorf (codes .AlreadyExists , "Snapshot name conflict: already exists for a different source volume" )
356+ } else if err != nil {
364357 return nil , status .Errorf (codes .Internal , "Failed to create snapshot for volume %s: %v" , volume .ID , err .Error ())
365358 }
366359
@@ -369,7 +362,6 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
369362 return nil , status .Errorf (codes .Internal , "Failed to parse snapshot creation time: %v" , err )
370363 }
371364
372- // Convert to Timestamp protobuf
373365 ts := timestamppb .New (t )
374366
375367 resp := & csi.CreateSnapshotResponse {
@@ -378,37 +370,53 @@ func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateS
378370 SourceVolumeId : volume .ID ,
379371 CreationTime : ts ,
380372 ReadyToUse : true ,
381- // We leave the optional SizeBytes field unset as the size of a block storage snapshot is the size of the difference to the volume or previous snapshots, k8s however expects the size to be the size of the restored volume.
382373 },
383374 }
384375 return resp , nil
385-
386376}
387377
388378func (cs * controllerServer ) ListSnapshots (ctx context.Context , req * csi.ListSnapshotsRequest ) (* csi.ListSnapshotsResponse , error ) {
389379 entries := []* csi.ListSnapshotsResponse_Entry {}
390380
391- if req .GetSnapshotId () != "" {
392- snap , err := cs .connector .GetSnapshotByID (ctx , req .GetSnapshotId ())
393- if err == nil && snap != nil {
394- t , _ := time .Parse ("2006-01-02T15:04:05-0700" , snap .CreatedAt )
395- ts := timestamppb .New (t )
396- entry := & csi.ListSnapshotsResponse_Entry {
397- Snapshot : & csi.Snapshot {
398- SnapshotId : snap .ID ,
399- SourceVolumeId : snap .VolumeID ,
400- CreationTime : ts ,
401- ReadyToUse : true ,
402- },
403- }
404- entries = append (entries , entry )
405- return & csi.ListSnapshotsResponse {Entries : entries }, nil
406- }
407- // If not found, return empty list
408- return & csi.ListSnapshotsResponse {Entries : []* csi.ListSnapshotsResponse_Entry {}}, nil
381+ snapshots , err := cs .connector .ListSnapshots (ctx , req .GetSourceVolumeId (), req .GetSnapshotId ())
382+ if err != nil {
383+ return nil , status .Errorf (codes .Internal , "Failed to list snapshots: %v" , err )
409384 }
410385
411- return & csi.ListSnapshotsResponse {Entries : entries }, nil
386+ // Pagination logic
387+ start := 0
388+ if req .StartingToken != "" {
389+ var err error
390+ start , err = strconv .Atoi (req .StartingToken )
391+ if err != nil || start < 0 || start > len (snapshots ) {
392+ return nil , status .Error (codes .Aborted , "Invalid startingToken" )
393+ }
394+ }
395+ maxEntries := int (req .MaxEntries )
396+ end := len (snapshots )
397+ if maxEntries > 0 && start + maxEntries < end {
398+ end = start + maxEntries
399+ }
400+ nextToken := ""
401+ if end < len (snapshots ) {
402+ nextToken = strconv .Itoa (end )
403+ }
404+
405+ for i := start ; i < end ; i ++ {
406+ snap := snapshots [i ]
407+ t , _ := time .Parse ("2006-01-02T15:04:05-0700" , snap .CreatedAt )
408+ ts := timestamppb .New (t )
409+ entry := & csi.ListSnapshotsResponse_Entry {
410+ Snapshot : & csi.Snapshot {
411+ SnapshotId : snap .ID ,
412+ SourceVolumeId : snap .VolumeID ,
413+ CreationTime : ts ,
414+ ReadyToUse : true ,
415+ },
416+ }
417+ entries = append (entries , entry )
418+ }
419+ return & csi.ListSnapshotsResponse {Entries : entries , NextToken : nextToken }, nil
412420}
413421
414422func (cs * controllerServer ) DeleteSnapshot (ctx context.Context , req * csi.DeleteSnapshotRequest ) (* csi.DeleteSnapshotResponse , error ) {
@@ -420,19 +428,14 @@ func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteS
420428
421429 klog .V (4 ).Infof ("DeleteSnapshot for snapshotID: %s" , snapshotID )
422430
423- snapshot , err := cs .connector .GetSnapshotByID (ctx , snapshotID )
431+ err := cs .connector .DeleteSnapshot (ctx , snapshotID )
424432 if errors .Is (err , cloud .ErrNotFound ) {
425- return nil , status .Errorf (codes .NotFound , "Snapshot %v not found" , snapshotID )
433+ // Per CSI spec, return OK if snapshot does not exist
434+ return & csi.DeleteSnapshotResponse {}, nil
426435 } else if err != nil {
427- // Error with CloudStack
428436 return nil , status .Errorf (codes .Internal , "Error %v" , err )
429437 }
430438
431- err = cs .connector .DeleteSnapshot (ctx , snapshot .ID )
432- if err != nil && ! errors .Is (err , cloud .ErrNotFound ) {
433- return nil , status .Errorf (codes .Internal , "Cannot delete snapshot %s: %s" , snapshotID , err .Error ())
434- }
435-
436439 return & csi.DeleteSnapshotResponse {}, nil
437440}
438441
0 commit comments