diff --git a/pkg/gce-cloud-provider/compute/gce-compute.go b/pkg/gce-cloud-provider/compute/gce-compute.go index d1b5d27c3..35c120e3b 100644 --- a/pkg/gce-cloud-provider/compute/gce-compute.go +++ b/pkg/gce-cloud-provider/compute/gce-compute.go @@ -330,7 +330,7 @@ func ValidateDiskParameters(disk *CloudDisk, params common.DiskParameters) error return fmt.Errorf("actual disk replication type %v did not match expected param %s", locationType, params.ReplicationType) } - if !kmsKeyEqual( + if !KmsKeyEqual( disk.GetKMSKeyName(), /* fetchedKMSKey */ params.DiskEncryptionKMSKey /* storageClassKMSKey */) { return fmt.Errorf("actual disk KMS key name %s did not match expected param %s", disk.GetKMSKeyName(), params.DiskEncryptionKMSKey) @@ -1119,7 +1119,7 @@ func (cloud *CloudProvider) waitForSnapshotCreation(ctx context.Context, project // storageClassKMSKey - key as provided by the client // example: projects/{0}/locations/{1}/keyRings/{2}/cryptoKeys/{3} // cryptoKeyVersions should be disregarded if the rest of the key is identical. -func kmsKeyEqual(fetchedKMSKey, storageClassKMSKey string) bool { +func KmsKeyEqual(fetchedKMSKey, storageClassKMSKey string) bool { return removeCryptoKeyVersion(fetchedKMSKey) == removeCryptoKeyVersion(storageClassKMSKey) } diff --git a/pkg/gce-pd-csi-driver/controller.go b/pkg/gce-pd-csi-driver/controller.go index 1e2ef1d4c..632a1a314 100644 --- a/pkg/gce-pd-csi-driver/controller.go +++ b/pkg/gce-pd-csi-driver/controller.go @@ -243,10 +243,38 @@ func (gceCS *GCEControllerServer) CreateVolume(ctx context.Context, req *csi.Cre return nil, status.Error(codes.Internal, fmt.Sprintf("CreateVolume unknown get disk error when validating: %v", err)) } } - // Verify the zone, region, and disk type of the clone must be the same as that of the source disk. - if err := gce.ValidateDiskParameters(diskFromSourceVolume, params); err != nil { - return nil, status.Errorf(codes.InvalidArgument, `CreateVolume source volume parameters do not match CreateVolumeRequest Parameters: %v`, err) + + // Verify the disk type and encryption key of the clone are the same as that of the source disk. + if diskFromSourceVolume.GetPDType() != params.DiskType || !gce.KmsKeyEqual(diskFromSourceVolume.GetKMSKeyName(), params.DiskEncryptionKMSKey) { + return nil, status.Errorf(codes.InvalidArgument, "CreateVolume Parameters %v do not match source volume Parameters", params) + } + // Verify the disk capacity range are the same or greater as that of the source disk. + if diskFromSourceVolume.GetSizeGb() > common.BytesToGbRoundDown(capBytes) { + return nil, status.Errorf(codes.InvalidArgument, "CreateVolume disk CapacityRange %d is less than source volume CapacityRange %d", common.BytesToGbRoundDown(capBytes), diskFromSourceVolume.GetSizeGb()) + } + + if params.ReplicationType == replicationTypeNone { + // For zonal->zonal disk clones, verify the zone is the same as that of the source disk. + if sourceVolKey.Zone != volKey.Zone { + return nil, status.Errorf(codes.InvalidArgument, "CreateVolume disk zone %s does not match source volume zone %s", volKey.Zone, sourceVolKey.Zone) + } + // regional->zonal disk clones are not allowed. + if diskFromSourceVolume.LocationType() == meta.Regional { + return nil, status.Errorf(codes.InvalidArgument, "Cannot create a zonal disk clone from a regional disk") + } } + + if params.ReplicationType == replicationTypeNone { + // For regional->regional disk clones, verify the region is the same as that of the source disk. + if diskFromSourceVolume.LocationType() == meta.Regional && sourceVolKey.Region != volKey.Region { + return nil, status.Errorf(codes.InvalidArgument, "CreateVolume disk region %s does not match source volume region %s", volKey.Region, sourceVolKey.Region) + } + // For zonal->regional disk clones, verify one of the replica zones matches the source disk zone. + if diskFromSourceVolume.LocationType() == meta.Zonal && !containsZone(zones, sourceVolKey.Zone) { + return nil, status.Errorf(codes.InvalidArgument, "CreateVolume regional disk replica zones %v do not match source volume zone %s", zones, sourceVolKey.Zone) + } + } + // Verify the source disk is ready. ready, err := isDiskReady(diskFromSourceVolume) if err != nil { diff --git a/pkg/gce-pd-csi-driver/controller_test.go b/pkg/gce-pd-csi-driver/controller_test.go index a2ca8647f..3574f6117 100644 --- a/pkg/gce-pd-csi-driver/controller_test.go +++ b/pkg/gce-pd-csi-driver/controller_test.go @@ -1004,89 +1004,192 @@ func TestCreateVolumeWithVolumeSourceFromVolume(t *testing.T) { testSourceVolumeName := "test-volume-source-name" testZonalVolumeSourceID := fmt.Sprintf("projects/%s/zones/%s/disks/%s", project, zone, testSourceVolumeName) testRegionalVolumeSourceID := fmt.Sprintf("projects/%s/regions/%s/disks/%s", project, region, testSourceVolumeName) - testVolumeSourceIDDifferentZone := fmt.Sprintf("projects/%s/zones/%s/disks/%s", project, "different-zone", testSourceVolumeName) + testSecondZonalVolumeSourceID := fmt.Sprintf("projects/%s/zones/%s/disks/%s", project, "different-zone1", testSourceVolumeName) + zonalParams := map[string]string{ + common.ParameterKeyType: "test-type", common.ParameterKeyReplicationType: replicationTypeNone, + common.ParameterKeyDiskEncryptionKmsKey: "encryption-key", + } + regionalParams := map[string]string{ + common.ParameterKeyType: "test-type", common.ParameterKeyReplicationType: replicationTypeRegionalPD, + common.ParameterKeyDiskEncryptionKmsKey: "encryption-key", + } topology := &csi.TopologyRequirement{ Requisite: []*csi.Topology{ { - Segments: map[string]string{common.TopologyKeyZone: region + "-b"}, + Segments: map[string]string{common.TopologyKeyZone: zone}, }, { - Segments: map[string]string{common.TopologyKeyZone: region + "-c"}, + Segments: map[string]string{common.TopologyKeyZone: secondZone}, }, }, } - regionalParams := map[string]string{ - common.ParameterKeyType: "test-type", common.ParameterKeyReplicationType: "regional-pd", - } + // Define test cases testCases := []struct { - name string - volumeOnCloud bool - expErrCode codes.Code - sourceVolumeID string - reqParameters map[string]string - sourceReqParameters map[string]string - topology *csi.TopologyRequirement + name string + volumeOnCloud bool + expErrCode codes.Code + sourceVolumeID string + reqParameters map[string]string + sourceReqParameters map[string]string + sourceCapacityRange *csi.CapacityRange + requestCapacityRange *csi.CapacityRange + sourceTopology *csi.TopologyRequirement + requestTopology *csi.TopologyRequirement }{ { - name: "success with data source of zonal volume type", - volumeOnCloud: true, - sourceVolumeID: testZonalVolumeSourceID, - reqParameters: stdParams, - sourceReqParameters: stdParams, - }, - { - name: "success with data source of regional volume type", - volumeOnCloud: true, - sourceVolumeID: testRegionalVolumeSourceID, - reqParameters: regionalParams, - sourceReqParameters: regionalParams, - topology: topology, - }, - { - name: "fail with with data source of replication-type different from CreateVolumeRequest", - volumeOnCloud: true, - expErrCode: codes.InvalidArgument, - sourceVolumeID: testZonalVolumeSourceID, - reqParameters: stdParams, - sourceReqParameters: regionalParams, - topology: topology, - }, - { - name: "fail with data source of zonal volume type that doesn't exist", - volumeOnCloud: false, - expErrCode: codes.NotFound, - sourceVolumeID: testZonalVolumeSourceID, - reqParameters: stdParams, - sourceReqParameters: stdParams, - }, - { - name: "fail with data source of zonal volume type with invalid volume id format", - volumeOnCloud: false, - expErrCode: codes.InvalidArgument, - sourceVolumeID: testZonalVolumeSourceID + "invalid/format", - reqParameters: stdParams, - sourceReqParameters: stdParams, + name: "success zonal disk clone of zonal source disk", + volumeOnCloud: true, + sourceVolumeID: testZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: zonalParams, + sourceReqParameters: zonalParams, + sourceTopology: topology, + requestTopology: topology, + }, + { + name: "success regional disk clone of regional source disk", + volumeOnCloud: true, + sourceVolumeID: testRegionalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: regionalParams, + sourceReqParameters: regionalParams, + sourceTopology: topology, + requestTopology: topology, + }, + { + name: "success regional disk clone of zonal data source", + volumeOnCloud: true, + sourceVolumeID: testZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: regionalParams, + sourceReqParameters: zonalParams, + sourceTopology: topology, + requestTopology: topology, + }, + { + name: "fail regional disk clone with no matching replica zone of zonal data source", + volumeOnCloud: true, + expErrCode: codes.InvalidArgument, + sourceVolumeID: testZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: regionalParams, + sourceReqParameters: zonalParams, + sourceTopology: topology, + requestTopology: &csi.TopologyRequirement{ + Requisite: []*csi.Topology{ + { + Segments: map[string]string{common.TopologyKeyZone: "different-zone1"}, + }, + { + Segments: map[string]string{common.TopologyKeyZone: "different-zone2"}, + }, + }, + }, }, { - name: "fail with data source of zonal volume type with invalid disk parameters", - volumeOnCloud: true, - expErrCode: codes.InvalidArgument, - sourceVolumeID: testVolumeSourceIDDifferentZone, - reqParameters: stdParams, + name: "fail zonal disk clone with different disk type", + volumeOnCloud: true, + expErrCode: codes.InvalidArgument, + sourceVolumeID: testZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: zonalParams, sourceReqParameters: map[string]string{ common.ParameterKeyType: "different-type", }, + sourceTopology: topology, + requestTopology: topology, }, { - name: "fail with data source of zonal volume type with invalid replication type", - volumeOnCloud: true, - expErrCode: codes.InvalidArgument, - sourceVolumeID: testZonalVolumeSourceID, - reqParameters: regionalParams, - sourceReqParameters: stdParams, - }, - } + name: "fail zonal disk clone with different DiskEncryptionKMSKey", + volumeOnCloud: true, + expErrCode: codes.InvalidArgument, + sourceVolumeID: testZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: zonalParams, + sourceReqParameters: map[string]string{ + common.ParameterKeyType: "test-type", common.ParameterKeyReplicationType: replicationTypeNone, + common.ParameterKeyDiskEncryptionKmsKey: "different-encryption-key", + }, + sourceTopology: topology, + requestTopology: topology, + }, + { + name: "fail zonal disk clone with different zone", + volumeOnCloud: true, + expErrCode: codes.InvalidArgument, + sourceVolumeID: testSecondZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: zonalParams, + sourceReqParameters: zonalParams, + sourceTopology: &csi.TopologyRequirement{ + Requisite: []*csi.Topology{ + { + Segments: map[string]string{common.TopologyKeyZone: "different-zone1"}, + }, + { + Segments: map[string]string{common.TopologyKeyZone: "different-zone2"}, + }, + }, + }, + requestTopology: topology, + }, + { + name: "fail zonal disk clone of regional data source", + volumeOnCloud: true, + expErrCode: codes.InvalidArgument, + sourceVolumeID: testRegionalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: zonalParams, + sourceReqParameters: regionalParams, + sourceTopology: topology, + requestTopology: topology, + }, + + { + name: "fail zonal source disk does not exist", + volumeOnCloud: false, + expErrCode: codes.NotFound, + sourceVolumeID: testZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: stdParams, + sourceReqParameters: stdParams, + requestTopology: topology, + }, + { + name: "fail invalid source disk volume id format", + volumeOnCloud: false, + expErrCode: codes.InvalidArgument, + sourceVolumeID: testZonalVolumeSourceID + "/invalid/format", + requestCapacityRange: stdCapRange, + sourceCapacityRange: stdCapRange, + reqParameters: stdParams, + sourceReqParameters: stdParams, + requestTopology: topology, + }, + { + name: "fail zonal disk clone with smaller disk capacity", + volumeOnCloud: true, + expErrCode: codes.InvalidArgument, + sourceVolumeID: testZonalVolumeSourceID, + requestCapacityRange: stdCapRange, + sourceCapacityRange: &csi.CapacityRange{ + RequiredBytes: common.GbToBytes(40), + }, + reqParameters: zonalParams, + sourceReqParameters: zonalParams, + sourceTopology: topology, + requestTopology: topology, + }} for _, tc := range testCases { t.Logf("test case: %s", tc.name) @@ -1094,7 +1197,7 @@ func TestCreateVolumeWithVolumeSourceFromVolume(t *testing.T) { req := &csi.CreateVolumeRequest{ Name: name, - CapacityRange: stdCapRange, + CapacityRange: tc.requestCapacityRange, VolumeCapabilities: stdVolCaps, Parameters: tc.reqParameters, VolumeContentSource: &csi.VolumeContentSource{ @@ -1104,18 +1207,15 @@ func TestCreateVolumeWithVolumeSourceFromVolume(t *testing.T) { }, }, }, + AccessibilityRequirements: tc.requestTopology, } sourceVolumeRequest := &csi.CreateVolumeRequest{ - Name: testSourceVolumeName, - CapacityRange: stdCapRange, - VolumeCapabilities: stdVolCaps, - Parameters: tc.sourceReqParameters, - } - - if tc.topology != nil { - // req.AccessibilityRequirements = tc.topology - sourceVolumeRequest.AccessibilityRequirements = tc.topology + Name: testSourceVolumeName, + CapacityRange: tc.sourceCapacityRange, + VolumeCapabilities: stdVolCaps, + Parameters: tc.sourceReqParameters, + AccessibilityRequirements: tc.sourceTopology, } if tc.volumeOnCloud { @@ -1148,7 +1248,6 @@ func TestCreateVolumeWithVolumeSourceFromVolume(t *testing.T) { // Make sure the response has the source volume. sourceVolume := resp.GetVolume() - t.Logf("response has source volume: %v ", sourceVolume) if sourceVolume.ContentSource == nil || sourceVolume.ContentSource.Type == nil || sourceVolume.ContentSource.GetVolume() == nil || sourceVolume.ContentSource.GetVolume().VolumeId == "" { t.Fatalf("Expected volume content source to have volume ID, got none") diff --git a/pkg/gce-pd-csi-driver/utils.go b/pkg/gce-pd-csi-driver/utils.go index 5478971a7..4862613ab 100644 --- a/pkg/gce-pd-csi-driver/utils.go +++ b/pkg/gce-pd-csi-driver/utils.go @@ -199,3 +199,13 @@ func collectMountOptions(fsType string, mntFlags []string) []string { } return options } + +func containsZone(zones []string, zone string) bool { + for _, z := range zones { + if z == zone { + return true + } + } + + return false +} diff --git a/test/e2e/tests/multi_zone_e2e_test.go b/test/e2e/tests/multi_zone_e2e_test.go index 991072ce8..6dae9c1a6 100644 --- a/test/e2e/tests/multi_zone_e2e_test.go +++ b/test/e2e/tests/multi_zone_e2e_test.go @@ -101,7 +101,7 @@ var _ = Describe("GCE PD CSI Driver Multi-Zone", func() { Segments: map[string]string{common.TopologyKeyZone: zones[1]}, }, }, - }) + }, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created diff --git a/test/e2e/tests/resize_e2e_test.go b/test/e2e/tests/resize_e2e_test.go index 00ab12ed8..48241267b 100644 --- a/test/e2e/tests/resize_e2e_test.go +++ b/test/e2e/tests/resize_e2e_test.go @@ -45,7 +45,7 @@ var _ = Describe("GCE PD CSI Driver", func() { Segments: map[string]string{common.TopologyKeyZone: z}, }, }, - }) + }, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -152,7 +152,7 @@ var _ = Describe("GCE PD CSI Driver", func() { Segments: map[string]string{common.TopologyKeyZone: z}, }, }, - }) + }, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created & size @@ -264,7 +264,7 @@ var _ = Describe("GCE PD CSI Driver", func() { Segments: map[string]string{common.TopologyKeyZone: z}, }, }, - }) + }, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created diff --git a/test/e2e/tests/single_zone_e2e_test.go b/test/e2e/tests/single_zone_e2e_test.go index dc79d9365..023170417 100644 --- a/test/e2e/tests/single_zone_e2e_test.go +++ b/test/e2e/tests/single_zone_e2e_test.go @@ -246,7 +246,7 @@ var _ = Describe("GCE PD CSI Driver", func() { }, }, } - volID, err := testContext.Client.CreateVolume(volName, nil, defaultSizeGb, topReq) + volID, err := testContext.Client.CreateVolume(volName, nil, defaultSizeGb, topReq, nil) Expect(err).To(BeNil(), "Failed to create volume") defer func() { err = testContext.Client.DeleteVolume(volID) @@ -302,7 +302,7 @@ var _ = Describe("GCE PD CSI Driver", func() { volName := testNamePrefix + string(uuid.NewUUID()) volID, err := controllerClient.CreateVolume(volName, map[string]string{ common.ParameterKeyReplicationType: "regional-pd", - }, defaultRepdSizeGb, nil) + }, defaultRepdSizeGb, nil, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -340,7 +340,7 @@ var _ = Describe("GCE PD CSI Driver", func() { // Create Disk volName := testNamePrefix + string(uuid.NewUUID()) - volID, err := client.CreateVolume(volName, nil, defaultSizeGb, nil) + volID, err := client.CreateVolume(volName, nil, defaultSizeGb, nil, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -374,7 +374,7 @@ var _ = Describe("GCE PD CSI Driver", func() { params := map[string]string{ common.ParameterKeyLabels: "key1=value1,key2=value2", } - volID, err := client.CreateVolume(volName, params, defaultSizeGb, nil) + volID, err := client.CreateVolume(volName, params, defaultSizeGb, nil, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -542,7 +542,7 @@ var _ = Describe("GCE PD CSI Driver", func() { Segments: map[string]string{common.TopologyKeyZone: z}, }, }, - }) + }, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -654,7 +654,7 @@ var _ = Describe("GCE PD CSI Driver", func() { volName := testNamePrefix + string(uuid.NewUUID()) volID, err := controllerClient.CreateVolume(volName, map[string]string{ common.ParameterKeyReplicationType: "regional-pd", - }, defaultRepdSizeGb, nil) + }, defaultRepdSizeGb, nil, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -870,7 +870,7 @@ var _ = Describe("GCE PD CSI Driver", func() { common.ParameterKeyPVCName: "test-pvc", common.ParameterKeyPVCNamespace: "test-pvc-namespace", common.ParameterKeyPVName: "test-pv-name", - }, defaultSizeGb, nil /* topReq */) + }, defaultSizeGb, nil /* topReq */, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -1011,6 +1011,116 @@ var _ = Describe("GCE PD CSI Driver", func() { Expect(gce.IsGCEError(err, "notFound")).To(BeTrue(), "Expected snapshot to not be found") }() }) + + It("Should successfully create zonal PD from a zonal PD VolumeContentSource", func() { + Expect(testContexts).ToNot(BeEmpty()) + testContext := getRandomTestContext() + + controllerInstance := testContext.Instance + controllerClient := testContext.Client + + p, z, _ := controllerInstance.GetIdentity() + + // Create Source Disk + _, srcVolID := createAndValidateUniqueZonalDisk(controllerClient, p, z) + + // Create Disk + volName := testNamePrefix + string(uuid.NewUUID()) + volID, err := controllerClient.CreateVolume(volName, map[string]string{ + common.ParameterKeyReplicationType: "none", + }, defaultSizeGb, + &csi.TopologyRequirement{ + Requisite: []*csi.Topology{ + { + Segments: map[string]string{common.TopologyKeyZone: z}, + }, + }, + }, + &csi.VolumeContentSource{ + Type: &csi.VolumeContentSource_Volume{ + Volume: &csi.VolumeContentSource_VolumeSource{ + VolumeId: srcVolID, + }, + }, + }) + + Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) + + // Validate Disk Created + cloudDisk, err := computeService.Disks.Get(p, z, volName).Do() + Expect(err).To(BeNil(), "Could not get disk from cloud directly") + Expect(cloudDisk.Type).To(ContainSubstring(standardDiskType)) + Expect(cloudDisk.Status).To(Equal(readyState)) + Expect(cloudDisk.SizeGb).To(Equal(defaultSizeGb)) + Expect(cloudDisk.Name).To(Equal(volName)) + defer func() { + // Delete Disk + controllerClient.DeleteVolume(volID) + Expect(err).To(BeNil(), "DeleteVolume failed") + + // Validate Disk Deleted + _, err = computeService.Disks.Get(p, z, volName).Do() + Expect(gce.IsGCEError(err, "notFound")).To(BeTrue(), "Expected disk to not be found") + }() + }) + + It("Should successfully create RePD from a zonal PD VolumeContentSource", func() { + Expect(testContexts).ToNot(BeEmpty()) + testContext := getRandomTestContext() + + controllerInstance := testContext.Instance + controllerClient := testContext.Client + + p, z, _ := controllerInstance.GetIdentity() + + region, err := common.GetRegionFromZones([]string{z}) + Expect(err).To(BeNil(), "Failed to get region from zones") + + // Create Source Disk + srcVolName := testNamePrefix + string(uuid.NewUUID()) + srcVolID, err := controllerClient.CreateVolume(srcVolName, map[string]string{ + common.ParameterKeyReplicationType: "none", + }, defaultRepdSizeGb, nil, nil) + // Create Disk + volName := testNamePrefix + string(uuid.NewUUID()) + volID, err := controllerClient.CreateVolume(volName, map[string]string{ + common.ParameterKeyReplicationType: "regional-pd", + }, defaultRepdSizeGb, nil, + &csi.VolumeContentSource{ + Type: &csi.VolumeContentSource_Volume{ + Volume: &csi.VolumeContentSource_VolumeSource{ + VolumeId: srcVolID, + }, + }, + }) + + Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) + + // Validate Disk Created + cloudDisk, err := computeService.RegionDisks.Get(p, region, volName).Do() + Expect(err).To(BeNil(), "Could not get disk from cloud directly") + Expect(cloudDisk.Type).To(ContainSubstring(standardDiskType)) + Expect(cloudDisk.Status).To(Equal(readyState)) + Expect(cloudDisk.SizeGb).To(Equal(defaultRepdSizeGb)) + Expect(cloudDisk.Name).To(Equal(volName)) + Expect(len(cloudDisk.ReplicaZones)).To(Equal(2)) + for _, replicaZone := range cloudDisk.ReplicaZones { + tokens := strings.Split(replicaZone, "/") + actualZone := tokens[len(tokens)-1] + gotRegion, err := common.GetRegionFromZones([]string{actualZone}) + Expect(err).To(BeNil(), "failed to get region from actual zone %v", actualZone) + Expect(gotRegion).To(Equal(region), "Got region from replica zone that did not match supplied region") + } + defer func() { + // Delete Disk + controllerClient.DeleteVolume(volID) + Expect(err).To(BeNil(), "DeleteVolume failed") + + // Validate Disk Deleted + _, err = computeService.RegionDisks.Get(p, region, volName).Do() + Expect(gce.IsGCEError(err, "notFound")).To(BeTrue(), "Expected disk to not be found") + }() + }) }) func equalWithinEpsilon(a, b, epsiolon int64) bool { @@ -1031,7 +1141,7 @@ func createAndValidateUniqueZonalDisk(client *remote.CsiClient, project, zone st Segments: map[string]string{common.TopologyKeyZone: zone}, }, }, - }) + }, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created @@ -1076,7 +1186,7 @@ func createAndValidateUniqueZonalMultiWriterDisk(client *remote.CsiClient, proje Mode: csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER, }, }, - }) + }, nil) Expect(err).To(BeNil(), "CreateVolume failed with error: %v", err) // Validate Disk Created diff --git a/test/remote/client-wrappers.go b/test/remote/client-wrappers.go index 152570ba6..8bfccee09 100644 --- a/test/remote/client-wrappers.go +++ b/test/remote/client-wrappers.go @@ -99,7 +99,7 @@ func (c *CsiClient) CloseConn() error { return c.conn.Close() } -func (c *CsiClient) CreateVolumeWithCaps(volName string, params map[string]string, sizeInGb int64, topReq *csipb.TopologyRequirement, caps []*csipb.VolumeCapability) (string, error) { +func (c *CsiClient) CreateVolumeWithCaps(volName string, params map[string]string, sizeInGb int64, topReq *csipb.TopologyRequirement, caps []*csipb.VolumeCapability, volContentSrc *csipb.VolumeContentSource) (string, error) { capRange := &csipb.CapacityRange{ RequiredBytes: common.GbToBytes(sizeInGb), } @@ -112,6 +112,9 @@ func (c *CsiClient) CreateVolumeWithCaps(volName string, params map[string]strin if topReq != nil { cvr.AccessibilityRequirements = topReq } + if volContentSrc != nil { + cvr.VolumeContentSource = volContentSrc + } cresp, err := c.ctrlClient.CreateVolume(context.Background(), cvr) if err != nil { return "", err @@ -119,8 +122,8 @@ func (c *CsiClient) CreateVolumeWithCaps(volName string, params map[string]strin return cresp.GetVolume().GetVolumeId(), nil } -func (c *CsiClient) CreateVolume(volName string, params map[string]string, sizeInGb int64, topReq *csipb.TopologyRequirement) (string, error) { - return c.CreateVolumeWithCaps(volName, params, sizeInGb, topReq, stdVolCaps) +func (c *CsiClient) CreateVolume(volName string, params map[string]string, sizeInGb int64, topReq *csipb.TopologyRequirement, volContentSrc *csipb.VolumeContentSource) (string, error) { + return c.CreateVolumeWithCaps(volName, params, sizeInGb, topReq, stdVolCaps, volContentSrc) } func (c *CsiClient) DeleteVolume(volId string) error {