Skip to content

Commit 005e63d

Browse files
committed
added volume cloning
1 parent 06f0ed9 commit 005e63d

File tree

64 files changed

+349
-1150
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+349
-1150
lines changed

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
ARG BUILDPLATFORM
1616

17-
FROM --platform=$BUILDPLATFORM golang:1.13.15 as builder
17+
FROM --platform=$BUILDPLATFORM golang:1.17.2 as builder
1818

1919
ARG STAGINGVERSION
2020
ARG TARGETPLATFORM

deploy/kubernetes/images/prow-gke-release-staging-rc-master/image.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,6 @@ metadata:
5252
name: imagetag-csi-gce-driver-prow-rc
5353
imageTag:
5454
name: k8s.gcr.io/cloud-provider-gcp/gcp-compute-persistent-disk-csi-driver
55-
newTag: "v1.3.1"
55+
newName: gcr.io/k8s-staging-cloud-provider-gcp/gcp-compute-persistent-disk-csi-driver
56+
newTag: "v1.3.4-rc1"
5657
---

go.mod

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module sigs.k8s.io/gcp-compute-persistent-disk-csi-driver
22

3-
go 1.13
3+
go 1.17
44

55
require (
66
cloud.google.com/go v0.65.0
@@ -29,6 +29,53 @@ require (
2929
k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9
3030
)
3131

32+
require (
33+
github.com/Microsoft/go-winio v0.4.16 // indirect
34+
github.com/beorn7/perks v1.0.1 // indirect
35+
github.com/blang/semver v3.5.1+incompatible // indirect
36+
github.com/cespare/xxhash/v2 v2.1.1 // indirect
37+
github.com/davecgh/go-spew v1.1.1 // indirect
38+
github.com/fsnotify/fsnotify v1.4.9 // indirect
39+
github.com/go-logr/logr v0.4.0 // indirect
40+
github.com/gogo/protobuf v1.3.2 // indirect
41+
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
42+
github.com/google/go-cmp v0.5.5 // indirect
43+
github.com/google/gofuzz v1.1.0 // indirect
44+
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
45+
github.com/googleapis/gnostic v0.5.5 // indirect
46+
github.com/hashicorp/errwrap v1.0.0 // indirect
47+
github.com/hashicorp/go-multierror v1.0.0 // indirect
48+
github.com/imdario/mergo v0.3.8 // indirect
49+
github.com/json-iterator/go v1.1.11 // indirect
50+
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
51+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
52+
github.com/modern-go/reflect2 v1.0.1 // indirect
53+
github.com/nxadm/tail v1.4.5 // indirect
54+
github.com/pkg/errors v0.9.1 // indirect
55+
github.com/prometheus/client_golang v1.11.0 // indirect
56+
github.com/prometheus/client_model v0.2.0 // indirect
57+
github.com/prometheus/common v0.26.0 // indirect
58+
github.com/prometheus/procfs v0.6.0 // indirect
59+
github.com/sirupsen/logrus v1.8.1 // indirect
60+
github.com/spf13/pflag v1.0.5 // indirect
61+
go.opencensus.io v0.22.4 // indirect
62+
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 // indirect
63+
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
64+
golang.org/x/text v0.3.6 // indirect
65+
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
66+
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
67+
google.golang.org/appengine v1.6.6 // indirect
68+
google.golang.org/protobuf v1.26.0 // indirect
69+
gopkg.in/inf.v0 v0.9.1 // indirect
70+
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
71+
gopkg.in/yaml.v2 v2.4.0 // indirect
72+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
73+
k8s.io/api v0.22.0 // indirect
74+
k8s.io/klog/v2 v2.9.0 // indirect
75+
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
76+
sigs.k8s.io/yaml v1.2.0 // indirect
77+
)
78+
3279
replace (
3380
k8s.io/api => k8s.io/api v0.22.0
3481
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.22.0

pkg/gce-cloud-provider/compute/cloud-disk.go

+11
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,17 @@ func (d *CloudDisk) GetSnapshotId() string {
177177
}
178178
}
179179

180+
func (d *CloudDisk) GetSourceDiskId() string {
181+
switch {
182+
case d.disk != nil:
183+
return d.disk.SourceDiskId
184+
case d.betaDisk != nil:
185+
return d.betaDisk.SourceDiskId
186+
default:
187+
return ""
188+
}
189+
}
190+
180191
func (d *CloudDisk) GetKMSKeyName() string {
181192
switch {
182193
case d.disk != nil:

pkg/gce-cloud-provider/compute/fake-gce.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ func (cloud *FakeCloudProvider) ValidateExistingDisk(ctx context.Context, resp *
220220
return ValidateDiskParameters(resp, params)
221221
}
222222

223-
func (cloud *FakeCloudProvider) InsertDisk(ctx context.Context, project string, volKey *meta.Key, params common.DiskParameters, capBytes int64, capacityRange *csi.CapacityRange, replicaZones []string, snapshotID string, multiWriter bool) error {
223+
func (cloud *FakeCloudProvider) InsertDisk(ctx context.Context, project string, volKey *meta.Key, params common.DiskParameters, capBytes int64, capacityRange *csi.CapacityRange, replicaZones []string, snapshotID string, volumeContentSourceVolumeID string, multiWriter bool) error {
224224
if disk, ok := cloud.disks[volKey.Name]; ok {
225225
err := cloud.ValidateExistingDisk(ctx, disk, params,
226226
int64(capacityRange.GetRequiredBytes()),
@@ -237,6 +237,7 @@ func (cloud *FakeCloudProvider) InsertDisk(ctx context.Context, project string,
237237
Description: "Disk created by GCE-PD CSI Driver",
238238
Type: cloud.GetDiskTypeURI(project, volKey, params.DiskType),
239239
SourceSnapshotId: snapshotID,
240+
SourceDiskId: volumeContentSourceVolumeID,
240241
Status: cloud.mockDiskStatus,
241242
Labels: params.Labels,
242243
}

pkg/gce-cloud-provider/compute/gce-compute.go

+12-4
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ type GCECompute interface {
5656
GetDisk(ctx context.Context, project string, volumeKey *meta.Key, gceAPIVersion GCEAPIVersion) (*CloudDisk, error)
5757
RepairUnderspecifiedVolumeKey(ctx context.Context, project string, volumeKey *meta.Key) (string, *meta.Key, error)
5858
ValidateExistingDisk(ctx context.Context, disk *CloudDisk, params common.DiskParameters, reqBytes, limBytes int64, multiWriter bool) error
59-
InsertDisk(ctx context.Context, project string, volKey *meta.Key, params common.DiskParameters, capBytes int64, capacityRange *csi.CapacityRange, replicaZones []string, snapshotID string, multiWriter bool) error
59+
InsertDisk(ctx context.Context, project string, volKey *meta.Key, params common.DiskParameters, capBytes int64, capacityRange *csi.CapacityRange, replicaZones []string, snapshotID string, volumeContentSourceVolumeID string, multiWriter bool) error
6060
DeleteDisk(ctx context.Context, project string, volumeKey *meta.Key) error
6161
AttachDisk(ctx context.Context, project string, volKey *meta.Key, readWrite, diskType, instanceZone, instanceName string) error
6262
DetachDisk(ctx context.Context, project, deviceName, instanceZone, instanceName string) error
@@ -315,7 +315,7 @@ func ValidateDiskParameters(disk *CloudDisk, params common.DiskParameters) error
315315
return nil
316316
}
317317

318-
func (cloud *CloudProvider) InsertDisk(ctx context.Context, project string, volKey *meta.Key, params common.DiskParameters, capBytes int64, capacityRange *csi.CapacityRange, replicaZones []string, snapshotID string, multiWriter bool) error {
318+
func (cloud *CloudProvider) InsertDisk(ctx context.Context, project string, volKey *meta.Key, params common.DiskParameters, capBytes int64, capacityRange *csi.CapacityRange, replicaZones []string, snapshotID string, volumeContentSourceVolumeID string, multiWriter bool) error {
319319
klog.V(5).Infof("Inserting disk %v", volKey)
320320

321321
description, err := encodeDiskTags(params.Tags)
@@ -328,12 +328,12 @@ func (cloud *CloudProvider) InsertDisk(ctx context.Context, project string, volK
328328
if description == "" {
329329
description = "Disk created by GCE-PD CSI Driver"
330330
}
331-
return cloud.insertZonalDisk(ctx, project, volKey, params, capBytes, capacityRange, snapshotID, description, multiWriter)
331+
return cloud.insertZonalDisk(ctx, project, volKey, params, capBytes, capacityRange, snapshotID, volumeContentSourceVolumeID, description, multiWriter)
332332
case meta.Regional:
333333
if description == "" {
334334
description = "Regional disk created by GCE-PD CSI Driver"
335335
}
336-
return cloud.insertRegionalDisk(ctx, project, volKey, params, capBytes, capacityRange, replicaZones, snapshotID, description, multiWriter)
336+
return cloud.insertRegionalDisk(ctx, project, volKey, params, capBytes, capacityRange, replicaZones, snapshotID, volumeContentSourceVolumeID, description, multiWriter)
337337
default:
338338
return fmt.Errorf("could not insert disk, key was neither zonal nor regional, instead got: %v", volKey.String())
339339
}
@@ -377,6 +377,7 @@ func (cloud *CloudProvider) insertRegionalDisk(
377377
capacityRange *csi.CapacityRange,
378378
replicaZones []string,
379379
snapshotID string,
380+
volumeContentSourceVolumeID string,
380381
description string,
381382
multiWriter bool) error {
382383
var (
@@ -399,6 +400,9 @@ func (cloud *CloudProvider) insertRegionalDisk(
399400
if snapshotID != "" {
400401
diskToCreate.SourceSnapshot = snapshotID
401402
}
403+
if volumeContentSourceVolumeID != "" {
404+
diskToCreate.SourceDisk = volumeContentSourceVolumeID
405+
}
402406
if len(replicaZones) != 0 {
403407
diskToCreate.ReplicaZones = replicaZones
404408
}
@@ -472,6 +476,7 @@ func (cloud *CloudProvider) insertZonalDisk(
472476
capBytes int64,
473477
capacityRange *csi.CapacityRange,
474478
snapshotID string,
479+
volumeContentSourceVolumeID string,
475480
description string,
476481
multiWriter bool) error {
477482
var (
@@ -495,6 +500,9 @@ func (cloud *CloudProvider) insertZonalDisk(
495500
if snapshotID != "" {
496501
diskToCreate.SourceSnapshot = snapshotID
497502
}
503+
if volumeContentSourceVolumeID != "" {
504+
diskToCreate.SourceDisk = volumeContentSourceVolumeID
505+
}
498506

499507
if params.DiskEncryptionKMSKey != "" {
500508
diskToCreate.DiskEncryptionKey = &computev1.CustomerEncryptionKey{

pkg/gce-pd-csi-driver/controller.go

+62-19
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,8 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
179179
if err != nil {
180180
return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume disk %v had error checking ready status: %v", volKey, err))
181181
}
182-
183182
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()))
185184
}
186185

187186
// If there is no validation error, immediately return success
@@ -190,10 +189,10 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
190189
}
191190

192191
snapshotID := ""
192+
volumeContentSourceVolumeID := ""
193193
content := req.GetVolumeContentSource()
194194
if content != nil {
195195
if content.GetSnapshot() != nil {
196-
// TODO(#161): Add support for Volume Source (cloning) introduced in CSI v1.0.0
197196
snapshotID = content.GetSnapshot().GetSnapshotId()
198197

199198
// Verify that snapshot exists
@@ -204,24 +203,56 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
204203
return nil, status.Errorf(codes.NotFound, "CreateVolume source snapshot %s does not exist", snapshotID)
205204
}
206205
}
207-
}
208206

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+
}
209240
// Create the disk
210241
var disk *gce.CloudDisk
211242
switch params.ReplicationType {
212243
case replicationTypeNone:
213244
if len(zones) != 1 {
214245
return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume failed to get a single zone for creating zonal disk, instead got: %v", zones))
215246
}
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)
217248
if err != nil {
218249
return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume failed to create single zonal disk %#v: %v", name, err))
219250
}
220251
case replicationTypeRegionalPD:
221252
if len(zones) != 2 {
222253
return nil, status.Errorf(codes.Internal, fmt.Sprintf("CreateVolume failed to get a 2 zones for creating regional disk, instead got: %v", zones))
223254
}
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)
225256
if err != nil {
226257
return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume failed to create regional disk %#v: %v", name, err))
227258
}
@@ -234,12 +265,11 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre
234265
return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume disk %v had error checking ready status: %v", volKey, err))
235266
}
236267
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))
238269
}
239270

240271
klog.V(4).Infof("CreateVolume succeeded for disk %v", volKey)
241272
return generateCreateVolumeResponse(disk, zones), nil
242-
243273
}
244274

245275
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
10531083
},
10541084
}
10551085
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+
},
10611095
},
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+
}
10631106
}
1064-
createResp.Volume.ContentSource = source
1107+
createResp.Volume.ContentSource = contentSource
10651108
}
10661109
return createResp
10671110
}
@@ -1072,7 +1115,7 @@ func cleanSelfLink(selfLink string) string {
10721115
return strings.TrimPrefix(temp, gce.GCEComputeAlphaAPIEndpoint)
10731116
}
10741117

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) {
10761119
project := cloudProvider.GetDefaultProject()
10771120
region, err := common.GetRegionFromZones(zones)
10781121
if err != nil {
@@ -1085,7 +1128,7 @@ func createRegionalDisk(ctx context.Context, cloudProvider gce.GCECompute, name
10851128
fullyQualifiedReplicaZones, cloudProvider.GetReplicaZoneURI(project, replicaZone))
10861129
}
10871130

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)
10891132
if err != nil {
10901133
return nil, fmt.Errorf("failed to insert regional disk: %v", err)
10911134
}
@@ -1102,13 +1145,13 @@ func createRegionalDisk(ctx context.Context, cloudProvider gce.GCECompute, name
11021145
return disk, nil
11031146
}
11041147

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) {
11061149
project := cloudProvider.GetDefaultProject()
11071150
if len(zones) != 1 {
11081151
return nil, fmt.Errorf("got wrong number of zones for zonal create volume: %v", len(zones))
11091152
}
11101153
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)
11121155
if err != nil {
11131156
return nil, fmt.Errorf("failed to insert zonal disk: %v", err)
11141157
}

0 commit comments

Comments
 (0)