@@ -21,7 +21,9 @@ import (
21
21
"strings"
22
22
"time"
23
23
24
- csi "github.com/container-storage-interface/spec/lib/go/csi/v0"
24
+ "github.com/golang/protobuf/ptypes"
25
+
26
+ csi "github.com/container-storage-interface/spec/lib/go/csi"
25
27
"github.com/golang/glog"
26
28
"golang.org/x/net/context"
27
29
compute "google.golang.org/api/compute/v1"
@@ -152,7 +154,8 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
152
154
content := req .GetVolumeContentSource ()
153
155
if content != nil {
154
156
if content .GetSnapshot () != nil {
155
- snapshotId = content .GetSnapshot ().GetId ()
157
+ // TODO(#161): Add support for Volume Source (cloning) introduced in CSI v1.0.0
158
+ snapshotId = content .GetSnapshot ().GetSnapshotId ()
156
159
}
157
160
}
158
161
@@ -241,7 +244,7 @@ func (gceCS *GCEControllerServer) ControllerPublishVolume(ctx context.Context, r
241
244
// TODO(#94): Check volume capability matches
242
245
243
246
pubVolResp := & csi.ControllerPublishVolumeResponse {
244
- PublishInfo : nil ,
247
+ PublishContext : nil ,
245
248
}
246
249
247
250
_ , err = gceCS .CloudProvider .GetDisk (ctx , volKey )
@@ -352,6 +355,8 @@ func (gceCS *GCEControllerServer) ControllerUnpublishVolume(ctx context.Context,
352
355
353
356
func (gceCS * GCEControllerServer ) ValidateVolumeCapabilities (ctx context.Context , req * csi.ValidateVolumeCapabilitiesRequest ) (* csi.ValidateVolumeCapabilitiesResponse , error ) {
354
357
// TODO(#94): Factor out the volume capability functionality and use as validation in all other functions as well
358
+ // TODO(#162): Implement ValidateVolumeCapabilities
359
+
355
360
glog .V (5 ).Infof ("Using default ValidateVolumeCapabilities" )
356
361
// Validate Arguments
357
362
if req .GetVolumeCapabilities () == nil || len (req .GetVolumeCapabilities ()) == 0 {
@@ -373,63 +378,68 @@ func (gceCS *GCEControllerServer) ValidateVolumeCapabilities(ctx context.Context
373
378
return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown get disk error: %v" , err ))
374
379
}
375
380
376
- for _ , c := range req .GetVolumeCapabilities () {
377
- found := false
378
- for _ , c1 := range gceCS .Driver .vcap {
379
- if c1 .Mode == c .GetAccessMode ().Mode {
380
- found = true
381
+ return & csi.ValidateVolumeCapabilitiesResponse {
382
+ Message : "ValidateVolumeCapabilities is currently unimplemented for CSI v1.0.0" ,
383
+ }, nil
384
+ /*
385
+ for _, c := range req.GetVolumeCapabilities() {
386
+ found := false
387
+ for _, c1 := range gceCS.Driver.vcap {
388
+ if c1.Mode == c.GetAccessMode().Mode {
389
+ found = true
390
+ }
381
391
}
382
- }
383
- if ! found {
384
- return & csi.ValidateVolumeCapabilitiesResponse {
385
- Supported : false ,
386
- Message : "Driver does not support mode:" + c .GetAccessMode ().Mode .String (),
387
- }, status .Error (codes .InvalidArgument , "Driver does not support mode:" + c .GetAccessMode ().Mode .String ())
388
- }
389
- // TODO: Ignoring mount & block types for now.
390
- }
391
-
392
- for _ , top := range req .GetAccessibleTopology () {
393
- for k , v := range top .GetSegments () {
394
- switch k {
395
- case common .TopologyKeyZone :
396
- switch volKey .Type () {
397
- case meta .Zonal :
398
- if v == volKey .Zone {
399
- // Accessible zone matches with storage zone
400
- return & csi.ValidateVolumeCapabilitiesResponse {
401
- Supported : true ,
402
- }, nil
403
- }
404
- case meta .Regional :
405
- // TODO: This should more accurately check the disks replica Zones but that involves
406
- // GET-ing the disk
407
- region , err := common .GetRegionFromZones ([]string {v })
408
- if err != nil {
409
- return nil , status .Error (codes .InvalidArgument , fmt .Sprintf ("ValidateVolumeCapabilities could not extract topology region from zone %v: %v" , v , err ))
410
- }
411
- if region == volKey .Region {
412
- // Accessible region matches with storage region
392
+ if !found {
393
+ return &csi.ValidateVolumeCapabilitiesResponse{
394
+ Supported: false,
395
+ Message: "Driver does not support mode:" + c.GetAccessMode().Mode.String(),
396
+ }, status.Error(codes.InvalidArgument, "Driver does not support mode:"+c.GetAccessMode().Mode.String())
397
+ }
398
+ // TODO: Ignoring mount & block types for now.
399
+ }
400
+
401
+ for _, top := range req.GetAccessibleTopology() {
402
+ for k, v := range top.GetSegments() {
403
+ switch k {
404
+ case common.TopologyKeyZone:
405
+ switch volKey.Type() {
406
+ case meta.Zonal:
407
+ if v == volKey.Zone {
408
+ // Accessible zone matches with storage zone
409
+ return &csi.ValidateVolumeCapabilitiesResponse{
410
+ Supported: true,
411
+ }, nil
412
+ }
413
+ case meta.Regional:
414
+ // TODO: This should more accurately check the disks replica Zones but that involves
415
+ // GET-ing the disk
416
+ region, err := common.GetRegionFromZones([]string{v})
417
+ if err != nil {
418
+ return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("ValidateVolumeCapabilities could not extract topology region from zone %v: %v", v, err))
419
+ }
420
+ if region == volKey.Region {
421
+ // Accessible region matches with storage region
422
+ return &csi.ValidateVolumeCapabilitiesResponse{
423
+ Supported: true,
424
+ }, nil
425
+ }
426
+ default:
427
+ // Accessible zone does not match
413
428
return &csi.ValidateVolumeCapabilitiesResponse{
414
- Supported : true ,
429
+ Supported: false,
430
+ Message: fmt.Sprintf("Volume %s is not accesible from topology %s:%s", volumeID, k, v),
415
431
}, nil
416
432
}
417
433
default:
418
- // Accessible zone does not match
419
- return & csi.ValidateVolumeCapabilitiesResponse {
420
- Supported : false ,
421
- Message : fmt .Sprintf ("Volume %s is not accesible from topology %s:%s" , volumeID , k , v ),
422
- }, nil
434
+ return nil, status.Error(codes.InvalidArgument, "ValidateVolumeCapabilities unknown topology segment key")
423
435
}
424
- default :
425
- return nil , status .Error (codes .InvalidArgument , "ValidateVolumeCapabilities unknown topology segment key" )
426
436
}
427
437
}
428
- }
429
438
430
- return & csi.ValidateVolumeCapabilitiesResponse {
431
- Supported : true ,
432
- }, nil
439
+ return &csi.ValidateVolumeCapabilitiesResponse{
440
+ Supported: true,
441
+ }, nil
442
+ */
433
443
}
434
444
435
445
func (gceCS * GCEControllerServer ) ListVolumes (ctx context.Context , req * csi.ListVolumesRequest ) (* csi.ListVolumesResponse , error ) {
@@ -467,13 +477,23 @@ func (gceCS *GCEControllerServer) CreateSnapshot(ctx context.Context, req *csi.C
467
477
return nil , status .Error (codes .NotFound , fmt .Sprintf ("Could not find volume with ID %v: %v" , volumeID , err ))
468
478
}
469
479
470
- snapshot , err := gceCS .CloudProvider .CreateSnapshot (ctx , volKey , req .Name )
480
+ // Check if snapshot already exists
481
+ var snapshot * compute.Snapshot
482
+ snapshot , err = gceCS .CloudProvider .GetSnapshot (ctx , req .Name )
471
483
if err != nil {
472
- if gce .IsGCEError (err , "notFound" ) {
473
- return nil , status .Error (codes .NotFound , fmt .Sprintf ("Could not find volume with ID %v: %v" , volKey .String (), err ))
484
+ if ! gce .IsGCEError (err , "notFound" ) {
485
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown get snapshot error: %v" , err ))
486
+ }
487
+ // If we could not find the snapshot, we create a new one
488
+ snapshot , err = gceCS .CloudProvider .CreateSnapshot (ctx , volKey , req .Name )
489
+ if err != nil {
490
+ if gce .IsGCEError (err , "notFound" ) {
491
+ return nil , status .Error (codes .NotFound , fmt .Sprintf ("Could not find volume with ID %v: %v" , volKey .String (), err ))
492
+ }
493
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown create snapshot error: %v" , err ))
474
494
}
475
- return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown create snapshot error: %v" , err ))
476
495
}
496
+
477
497
err = gceCS .validateExistingSnapshot (snapshot , volKey )
478
498
if err != nil {
479
499
return nil , status .Error (codes .AlreadyExists , fmt .Sprintf ("Error in creating snapshot: %v" , err ))
@@ -482,15 +502,24 @@ func (gceCS *GCEControllerServer) CreateSnapshot(ctx context.Context, req *csi.C
482
502
if err != nil {
483
503
return nil , status .Error (codes .Internal , fmt .Sprintf ("Failed to covert creation timestamp: %v" , err ))
484
504
}
505
+
506
+ tp , err := ptypes .TimestampProto (t )
507
+ if err != nil {
508
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("Failed to covert creation timestamp: %v" , err ))
509
+ }
510
+
511
+ ready , err := isCSISnapshotReady (snapshot .Status )
512
+ if err != nil {
513
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("Snapshot had error checking ready status: %v" , err ))
514
+ }
515
+
485
516
createResp := & csi.CreateSnapshotResponse {
486
517
Snapshot : & csi.Snapshot {
487
518
SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
488
- Id : cleanSelfLink (snapshot .SelfLink ),
519
+ SnapshotId : cleanSelfLink (snapshot .SelfLink ),
489
520
SourceVolumeId : volumeID ,
490
- CreatedAt : t .UnixNano (),
491
- Status : & csi.SnapshotStatus {
492
- Type : convertCSISnapshotStatus (snapshot .Status ),
493
- },
521
+ CreationTime : tp ,
522
+ ReadyToUse : ready ,
494
523
},
495
524
}
496
525
return createResp , nil
@@ -514,22 +543,18 @@ func (gceCS *GCEControllerServer) validateExistingSnapshot(snapshot *compute.Sna
514
543
return nil
515
544
}
516
545
517
- func convertCSISnapshotStatus (status string ) csi.SnapshotStatus_Type {
518
- var csiStatus csi.SnapshotStatus_Type
546
+ func isCSISnapshotReady (status string ) (bool , error ) {
519
547
switch status {
520
548
case "READY" :
521
- csiStatus = csi .SnapshotStatus_READY
522
- case "UPLOADING" :
523
- csiStatus = csi .SnapshotStatus_UPLOADING
549
+ return true , nil
524
550
case "FAILED" :
525
- csiStatus = csi . SnapshotStatus_ERROR_UPLOADING
551
+ return false , fmt . Errorf ( "snapshot status is FAILED" )
526
552
case "DELETING" :
527
- csiStatus = csi .SnapshotStatus_UNKNOWN
528
553
glog .V (4 ).Infof ("snapshot is in DELETING" )
554
+ fallthrough
529
555
default :
530
- csiStatus = csi . SnapshotStatus_UNKNOWN
556
+ return false , nil
531
557
}
532
- return csiStatus
533
558
}
534
559
535
560
func (gceCS * GCEControllerServer ) DeleteSnapshot (ctx context.Context , req * csi.DeleteSnapshotRequest ) (* csi.DeleteSnapshotResponse , error ) {
@@ -587,7 +612,10 @@ func (gceCS *GCEControllerServer) getSnapshots(ctx context.Context, req *csi.Lis
587
612
entries := []* csi.ListSnapshotsResponse_Entry {}
588
613
589
614
for _ , snapshot := range snapshots {
590
- entry := generateSnapshotEntry (snapshot )
615
+ entry , err := generateSnapshotEntry (snapshot )
616
+ if err != nil {
617
+ return nil , fmt .Errorf ("failed to generate snapshot entry: %v" , err )
618
+ }
591
619
entries = append (entries , entry )
592
620
}
593
621
listSnapshotResp := & csi.ListSnapshotsResponse {
@@ -614,28 +642,42 @@ func (gceCS *GCEControllerServer) getSnapshotById(ctx context.Context, snapshotI
614
642
}
615
643
return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown list snapshot error: %v" , err ))
616
644
}
617
- entries := []* csi.ListSnapshotsResponse_Entry {generateSnapshotEntry (snapshot )}
645
+ e , err := generateSnapshotEntry (snapshot )
646
+ if err != nil {
647
+ return nil , fmt .Errorf ("failed to generate snapshot entry: %v" , err )
648
+ }
649
+
650
+ entries := []* csi.ListSnapshotsResponse_Entry {e }
618
651
//entries[0] = entry
619
652
listSnapshotResp := & csi.ListSnapshotsResponse {
620
653
Entries : entries ,
621
654
}
622
655
return listSnapshotResp , nil
623
656
}
624
657
625
- func generateSnapshotEntry (snapshot * compute.Snapshot ) * csi.ListSnapshotsResponse_Entry {
658
+ func generateSnapshotEntry (snapshot * compute.Snapshot ) ( * csi.ListSnapshotsResponse_Entry , error ) {
626
659
t , _ := time .Parse (time .RFC3339 , snapshot .CreationTimestamp )
660
+
661
+ tp , err := ptypes .TimestampProto (t )
662
+ if err != nil {
663
+ return nil , fmt .Errorf ("Failed to covert creation timestamp: %v" , err )
664
+ }
665
+
666
+ // We ignore the error intentionally here since we are just listing snapshots
667
+ // TODO: If the snapshot is in "FAILED" state we need to think through what this
668
+ // should actually look like.
669
+ ready , _ := isCSISnapshotReady (snapshot .Status )
670
+
627
671
entry := & csi.ListSnapshotsResponse_Entry {
628
672
Snapshot : & csi.Snapshot {
629
673
SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
630
- Id : cleanSelfLink (snapshot .SelfLink ),
674
+ SnapshotId : cleanSelfLink (snapshot .SelfLink ),
631
675
SourceVolumeId : cleanSelfLink (snapshot .SourceDisk ),
632
- CreatedAt : t .UnixNano (),
633
- Status : & csi.SnapshotStatus {
634
- Type : convertCSISnapshotStatus (snapshot .Status ),
635
- },
676
+ CreationTime : tp ,
677
+ ReadyToUse : ready ,
636
678
},
637
679
}
638
- return entry
680
+ return entry , nil
639
681
}
640
682
641
683
func getRequestCapacity (capRange * csi.CapacityRange ) (int64 , error ) {
@@ -815,8 +857,8 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, capBytes int64, zones []s
815
857
createResp := & csi.CreateVolumeResponse {
816
858
Volume : & csi.Volume {
817
859
CapacityBytes : capBytes ,
818
- Id : cleanSelfLink (disk .GetSelfLink ()),
819
- Attributes : nil ,
860
+ VolumeId : cleanSelfLink (disk .GetSelfLink ()),
861
+ VolumeContext : nil ,
820
862
AccessibleTopology : tops ,
821
863
},
822
864
}
@@ -825,7 +867,7 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, capBytes int64, zones []s
825
867
source := & csi.VolumeContentSource {
826
868
Type : & csi.VolumeContentSource_Snapshot {
827
869
Snapshot : & csi.VolumeContentSource_SnapshotSource {
828
- Id : snapshotId ,
870
+ SnapshotId : snapshotId ,
829
871
},
830
872
},
831
873
}
0 commit comments