@@ -179,9 +179,8 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
179
179
if err != nil {
180
180
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk %v had error checking ready status: %v" , volKey , err ))
181
181
}
182
-
183
182
if ! ready {
184
- return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk %v is not ready" , volKey ))
183
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume existing disk %v is not ready. Existing disk state= name: %v, ID: %v, status: %v, zone: %v, location-type: %v " , volKey , existingDisk . GetName (), existingDisk . GetSourceDiskId (), existingDisk . GetStatus (), existingDisk . GetZone (), existingDisk . LocationType () ))
185
184
}
186
185
187
186
// If there is no validation error, immediately return success
@@ -190,10 +189,10 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
190
189
}
191
190
192
191
snapshotID := ""
192
+ volumeContentSourceVolumeID := ""
193
193
content := req .GetVolumeContentSource ()
194
194
if content != nil {
195
195
if content .GetSnapshot () != nil {
196
- // TODO(#161): Add support for Volume Source (cloning) introduced in CSI v1.0.0
197
196
snapshotID = content .GetSnapshot ().GetSnapshotId ()
198
197
199
198
// Verify that snapshot exists
@@ -204,24 +203,56 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
204
203
return nil , status .Errorf (codes .NotFound , "CreateVolume source snapshot %s does not exist" , snapshotID )
205
204
}
206
205
}
207
- }
208
206
207
+ if content .GetVolume () != nil {
208
+ volumeContentSourceVolumeID = content .GetVolume ().GetVolumeId ()
209
+ // Verify that the source VolumeID is in the correct format.
210
+ project , volKey , err := common .VolumeIDToKey (volumeContentSourceVolumeID )
211
+ if err != nil {
212
+ return nil , status .Error (codes .InvalidArgument , fmt .Sprintf ("CreateVolume source volume ID is invalid: %v" , err ))
213
+ }
214
+
215
+ // Verify that the volume in VolumeContentSource exists.
216
+ diskFromSourceVolume , err := gceCS .CloudProvider .GetDisk (ctx , project , volKey , gceAPIVersion )
217
+ if err != nil {
218
+ if gce .IsGCEError (err , "notFound" ) {
219
+ return nil , status .Errorf (codes .NotFound , "CreateVolume source volume %s does not exist" , volumeContentSourceVolumeID )
220
+ } else {
221
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume unknown get disk error when validating: %v" , err ))
222
+ }
223
+ }
224
+ // Verify the zone, region, and disk type of the clone must be the same as that of the source disk.
225
+ if err := gce .ValidateDiskParameters (diskFromSourceVolume , params ); err != nil {
226
+ return nil , status .Errorf (codes .InvalidArgument , `CreateVolume source volume parameters do not match CreateVolumeRequest Parameters: %v` , err )
227
+ }
228
+ // Verify the source disk is ready.
229
+ if err == nil {
230
+ ready , err := isDiskReady (diskFromSourceVolume )
231
+ if err != nil {
232
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk from source volume %v had error checking ready status: %v" , volKey , err ))
233
+ }
234
+ if ! ready {
235
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk from source volume %v is not ready" , volKey ))
236
+ }
237
+ }
238
+ }
239
+ }
209
240
// Create the disk
210
241
var disk * gce.CloudDisk
211
242
switch params .ReplicationType {
212
243
case replicationTypeNone :
213
244
if len (zones ) != 1 {
214
245
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume failed to get a single zone for creating zonal disk, instead got: %v" , zones ))
215
246
}
216
- disk , err = createSingleZoneDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , multiWriter )
247
+ disk , err = createSingleZoneDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , volumeContentSourceVolumeID , multiWriter )
217
248
if err != nil {
218
249
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume failed to create single zonal disk %#v: %v" , name , err ))
219
250
}
220
251
case replicationTypeRegionalPD :
221
252
if len (zones ) != 2 {
222
253
return nil , status .Errorf (codes .Internal , fmt .Sprintf ("CreateVolume failed to get a 2 zones for creating regional disk, instead got: %v" , zones ))
223
254
}
224
- disk , err = createRegionalDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , multiWriter )
255
+ disk , err = createRegionalDisk (ctx , gceCS .CloudProvider , name , zones , params , capacityRange , capBytes , snapshotID , volumeContentSourceVolumeID , multiWriter )
225
256
if err != nil {
226
257
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume failed to create regional disk %#v: %v" , name , err ))
227
258
}
@@ -234,12 +265,11 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
234
265
return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk %v had error checking ready status: %v" , volKey , err ))
235
266
}
236
267
if ! ready {
237
- return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume disk %v is not ready" , volKey ))
268
+ return nil , status .Error (codes .Internal , fmt .Sprintf ("CreateVolume new disk %v is not ready" , volKey ))
238
269
}
239
270
240
271
klog .V (4 ).Infof ("CreateVolume succeeded for disk %v" , volKey )
241
272
return generateCreateVolumeResponse (disk , zones ), nil
242
-
243
273
}
244
274
245
275
func (gceCS * GCEControllerServer ) DeleteVolume (ctx context.Context , req * csi.DeleteVolumeRequest ) (* csi.DeleteVolumeResponse , error ) {
@@ -1053,15 +1083,28 @@ func generateCreateVolumeResponse(disk *gce.CloudDisk, zones []string) *csi.Crea
1053
1083
},
1054
1084
}
1055
1085
snapshotID := disk .GetSnapshotId ()
1056
- if snapshotID != "" {
1057
- source := & csi.VolumeContentSource {
1058
- Type : & csi.VolumeContentSource_Snapshot {
1059
- Snapshot : & csi.VolumeContentSource_SnapshotSource {
1060
- SnapshotId : snapshotID ,
1086
+ diskID := disk .GetSourceDiskId ()
1087
+ if diskID != "" || snapshotID != "" {
1088
+ contentSource := & csi.VolumeContentSource {}
1089
+ if snapshotID != "" {
1090
+ contentSource = & csi.VolumeContentSource {
1091
+ Type : & csi.VolumeContentSource_Snapshot {
1092
+ Snapshot : & csi.VolumeContentSource_SnapshotSource {
1093
+ SnapshotId : snapshotID ,
1094
+ },
1061
1095
},
1062
- },
1096
+ }
1097
+ }
1098
+ if diskID != "" {
1099
+ contentSource = & csi.VolumeContentSource {
1100
+ Type : & csi.VolumeContentSource_Volume {
1101
+ Volume : & csi.VolumeContentSource_VolumeSource {
1102
+ VolumeId : diskID ,
1103
+ },
1104
+ },
1105
+ }
1063
1106
}
1064
- createResp .Volume .ContentSource = source
1107
+ createResp .Volume .ContentSource = contentSource
1065
1108
}
1066
1109
return createResp
1067
1110
}
@@ -1072,7 +1115,7 @@ func cleanSelfLink(selfLink string) string {
1072
1115
return strings .TrimPrefix (temp , gce .GCEComputeAlphaAPIEndpoint )
1073
1116
}
1074
1117
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 ) {
1118
+ 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
1119
project := cloudProvider .GetDefaultProject ()
1077
1120
region , err := common .GetRegionFromZones (zones )
1078
1121
if err != nil {
@@ -1085,7 +1128,7 @@ func createRegionalDisk(ctx context.Context, cloudProvider gce.GCECompute, name
1085
1128
fullyQualifiedReplicaZones , cloudProvider .GetReplicaZoneURI (project , replicaZone ))
1086
1129
}
1087
1130
1088
- err = cloudProvider .InsertDisk (ctx , project , meta .RegionalKey (name , region ), params , capBytes , capacityRange , fullyQualifiedReplicaZones , snapshotID , multiWriter )
1131
+ err = cloudProvider .InsertDisk (ctx , project , meta .RegionalKey (name , region ), params , capBytes , capacityRange , fullyQualifiedReplicaZones , snapshotID , volumeContentSourceVolumeID , multiWriter )
1089
1132
if err != nil {
1090
1133
return nil , fmt .Errorf ("failed to insert regional disk: %v" , err )
1091
1134
}
@@ -1102,13 +1145,13 @@ func createRegionalDisk(ctx context.Context, cloudProvider gce.GCECompute, name
1102
1145
return disk , nil
1103
1146
}
1104
1147
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 ) {
1148
+ 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
1149
project := cloudProvider .GetDefaultProject ()
1107
1150
if len (zones ) != 1 {
1108
1151
return nil , fmt .Errorf ("got wrong number of zones for zonal create volume: %v" , len (zones ))
1109
1152
}
1110
1153
diskZone := zones [0 ]
1111
- err := cloudProvider .InsertDisk (ctx , project , meta .ZonalKey (name , diskZone ), params , capBytes , capacityRange , nil , snapshotID , multiWriter )
1154
+ err := cloudProvider .InsertDisk (ctx , project , meta .ZonalKey (name , diskZone ), params , capBytes , capacityRange , nil , snapshotID , volumeContentSourceVolumeID , multiWriter )
1112
1155
if err != nil {
1113
1156
return nil , fmt .Errorf ("failed to insert zonal disk: %v" , err )
1114
1157
}
0 commit comments