@@ -190,10 +190,10 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
190
190
}
191
191
192
192
snapshotID := ""
193
+ volumeContentSourceVolumeID := ""
193
194
content := req .GetVolumeContentSource ()
194
195
if content != nil {
195
196
if content .GetSnapshot () != nil {
196
- // TODO(#161): Add support for Volume Source (cloning) introduced in CSI v1.0.0
197
197
snapshotID = content .GetSnapshot ().GetSnapshotId ()
198
198
199
199
// Verify that snapshot exists
@@ -204,24 +204,60 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
204
204
return nil , status .Errorf (codes .NotFound , "CreateVolume source snapshot %s does not exist" , snapshotID )
205
205
}
206
206
}
207
- }
208
207
208
+ if content .GetVolume () != nil {
209
+ volumeContentSourceVolumeID = content .GetVolume ().GetVolumeId ()
210
+
211
+ // Verify that the source VolumeID is in the correct format.
212
+ project , volKey , err := common .VolumeIDToKey (volumeContentSourceVolumeID )
213
+ if err != nil {
214
+ return nil , status .Error (codes .InvalidArgument , fmt .Sprintf ("CreateVolume source volume ID is invalid: %v" , err ))
215
+ }
216
+ // Verify that the volume in VolumeContentSource exists.
217
+ diskFromSourceVolume , err := gceCS .CloudProvider .GetDisk (ctx , project , volKey , gceAPIVersion )
218
+ if err != nil {
219
+ if gce .IsGCEError (err , "notFound" ) {
220
+ return nil , status .Errorf (codes .NotFound , "CreateVolume source volume %s does not exist" , volumeContentSourceVolumeID )
221
+ } else {
222
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume unknown get disk error when validating: %v" , err ))
223
+ }
224
+ }
225
+
226
+ // Verify the zone, region, and disk type of the clone must be the same as that of the source disk.
227
+ if err := gce .ValidateDiskParameters (diskFromSourceVolume , params ); err != nil {
228
+ return nil , status .Errorf (codes .InvalidArgument , `CreateVolume source volume parameters do not match CreateVolumeRequest Parameters: %v` , err )
229
+ }
230
+
231
+ // Verify the source disk is ready.
232
+ if err == nil {
233
+ ready , err := isDiskReady (diskFromSourceVolume )
234
+ if err != nil {
235
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk from source volume %v had error checking ready status: %v" , volKey , err ))
236
+ }
237
+ if ! ready {
238
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk from source volume %v is not ready" , volKey ))
239
+ }
240
+ }
241
+ //TODO does this go inside of err == nil?
242
+
243
+ }
244
+ }
209
245
// Create the disk
210
246
var disk * gce.CloudDisk
211
247
switch params .ReplicationType {
212
248
case replicationTypeNone :
213
249
if len (zones ) != 1 {
214
250
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume failed to get a single zone for creating zonal disk, instead got: %v" , zones ))
215
251
}
216
- disk , err = createSingleZoneDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , multiWriter )
252
+ disk , err = createSingleZoneDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , volumeContentSourceVolumeID , multiWriter )
217
253
if err != nil {
218
254
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume failed to create single zonal disk %#v: %v" , name , err ))
219
255
}
220
256
case replicationTypeRegionalPD :
221
257
if len (zones ) != 2 {
222
258
return nil , status .Errorf (codes .Internal , fmt .Sprintf ("CreateVolume failed to get a 2 zones for creating regional disk, instead got: %v" , zones ))
223
259
}
224
- disk , err = createRegionalDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , multiWriter )
260
+ disk , err = createRegionalDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , volumeContentSourceVolumeID , multiWriter )
225
261
if err != nil {
226
262
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume failed to create regional disk %#v: %v" , name , err ))
227
263
}
@@ -1053,15 +1089,29 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, zones []string) *csi.Crea
1053
1089
},
1054
1090
}
1055
1091
snapshotID := disk .GetSnapshotId ()
1056
- if snapshotID != "" {
1057
- source := & csi.VolumeContentSource {
1058
- Type : & csi.VolumeContentSource_Snapshot {
1059
- Snapshot : & csi.VolumeContentSource_SnapshotSource {
1060
- SnapshotId : snapshotID ,
1092
+ diskID := disk .GetDiskId ()
1093
+ if diskID != "" || snapshotID != "" {
1094
+ contentSource := & csi.VolumeContentSource {}
1095
+ if snapshotID != "" {
1096
+ contentSource = & csi.VolumeContentSource {
1097
+ Type : & csi.VolumeContentSource_Snapshot {
1098
+ Snapshot : & csi.VolumeContentSource_SnapshotSource {
1099
+ SnapshotId : snapshotID ,
1100
+ },
1061
1101
},
1062
- },
1102
+ }
1103
+ }
1104
+ diskID := disk .GetDiskId ()
1105
+ if diskID != "" {
1106
+ contentSource = & csi.VolumeContentSource {
1107
+ Type : & csi.VolumeContentSource_Volume {
1108
+ Volume : & csi.VolumeContentSource_VolumeSource {
1109
+ VolumeId : diskID ,
1110
+ },
1111
+ },
1112
+ }
1063
1113
}
1064
- createResp .Volume .ContentSource = source
1114
+ createResp .Volume .ContentSource = contentSource
1065
1115
}
1066
1116
return createResp
1067
1117
}
@@ -1072,7 +1122,7 @@ func cleanSelfLink(selfLink string) string {
1072
1122
return strings .TrimPrefix (temp , gce .GCEComputeAlphaAPIEndpoint )
1073
1123
}
1074
1124
1075
- func createRegionalDisk (ctx context.Context , cloudProvider gce.GCECompute , name string , zones []string , params common.DiskParameters , capacityRange * csi.CapacityRange , capBytes int64 , snapshotID string , multiWriter bool ) (* gce.CloudDisk , error ) {
1125
+ 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 ) {
1076
1126
project := cloudProvider .GetDefaultProject ()
1077
1127
region , err := common .GetRegionFromZones (zones )
1078
1128
if err != nil {
@@ -1085,7 +1135,7 @@ func createRegionalDisk(ctx context.Context, cloudProvider gce.GCECompute, name
1085
1135
fullyQualifiedReplicaZones , cloudProvider .GetReplicaZoneURI (project , replicaZone ))
1086
1136
}
1087
1137
1088
- err = cloudProvider .InsertDisk (ctx , project , meta .RegionalKey (name , region ), params , capBytes , capacityRange , fullyQualifiedReplicaZones , snapshotID , multiWriter )
1138
+ err = cloudProvider .InsertDisk (ctx , project , meta .RegionalKey (name , region ), params , capBytes , capacityRange , fullyQualifiedReplicaZones , snapshotID , volumeContentSourceVolumeID , multiWriter )
1089
1139
if err != nil {
1090
1140
return nil , fmt .Errorf ("failed to insert regional disk: %v" , err )
1091
1141
}
@@ -1102,13 +1152,13 @@ func createRegionalDisk(ctx context.Context, cloudProvider gce.GCECompute, name
1102
1152
return disk , nil
1103
1153
}
1104
1154
1105
- func createSingleZoneDisk (ctx context.Context , cloudProvider gce.GCECompute , name string , zones []string , params common.DiskParameters , capacityRange * csi.CapacityRange , capBytes int64 , snapshotID string , multiWriter bool ) (* gce.CloudDisk , error ) {
1155
+ func createSingleZoneDisk (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 ) {
1106
1156
project := cloudProvider .GetDefaultProject ()
1107
1157
if len (zones ) != 1 {
1108
1158
return nil , fmt .Errorf ("got wrong number of zones for zonal create volume: %v" , len (zones ))
1109
1159
}
1110
1160
diskZone := zones [0 ]
1111
- err := cloudProvider .InsertDisk (ctx , project , meta .ZonalKey (name , diskZone ), params , capBytes , capacityRange , nil , snapshotID , multiWriter )
1161
+ err := cloudProvider .InsertDisk (ctx , project , meta .ZonalKey (name , diskZone ), params , capBytes , capacityRange , nil , snapshotID , volumeContentSourceVolumeID , multiWriter )
1112
1162
if err != nil {
1113
1163
return nil , fmt .Errorf ("failed to insert zonal disk: %v" , err )
1114
1164
}
0 commit comments