@@ -21,7 +21,9 @@ import (
2121 "strings"
2222 "time"
2323
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"
2527 "github.com/golang/glog"
2628 "golang.org/x/net/context"
2729 compute "google.golang.org/api/compute/v1"
@@ -152,7 +154,8 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
152154 content := req .GetVolumeContentSource ()
153155 if content != nil {
154156 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 ()
156159 }
157160 }
158161
@@ -241,7 +244,7 @@ func (gceCS *GCEControllerServer) ControllerPublishVolume(ctx context.Context, r
241244 // TODO(#94): Check volume capability matches
242245
243246 pubVolResp := & csi.ControllerPublishVolumeResponse {
244- PublishInfo : nil ,
247+ PublishContext : nil ,
245248 }
246249
247250 _ , err = gceCS .CloudProvider .GetDisk (ctx , volKey )
@@ -352,6 +355,8 @@ func (gceCS *GCEControllerServer) ControllerUnpublishVolume(ctx context.Context,
352355
353356func (gceCS * GCEControllerServer ) ValidateVolumeCapabilities (ctx context.Context , req * csi.ValidateVolumeCapabilitiesRequest ) (* csi.ValidateVolumeCapabilitiesResponse , error ) {
354357 // TODO(#94): Factor out the volume capability functionality and use as validation in all other functions as well
358+ // TODO(#162): Implement ValidateVolumeCapabilities
359+
355360 glog .V (5 ).Infof ("Using default ValidateVolumeCapabilities" )
356361 // Validate Arguments
357362 if req .GetVolumeCapabilities () == nil || len (req .GetVolumeCapabilities ()) == 0 {
@@ -373,63 +378,68 @@ func (gceCS *GCEControllerServer) ValidateVolumeCapabilities(ctx context.Context
373378 return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown get disk error: %v" , err ))
374379 }
375380
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+ }
381391 }
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
413428 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),
415431 }, nil
416432 }
417433 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")
423435 }
424- default :
425- return nil , status .Error (codes .InvalidArgument , "ValidateVolumeCapabilities unknown topology segment key" )
426436 }
427437 }
428- }
429438
430- return & csi.ValidateVolumeCapabilitiesResponse {
431- Supported : true ,
432- }, nil
439+ return &csi.ValidateVolumeCapabilitiesResponse{
440+ Supported: true,
441+ }, nil
442+ */
433443}
434444
435445func (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
467477 return nil , status .Error (codes .NotFound , fmt .Sprintf ("Could not find volume with ID %v: %v" , volumeID , err ))
468478 }
469479
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 )
471483 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 ))
474494 }
475- return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown create snapshot error: %v" , err ))
476495 }
496+
477497 err = gceCS .validateExistingSnapshot (snapshot , volKey )
478498 if err != nil {
479499 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
482502 if err != nil {
483503 return nil , status .Error (codes .Internal , fmt .Sprintf ("Failed to covert creation timestamp: %v" , err ))
484504 }
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+
485516 createResp := & csi.CreateSnapshotResponse {
486517 Snapshot : & csi.Snapshot {
487518 SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
488- Id : cleanSelfLink (snapshot .SelfLink ),
519+ SnapshotId : cleanSelfLink (snapshot .SelfLink ),
489520 SourceVolumeId : volumeID ,
490- CreatedAt : t .UnixNano (),
491- Status : & csi.SnapshotStatus {
492- Type : convertCSISnapshotStatus (snapshot .Status ),
493- },
521+ CreationTime : tp ,
522+ ReadyToUse : ready ,
494523 },
495524 }
496525 return createResp , nil
@@ -514,22 +543,18 @@ func (gceCS *GCEControllerServer) validateExistingSnapshot(snapshot *compute.Sna
514543 return nil
515544}
516545
517- func convertCSISnapshotStatus (status string ) csi.SnapshotStatus_Type {
518- var csiStatus csi.SnapshotStatus_Type
546+ func isCSISnapshotReady (status string ) (bool , error ) {
519547 switch status {
520548 case "READY" :
521- csiStatus = csi .SnapshotStatus_READY
522- case "UPLOADING" :
523- csiStatus = csi .SnapshotStatus_UPLOADING
549+ return true , nil
524550 case "FAILED" :
525- csiStatus = csi . SnapshotStatus_ERROR_UPLOADING
551+ return false , fmt . Errorf ( "snapshot status is FAILED" )
526552 case "DELETING" :
527- csiStatus = csi .SnapshotStatus_UNKNOWN
528553 glog .V (4 ).Infof ("snapshot is in DELETING" )
554+ fallthrough
529555 default :
530- csiStatus = csi . SnapshotStatus_UNKNOWN
556+ return false , nil
531557 }
532- return csiStatus
533558}
534559
535560func (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
587612 entries := []* csi.ListSnapshotsResponse_Entry {}
588613
589614 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+ }
591619 entries = append (entries , entry )
592620 }
593621 listSnapshotResp := & csi.ListSnapshotsResponse {
@@ -614,28 +642,42 @@ func (gceCS *GCEControllerServer) getSnapshotById(ctx context.Context, snapshotI
614642 }
615643 return nil , status .Error (codes .Internal , fmt .Sprintf ("Unknown list snapshot error: %v" , err ))
616644 }
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 }
618651 //entries[0] = entry
619652 listSnapshotResp := & csi.ListSnapshotsResponse {
620653 Entries : entries ,
621654 }
622655 return listSnapshotResp , nil
623656}
624657
625- func generateSnapshotEntry (snapshot * compute.Snapshot ) * csi.ListSnapshotsResponse_Entry {
658+ func generateSnapshotEntry (snapshot * compute.Snapshot ) ( * csi.ListSnapshotsResponse_Entry , error ) {
626659 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+
627671 entry := & csi.ListSnapshotsResponse_Entry {
628672 Snapshot : & csi.Snapshot {
629673 SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
630- Id : cleanSelfLink (snapshot .SelfLink ),
674+ SnapshotId : cleanSelfLink (snapshot .SelfLink ),
631675 SourceVolumeId : cleanSelfLink (snapshot .SourceDisk ),
632- CreatedAt : t .UnixNano (),
633- Status : & csi.SnapshotStatus {
634- Type : convertCSISnapshotStatus (snapshot .Status ),
635- },
676+ CreationTime : tp ,
677+ ReadyToUse : ready ,
636678 },
637679 }
638- return entry
680+ return entry , nil
639681}
640682
641683func getRequestCapacity (capRange * csi.CapacityRange ) (int64 , error ) {
@@ -815,8 +857,8 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, capBytes int64, zones []s
815857 createResp := & csi.CreateVolumeResponse {
816858 Volume : & csi.Volume {
817859 CapacityBytes : capBytes ,
818- Id : cleanSelfLink (disk .GetSelfLink ()),
819- Attributes : nil ,
860+ VolumeId : cleanSelfLink (disk .GetSelfLink ()),
861+ VolumeContext : nil ,
820862 AccessibleTopology : tops ,
821863 },
822864 }
@@ -825,7 +867,7 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, capBytes int64, zones []s
825867 source := & csi.VolumeContentSource {
826868 Type : & csi.VolumeContentSource_Snapshot {
827869 Snapshot : & csi.VolumeContentSource_SnapshotSource {
828- Id : snapshotId ,
870+ SnapshotId : snapshotId ,
829871 },
830872 },
831873 }
0 commit comments