@@ -23,6 +23,7 @@ import (
23
23
"sort"
24
24
"strings"
25
25
"time"
26
+ neturl "net/url"
26
27
27
28
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
28
29
csi "github.com/container-storage-interface/spec/lib/go/csi"
@@ -138,6 +139,15 @@ const (
138
139
139
140
// Keys in the volume context.
140
141
contextForceAttach = "force-attach"
142
+
143
+ resourceApiScheme = "https"
144
+ resourceApiService = "compute"
145
+ resourceProject = "projects"
146
+ )
147
+
148
+ var (
149
+ resourceApiHost = regexp .MustCompile ("^www.*apis.com$" )
150
+ validResourceApiVersions = map [string ]bool {"v1" : true , "alpha" : true , "beta" : true }
141
151
)
142
152
143
153
func isDiskReady (disk * gce.CloudDisk ) (bool , error ) {
@@ -319,7 +329,7 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
319
329
320
330
// If there is no validation error, immediately return success
321
331
klog .V (4 ).Infof ("CreateVolume succeeded for disk %v, it already exists and was compatible" , volKey )
322
- return generateCreateVolumeResponse (existingDisk , zones , params ), nil
332
+ return generateCreateVolumeResponse (existingDisk , zones , params )
323
333
}
324
334
325
335
snapshotID := ""
@@ -434,7 +444,7 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
434
444
}
435
445
436
446
klog .V (4 ).Infof ("CreateVolume succeeded for disk %v" , volKey )
437
- return generateCreateVolumeResponse (disk , zones , params ), nil
447
+ return generateCreateVolumeResponse (disk , zones , params )
438
448
439
449
}
440
450
@@ -869,13 +879,23 @@ func (gceCS *GCEControllerServer) ListVolumes(ctx context.Context, req *csi.List
869
879
entries := []* csi.ListVolumesResponse_Entry {}
870
880
for i := 0 ; i + offset < len (gceCS .disks ) && i < maxEntries ; i ++ {
871
881
d := gceCS .disks [i + offset ]
882
+ diskRsrc , err := getResourceId (d .SelfLink )
883
+ if err != nil {
884
+ klog .Warningf ("Bad ListVolumes disk resource %s, skipped: %v (%+v)" , d .SelfLink , err , d )
885
+ continue
886
+ }
872
887
users := []string {}
873
888
for _ , u := range d .Users {
874
- users = append (users , cleanSelfLink (u ))
889
+ rsrc , err := getResourceId (u )
890
+ if err != nil {
891
+ klog .Warningf ("Bad ListVolumes user %s, skipped: %v" , u , err )
892
+ } else {
893
+ users = append (users , rsrc )
894
+ }
875
895
}
876
896
entries = append (entries , & csi.ListVolumesResponse_Entry {
877
897
Volume : & csi.Volume {
878
- VolumeId : cleanSelfLink ( d . SelfLink ) ,
898
+ VolumeId : diskRsrc ,
879
899
},
880
900
Status : & csi.ListVolumesResponse_VolumeStatus {
881
901
PublishedNodeIds : users ,
@@ -988,6 +1008,10 @@ func (gceCS *GCEControllerServer) createPDSnapshot(ctx context.Context, project
988
1008
return nil , common .LoggedError ("Failed to create snapshot: " , err )
989
1009
}
990
1010
}
1011
+ snapshotId , err := getResourceId (snapshot .SelfLink )
1012
+ if err != nil {
1013
+ return nil , common .LoggedError (fmt .Sprintf ("Cannot extract resource id from snapshot %s" , snapshot .SelfLink ), err )
1014
+ }
991
1015
992
1016
err = gceCS .validateExistingSnapshot (snapshot , volKey )
993
1017
if err != nil {
@@ -1006,7 +1030,7 @@ func (gceCS *GCEControllerServer) createPDSnapshot(ctx context.Context, project
1006
1030
1007
1031
return & csi.Snapshot {
1008
1032
SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
1009
- SnapshotId : cleanSelfLink ( snapshot . SelfLink ) ,
1033
+ SnapshotId : snapshotId ,
1010
1034
SourceVolumeId : volumeID ,
1011
1035
CreationTime : timestamp ,
1012
1036
ReadyToUse : ready ,
@@ -1035,6 +1059,10 @@ func (gceCS *GCEControllerServer) createImage(ctx context.Context, project strin
1035
1059
return nil , common .LoggedError ("Failed to create image: " , err )
1036
1060
}
1037
1061
}
1062
+ imageId , err := getResourceId (image .SelfLink )
1063
+ if err != nil {
1064
+ return nil , common .LoggedError (fmt .Sprintf ("Cannot extract resource id from snapshot %s" , image .SelfLink ), err )
1065
+ }
1038
1066
1039
1067
err = gceCS .validateExistingImage (image , volKey )
1040
1068
if err != nil {
@@ -1053,7 +1081,7 @@ func (gceCS *GCEControllerServer) createImage(ctx context.Context, project strin
1053
1081
1054
1082
return & csi.Snapshot {
1055
1083
SizeBytes : common .GbToBytes (image .DiskSizeGb ),
1056
- SnapshotId : cleanSelfLink ( image . SelfLink ) ,
1084
+ SnapshotId : imageId ,
1057
1085
SourceVolumeId : volumeID ,
1058
1086
CreationTime : timestamp ,
1059
1087
ReadyToUse : ready ,
@@ -1065,9 +1093,13 @@ func (gceCS *GCEControllerServer) validateExistingImage(image *compute.Image, vo
1065
1093
return fmt .Errorf ("disk does not exist" )
1066
1094
}
1067
1095
1068
- _ , sourceKey , err := common .VolumeIDToKey (cleanSelfLink (image .SourceDisk ))
1096
+ sourceId , err := getResourceId (image .SourceDisk )
1097
+ if err != nil {
1098
+ return fmt .Errorf ("failed to get source id from %s: %w" , image .SourceDisk , err )
1099
+ }
1100
+ _ , sourceKey , err := common .VolumeIDToKey (sourceId )
1069
1101
if err != nil {
1070
- return fmt .Errorf ("fail to get source disk key %s, %w" , image .SourceDisk , err )
1102
+ return fmt .Errorf ("failed to get source disk key %s: %w" , image .SourceDisk , err )
1071
1103
}
1072
1104
1073
1105
if sourceKey .String () != volKey .String () {
@@ -1116,7 +1148,11 @@ func (gceCS *GCEControllerServer) validateExistingSnapshot(snapshot *compute.Sna
1116
1148
return fmt .Errorf ("disk does not exist" )
1117
1149
}
1118
1150
1119
- _ , sourceKey , err := common .VolumeIDToKey (cleanSelfLink (snapshot .SourceDisk ))
1151
+ sourceId , err := getResourceId (snapshot .SourceDisk )
1152
+ if err != nil {
1153
+ return fmt .Errorf ("failed to get source id from %s: %w" , snapshot .SourceDisk , err )
1154
+ }
1155
+ _ , sourceKey , err := common .VolumeIDToKey (sourceId )
1120
1156
if err != nil {
1121
1157
return fmt .Errorf ("fail to get source disk key %s, %w" , snapshot .SourceDisk , err )
1122
1158
}
@@ -1159,7 +1195,7 @@ func (gceCS *GCEControllerServer) DeleteSnapshot(ctx context.Context, req *csi.D
1159
1195
if err != nil {
1160
1196
// Cannot get snapshot ID from the passing request
1161
1197
// This is a success according to the spec
1162
- klog .Warningf ("Snapshot id does not have the correct format %s" , snapshotID )
1198
+ klog .Warningf ("Snapshot id does not have the correct format %s: %v " , snapshotID , err )
1163
1199
return & csi.DeleteSnapshotResponse {}, nil
1164
1200
}
1165
1201
@@ -1350,7 +1386,7 @@ func (gceCS *GCEControllerServer) getSnapshotByID(ctx context.Context, snapshotI
1350
1386
return & csi.ListSnapshotsResponse {}, nil
1351
1387
}
1352
1388
}
1353
- e , err := generateImageEntry (image )
1389
+ e , err := generateDiskImageEntry (image )
1354
1390
if err != nil {
1355
1391
return nil , fmt .Errorf ("failed to generate image entry: %w" , err )
1356
1392
}
@@ -1372,6 +1408,15 @@ func generateDiskSnapshotEntry(snapshot *compute.Snapshot) (*csi.ListSnapshotsRe
1372
1408
return nil , fmt .Errorf ("Failed to covert creation timestamp: %w" , err )
1373
1409
}
1374
1410
1411
+ snapshotId , err := getResourceId (snapshot .SelfLink )
1412
+ if err != nil {
1413
+ return nil , fmt .Errorf ("failed to get snapshot id from %s: %w" , snapshot .SelfLink , err )
1414
+ }
1415
+ sourceId , err := getResourceId (snapshot .SourceDisk )
1416
+ if err != nil {
1417
+ return nil , fmt .Errorf ("failed to get source id from %s: %w" , snapshot .SourceDisk , err )
1418
+ }
1419
+
1375
1420
// We ignore the error intentionally here since we are just listing snapshots
1376
1421
// TODO: If the snapshot is in "FAILED" state we need to think through what this
1377
1422
// should actually look like.
@@ -1380,8 +1425,8 @@ func generateDiskSnapshotEntry(snapshot *compute.Snapshot) (*csi.ListSnapshotsRe
1380
1425
entry := & csi.ListSnapshotsResponse_Entry {
1381
1426
Snapshot : & csi.Snapshot {
1382
1427
SizeBytes : common .GbToBytes (snapshot .DiskSizeGb ),
1383
- SnapshotId : cleanSelfLink ( snapshot . SelfLink ) ,
1384
- SourceVolumeId : cleanSelfLink ( snapshot . SourceDisk ) ,
1428
+ SnapshotId : snapshotId ,
1429
+ SourceVolumeId : sourceId ,
1385
1430
CreationTime : tp ,
1386
1431
ReadyToUse : ready ,
1387
1432
},
@@ -1397,35 +1442,23 @@ func generateDiskImageEntry(image *compute.Image) (*csi.ListSnapshotsResponse_En
1397
1442
return nil , fmt .Errorf ("failed to covert creation timestamp: %w" , err )
1398
1443
}
1399
1444
1400
- ready , _ := isImageReady (image .Status )
1401
-
1402
- entry := & csi.ListSnapshotsResponse_Entry {
1403
- Snapshot : & csi.Snapshot {
1404
- SizeBytes : common .GbToBytes (image .DiskSizeGb ),
1405
- SnapshotId : cleanSelfLink (image .SelfLink ),
1406
- SourceVolumeId : cleanSelfLink (image .SourceDisk ),
1407
- CreationTime : tp ,
1408
- ReadyToUse : ready ,
1409
- },
1445
+ imageId , err := getResourceId (image .SelfLink )
1446
+ if err != nil {
1447
+ return nil , fmt .Errorf ("cannot get image id from %s: %w" , image .SelfLink , err )
1410
1448
}
1411
- return entry , nil
1412
- }
1413
-
1414
- func generateImageEntry (image * compute.Image ) (* csi.ListSnapshotsResponse_Entry , error ) {
1415
- timestamp , err := parseTimestamp (image .CreationTimestamp )
1449
+ sourceId , err := getResourceId (image .SourceDisk )
1416
1450
if err != nil {
1417
- return nil , fmt .Errorf ("Failed to covert creation timestamp : %w" , err )
1451
+ return nil , fmt .Errorf ("cannot get source id from %s : %w" , image . SourceDisk , err )
1418
1452
}
1419
1453
1420
- // ignore the error intentionally here since we are just listing images
1421
1454
ready , _ := isImageReady (image .Status )
1422
1455
1423
1456
entry := & csi.ListSnapshotsResponse_Entry {
1424
1457
Snapshot : & csi.Snapshot {
1425
1458
SizeBytes : common .GbToBytes (image .DiskSizeGb ),
1426
- SnapshotId : cleanSelfLink ( image . SelfLink ) ,
1427
- SourceVolumeId : cleanSelfLink ( image . SourceDisk ) ,
1428
- CreationTime : timestamp ,
1459
+ SnapshotId : imageId ,
1460
+ SourceVolumeId : sourceId ,
1461
+ CreationTime : tp ,
1429
1462
ReadyToUse : ready ,
1430
1463
},
1431
1464
}
@@ -1691,7 +1724,12 @@ func extractVolumeContext(context map[string]string) (*PDCSIContext, error) {
1691
1724
return info , nil
1692
1725
}
1693
1726
1694
- func generateCreateVolumeResponse (disk * gce.CloudDisk , zones []string , params common.DiskParameters ) * csi.CreateVolumeResponse {
1727
+ func generateCreateVolumeResponse (disk * gce.CloudDisk , zones []string , params common.DiskParameters ) (* csi.CreateVolumeResponse , error ) {
1728
+ volumeId , err := getResourceId (disk .GetSelfLink ())
1729
+ if err != nil {
1730
+ return nil , fmt .Errorf ("cannot get volume id from %s: %w" , disk .GetSelfLink (), err )
1731
+ }
1732
+
1695
1733
tops := []* csi.Topology {}
1696
1734
for _ , zone := range zones {
1697
1735
tops = append (tops , & csi.Topology {
@@ -1702,7 +1740,7 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, zones []string, params co
1702
1740
createResp := & csi.CreateVolumeResponse {
1703
1741
Volume : & csi.Volume {
1704
1742
CapacityBytes : realDiskSizeBytes ,
1705
- VolumeId : cleanSelfLink ( disk . GetSelfLink ()) ,
1743
+ VolumeId : volumeId ,
1706
1744
VolumeContext : paramsToVolumeContext (params ),
1707
1745
AccessibleTopology : tops ,
1708
1746
},
@@ -1741,12 +1779,35 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, zones []string, params co
1741
1779
}
1742
1780
createResp .Volume .ContentSource = contentSource
1743
1781
}
1744
- return createResp
1782
+ return createResp , nil
1745
1783
}
1746
1784
1747
- func cleanSelfLink (selfLink string ) string {
1748
- r , _ := regexp .Compile ("https:\\ /\\ /www.*apis.com\\ /.*(v1|beta|alpha)\\ /" )
1749
- return r .ReplaceAllString (selfLink , "" )
1785
+ func getResourceId (resourceLink string ) (string , error ) {
1786
+ url , err := neturl .Parse (resourceLink )
1787
+ if err != nil {
1788
+ return "" , fmt .Errorf ("Could not parse resource %s: %w" , resourceLink , err )
1789
+ }
1790
+ if url .Scheme != resourceApiScheme {
1791
+ return "" , fmt .Errorf ("Unexpected API scheme for resource %s" , resourceLink )
1792
+ }
1793
+ if ! resourceApiHost .MatchString (url .Host ) {
1794
+ return "" , fmt .Errorf ("Unexpected API host for resource %s" , resourceLink )
1795
+ }
1796
+ // The path should be /compute/VERSION/project/....
1797
+ elts := strings .Split (url .Path , "/" )
1798
+ if len (elts ) < 4 {
1799
+ return "" , fmt .Errorf ("Short resource path %s" , resourceLink )
1800
+ }
1801
+ if elts [1 ] != resourceApiService {
1802
+ return "" , fmt .Errorf ("Bad resource service %s in %s" , elts [1 ], resourceLink )
1803
+ }
1804
+ if _ , ok := validResourceApiVersions [elts [2 ]]; ! ok {
1805
+ return "" , fmt .Errorf ("Bad version %s in %s" , elts [2 ], resourceLink )
1806
+ }
1807
+ if elts [3 ] != resourceProject {
1808
+ return "" , fmt .Errorf ("Expected %v to start with %s in resource %s" , elts [3 :], resourceProject , resourceLink )
1809
+ }
1810
+ return strings .Join (elts [3 :], "/" ), nil
1750
1811
}
1751
1812
1752
1813
func 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