@@ -19,7 +19,7 @@ import (
1919 "errors"
2020 "fmt"
2121 "math/rand"
22- "regexp "
22+ neturl "net/url "
2323 "sort"
2424 "strings"
2525 "time"
@@ -130,6 +130,17 @@ const (
130130 // but 500 is a good proxy (gives ~8KB of data per ListVolumesResponse#Entry)
131131 // See https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/grpc_types.h#L503)
132132 maxListVolumesResponseEntries = 500
133+
134+ // Keys in the volume context.
135+ contextForceAttach = "force-attach"
136+
137+ resourceApiScheme = "https"
138+ resourceApiService = "compute"
139+ resourceProject = "projects"
140+ )
141+
142+ var (
143+ validResourceApiVersions = map [string ]bool {"v1" : true , "alpha" : true , "beta" : true }
133144)
134145
135146func isDiskReady (disk * gce.CloudDisk ) (bool , error ) {
@@ -306,7 +317,7 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
306317
307318 // If there is no validation error, immediately return success
308319 klog .V (4 ).Infof ("CreateVolume succeeded for disk %v, it already exists and was compatible" , volKey )
309- return generateCreateVolumeResponse (existingDisk , zones ), nil
320+ return generateCreateVolumeResponse (existingDisk , zones )
310321 }
311322
312323 snapshotID := ""
@@ -421,7 +432,7 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
421432 }
422433
423434 klog .V (4 ).Infof ("CreateVolume succeeded for disk %v" , volKey )
424- return generateCreateVolumeResponse (disk , zones ), nil
435+ return generateCreateVolumeResponse (disk , zones )
425436
426437}
427438
@@ -856,13 +867,23 @@ func (gceCS *GCEControllerServer) ListVolumes(ctx context.Context, req *csi.List
856867 entries := []* csi.ListVolumesResponse_Entry {}
857868 for i := 0 ; i + offset < len (gceCS .disks ) && i < maxEntries ; i ++ {
858869 d := gceCS .disks [i + offset ]
870+ diskRsrc , err := getResourceId (d .SelfLink )
871+ if err != nil {
872+ klog .Warningf ("Bad ListVolumes disk resource %s, skipped: %v (%+v)" , d .SelfLink , err , d )
873+ continue
874+ }
859875 users := []string {}
860876 for _ , u := range d .Users {
861- users = append (users , cleanSelfLink (u ))
877+ rsrc , err := getResourceId (u )
878+ if err != nil {
879+ klog .Warningf ("Bad ListVolumes user %s, skipped: %v" , u , err )
880+ } else {
881+ users = append (users , rsrc )
882+ }
862883 }
863884 entries = append (entries , & csi.ListVolumesResponse_Entry {
864885 Volume : & csi.Volume {
865- VolumeId : cleanSelfLink ( d . SelfLink ) ,
886+ VolumeId : diskRsrc ,
866887 },
867888 Status : & csi.ListVolumesResponse_VolumeStatus {
868889 PublishedNodeIds : users ,
@@ -975,6 +996,10 @@ func (gceCS *GCEControllerServer) createPDSnapshot(ctx context.Context, project
975996 return nil , common .LoggedError ("Failed to create snapshot: " , err )
976997 }
977998 }
999+ snapshotId , err := getResourceId (snapshot .SelfLink )
1000+ if err != nil {
1001+ return nil , common .LoggedError (fmt .Sprintf ("Cannot extract resource id from snapshot %s" , snapshot .SelfLink ), err )
1002+ }
9781003
9791004 err = gceCS .validateExistingSnapshot (snapshot , volKey )
9801005 if err != nil {
@@ -993,7 +1018,7 @@ func (gceCS *GCEControllerServer) createPDSnapshot(ctx context.Context, project
9931018
9941019 return & csi.Snapshot {
9951020 SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
996- SnapshotId : cleanSelfLink ( snapshot . SelfLink ) ,
1021+ SnapshotId : snapshotId ,
9971022 SourceVolumeId : volumeID ,
9981023 CreationTime : timestamp ,
9991024 ReadyToUse : ready ,
@@ -1022,6 +1047,10 @@ func (gceCS *GCEControllerServer) createImage(ctx context.Context, project strin
10221047 return nil , common .LoggedError ("Failed to create image: " , err )
10231048 }
10241049 }
1050+ imageId , err := getResourceId (image .SelfLink )
1051+ if err != nil {
1052+ return nil , common .LoggedError (fmt .Sprintf ("Cannot extract resource id from snapshot %s" , image .SelfLink ), err )
1053+ }
10251054
10261055 err = gceCS .validateExistingImage (image , volKey )
10271056 if err != nil {
@@ -1040,7 +1069,7 @@ func (gceCS *GCEControllerServer) createImage(ctx context.Context, project strin
10401069
10411070 return & csi.Snapshot {
10421071 SizeBytes : common .GbToBytes (image .DiskSizeGb ),
1043- SnapshotId : cleanSelfLink ( image . SelfLink ) ,
1072+ SnapshotId : imageId ,
10441073 SourceVolumeId : volumeID ,
10451074 CreationTime : timestamp ,
10461075 ReadyToUse : ready ,
@@ -1052,9 +1081,13 @@ func (gceCS *GCEControllerServer) validateExistingImage(image *compute.Image, vo
10521081 return fmt .Errorf ("disk does not exist" )
10531082 }
10541083
1055- _ , sourceKey , err := common . VolumeIDToKey ( cleanSelfLink ( image .SourceDisk ) )
1084+ sourceId , err := getResourceId ( image .SourceDisk )
10561085 if err != nil {
1057- return fmt .Errorf ("fail to get source disk key %s, %w" , image .SourceDisk , err )
1086+ return fmt .Errorf ("failed to get source id from %s: %w" , image .SourceDisk , err )
1087+ }
1088+ _ , sourceKey , err := common .VolumeIDToKey (sourceId )
1089+ if err != nil {
1090+ return fmt .Errorf ("failed to get source disk key %s: %w" , image .SourceDisk , err )
10581091 }
10591092
10601093 if sourceKey .String () != volKey .String () {
@@ -1103,7 +1136,11 @@ func (gceCS *GCEControllerServer) validateExistingSnapshot(snapshot *compute.Sna
11031136 return fmt .Errorf ("disk does not exist" )
11041137 }
11051138
1106- _ , sourceKey , err := common .VolumeIDToKey (cleanSelfLink (snapshot .SourceDisk ))
1139+ sourceId , err := getResourceId (snapshot .SourceDisk )
1140+ if err != nil {
1141+ return fmt .Errorf ("failed to get source id from %s: %w" , snapshot .SourceDisk , err )
1142+ }
1143+ _ , sourceKey , err := common .VolumeIDToKey (sourceId )
11071144 if err != nil {
11081145 return fmt .Errorf ("fail to get source disk key %s, %w" , snapshot .SourceDisk , err )
11091146 }
@@ -1146,7 +1183,7 @@ func (gceCS *GCEControllerServer) DeleteSnapshot(ctx context.Context, req *csi.D
11461183 if err != nil {
11471184 // Cannot get snapshot ID from the passing request
11481185 // This is a success according to the spec
1149- klog .Warningf ("Snapshot id does not have the correct format %s" , snapshotID )
1186+ klog .Warningf ("Snapshot id does not have the correct format %s: %v " , snapshotID , err )
11501187 return & csi.DeleteSnapshotResponse {}, nil
11511188 }
11521189
@@ -1337,7 +1374,7 @@ func (gceCS *GCEControllerServer) getSnapshotByID(ctx context.Context, snapshotI
13371374 return & csi.ListSnapshotsResponse {}, nil
13381375 }
13391376 }
1340- e , err := generateImageEntry (image )
1377+ e , err := generateDiskImageEntry (image )
13411378 if err != nil {
13421379 return nil , fmt .Errorf ("failed to generate image entry: %w" , err )
13431380 }
@@ -1359,6 +1396,15 @@ func generateDiskSnapshotEntry(snapshot *compute.Snapshot) (*csi.ListSnapshotsRe
13591396 return nil , fmt .Errorf ("Failed to covert creation timestamp: %w" , err )
13601397 }
13611398
1399+ snapshotId , err := getResourceId (snapshot .SelfLink )
1400+ if err != nil {
1401+ return nil , fmt .Errorf ("failed to get snapshot id from %s: %w" , snapshot .SelfLink , err )
1402+ }
1403+ sourceId , err := getResourceId (snapshot .SourceDisk )
1404+ if err != nil {
1405+ return nil , fmt .Errorf ("failed to get source id from %s: %w" , snapshot .SourceDisk , err )
1406+ }
1407+
13621408 // We ignore the error intentionally here since we are just listing snapshots
13631409 // TODO: If the snapshot is in "FAILED" state we need to think through what this
13641410 // should actually look like.
@@ -1367,8 +1413,8 @@ func generateDiskSnapshotEntry(snapshot *compute.Snapshot) (*csi.ListSnapshotsRe
13671413 entry := & csi.ListSnapshotsResponse_Entry {
13681414 Snapshot : & csi.Snapshot {
13691415 SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
1370- SnapshotId : cleanSelfLink ( snapshot . SelfLink ) ,
1371- SourceVolumeId : cleanSelfLink ( snapshot . SourceDisk ) ,
1416+ SnapshotId : snapshotId ,
1417+ SourceVolumeId : sourceId ,
13721418 CreationTime : tp ,
13731419 ReadyToUse : ready ,
13741420 },
@@ -1384,35 +1430,23 @@ func generateDiskImageEntry(image *compute.Image) (*csi.ListSnapshotsResponse_En
13841430 return nil , fmt .Errorf ("failed to covert creation timestamp: %w" , err )
13851431 }
13861432
1387- ready , _ := isImageReady (image .Status )
1388-
1389- entry := & csi.ListSnapshotsResponse_Entry {
1390- Snapshot : & csi.Snapshot {
1391- SizeBytes : common .GbToBytes (image .DiskSizeGb ),
1392- SnapshotId : cleanSelfLink (image .SelfLink ),
1393- SourceVolumeId : cleanSelfLink (image .SourceDisk ),
1394- CreationTime : tp ,
1395- ReadyToUse : ready ,
1396- },
1433+ imageId , err := getResourceId (image .SelfLink )
1434+ if err != nil {
1435+ return nil , fmt .Errorf ("cannot get image id from %s: %w" , image .SelfLink , err )
13971436 }
1398- return entry , nil
1399- }
1400-
1401- func generateImageEntry (image * compute.Image ) (* csi.ListSnapshotsResponse_Entry , error ) {
1402- timestamp , err := parseTimestamp (image .CreationTimestamp )
1437+ sourceId , err := getResourceId (image .SourceDisk )
14031438 if err != nil {
1404- return nil , fmt .Errorf ("Failed to covert creation timestamp : %w" , err )
1439+ return nil , fmt .Errorf ("cannot get source id from %s : %w" , image . SourceDisk , err )
14051440 }
14061441
1407- // ignore the error intentionally here since we are just listing images
14081442 ready , _ := isImageReady (image .Status )
14091443
14101444 entry := & csi.ListSnapshotsResponse_Entry {
14111445 Snapshot : & csi.Snapshot {
14121446 SizeBytes : common .GbToBytes (image .DiskSizeGb ),
1413- SnapshotId : cleanSelfLink ( image . SelfLink ) ,
1414- SourceVolumeId : cleanSelfLink ( image . SourceDisk ) ,
1415- CreationTime : timestamp ,
1447+ SnapshotId : imageId ,
1448+ SourceVolumeId : sourceId ,
1449+ CreationTime : tp ,
14161450 ReadyToUse : ready ,
14171451 },
14181452 }
@@ -1650,7 +1684,12 @@ func getDefaultZonesInRegion(ctx context.Context, gceCS *GCEControllerServer, ex
16501684 return ret , nil
16511685}
16521686
1653- func generateCreateVolumeResponse (disk * gce.CloudDisk , zones []string ) * csi.CreateVolumeResponse {
1687+ func generateCreateVolumeResponse (disk * gce.CloudDisk , zones []string ) (* csi.CreateVolumeResponse , error ) {
1688+ volumeId , err := getResourceId (disk .GetSelfLink ())
1689+ if err != nil {
1690+ return nil , fmt .Errorf ("cannot get volume id from %s: %w" , disk .GetSelfLink (), err )
1691+ }
1692+
16541693 tops := []* csi.Topology {}
16551694 for _ , zone := range zones {
16561695 tops = append (tops , & csi.Topology {
@@ -1661,7 +1700,7 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, zones []string) *csi.Crea
16611700 createResp := & csi.CreateVolumeResponse {
16621701 Volume : & csi.Volume {
16631702 CapacityBytes : realDiskSizeBytes ,
1664- VolumeId : cleanSelfLink ( disk . GetSelfLink ()) ,
1703+ VolumeId : volumeId ,
16651704 VolumeContext : nil ,
16661705 AccessibleTopology : tops ,
16671706 },
@@ -1700,12 +1739,36 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, zones []string) *csi.Crea
17001739 }
17011740 createResp .Volume .ContentSource = contentSource
17021741 }
1703- return createResp
1742+ return createResp , nil
17041743}
17051744
1706- func cleanSelfLink (selfLink string ) string {
1707- r , _ := regexp .Compile ("https:\\ /\\ /www.*apis.com\\ /.*(v1|beta|alpha)\\ /" )
1708- return r .ReplaceAllString (selfLink , "" )
1745+ func getResourceId (resourceLink string ) (string , error ) {
1746+ url , err := neturl .Parse (resourceLink )
1747+ if err != nil {
1748+ return "" , fmt .Errorf ("Could not parse resource %s: %w" , resourceLink , err )
1749+ }
1750+ if url .Scheme != resourceApiScheme {
1751+ return "" , fmt .Errorf ("Unexpected API scheme for resource %s" , resourceLink )
1752+ }
1753+
1754+ // Note that the resource host can basically be anything, if we are running in
1755+ // a distributed cloud or trusted partner environment.
1756+
1757+ // The path should be /compute/VERSION/project/....
1758+ elts := strings .Split (url .Path , "/" )
1759+ if len (elts ) < 4 {
1760+ return "" , fmt .Errorf ("Short resource path %s" , resourceLink )
1761+ }
1762+ if elts [1 ] != resourceApiService {
1763+ return "" , fmt .Errorf ("Bad resource service %s in %s" , elts [1 ], resourceLink )
1764+ }
1765+ if _ , ok := validResourceApiVersions [elts [2 ]]; ! ok {
1766+ return "" , fmt .Errorf ("Bad version %s in %s" , elts [2 ], resourceLink )
1767+ }
1768+ if elts [3 ] != resourceProject {
1769+ return "" , fmt .Errorf ("Expected %v to start with %s in resource %s" , elts [3 :], resourceProject , resourceLink )
1770+ }
1771+ return strings .Join (elts [3 :], "/" ), nil
17091772}
17101773
17111774func createRegionalDisk (ctx context.Context , cloudProvider gce.GCECompute , name string , zones []string , params common.DiskParameters , capacityRange * csi.CapacityRange , capBytes int64 , snapshotID string , volumeContentSourceVolumeID string , multiWriter bool ) (* gce.CloudDisk , error ) {
0 commit comments