Skip to content

Commit 1d669d1

Browse files
Add provisionedThroughput for hyperdisk
1 parent cc2fea0 commit 1d669d1

File tree

8 files changed

+179
-22
lines changed

8 files changed

+179
-22
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ See Github [Issues](https://github.com/kubernetes-sigs/gcp-compute-persistent-di
6565
| disk-encryption-kms-key | Fully qualified resource identifier for the key to use to encrypt new disks. | Empty string. | Encrypt disk using Customer Managed Encryption Key (CMEK). See [GKE Docs](https://cloud.google.com/kubernetes-engine/docs/how-to/using-cmek#create_a_cmek_protected_attached_disk) for details. |
6666
| labels | `key1=value1,key2=value2` | | Labels allow you to assign custom [GCE Disk labels](https://cloud.google.com/compute/docs/labeling-resources). |
6767
| provisioned-iops-on-create | string (int64 format). Values typically between 10,000 and 120,000 | | Indicates how many IOPS to provision for the disk. See the [Extreme persistent disk documentation](https://cloud.google.com/compute/docs/disks/extreme-persistent-disk) for details, including valid ranges for IOPS. |
68-
68+
| provisioned-throughput-on-create | string (int64 format). Values typically between 1 and 7,124 mb per second | | Indicates how much throughput to provision for the disk. See the [hyperdisk documentation](TBD) for details, including valid ranges for throughput. |
6969

7070
### Topology
7171

pkg/common/parameters.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ import (
2323

2424
const (
2525
// Parameters for StorageClass
26-
ParameterKeyType = "type"
27-
ParameterKeyReplicationType = "replication-type"
28-
ParameterKeyDiskEncryptionKmsKey = "disk-encryption-kms-key"
29-
ParameterKeyLabels = "labels"
30-
ParameterKeyProvisionedIOPSOnCreate = "provisioned-iops-on-create"
26+
ParameterKeyType = "type"
27+
ParameterKeyReplicationType = "replication-type"
28+
ParameterKeyDiskEncryptionKmsKey = "disk-encryption-kms-key"
29+
ParameterKeyLabels = "labels"
30+
ParameterKeyProvisionedIOPSOnCreate = "provisioned-iops-on-create"
31+
ParameterKeyProvisionedThroughputOnCreate = "provisioned-throughput-on-create"
3132

3233
// Parameters for VolumeSnapshotClass
3334
ParameterKeyStorageLocations = "storage-locations"
@@ -79,6 +80,9 @@ type DiskParameters struct {
7980
// Values: {int64}
8081
// Default: none
8182
ProvisionedIOPSOnCreate int64
83+
// Values: {int64}
84+
// Default: none
85+
ProvisionedThroughputOnCreate int64
8286
}
8387

8488
// SnapshotParameters contains normalized and defaulted parameters for snapshots
@@ -144,6 +148,12 @@ func ExtractAndDefaultParameters(parameters map[string]string, driverName string
144148
return p, fmt.Errorf("parameters contain invalid provisionedIOPSOnCreate parameter: %w", err)
145149
}
146150
p.ProvisionedIOPSOnCreate = paramProvisionedIOPSOnCreate
151+
case ParameterKeyProvisionedThroughputOnCreate:
152+
paramProvisionedThroughputOnCreate, err := ConvertMiBStringToInt64(v)
153+
if err != nil {
154+
return p, fmt.Errorf("parameters contain invalid provisionedThroughputOnCreate parameter: %w", err)
155+
}
156+
p.ProvisionedThroughputOnCreate = paramProvisionedThroughputOnCreate
147157
default:
148158
return p, fmt.Errorf("parameters contains invalid option %q", k)
149159
}

pkg/common/parameters_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ func TestExtractAndDefaultParameters(t *testing.T) {
9090
ProvisionedIOPSOnCreate: 10000,
9191
},
9292
},
93+
{
94+
name: "values from parameters, checking hyperdisk-throughput",
95+
parameters: map[string]string{ParameterKeyType: "hyperdisk-throughput", ParameterKeyReplicationType: "none", ParameterKeyDiskEncryptionKmsKey: "foo/key", ParameterKeyLabels: "key1=value1,key2=value2", ParameterKeyProvisionedThroughputOnCreate: "1000Mi"},
96+
labels: map[string]string{},
97+
expectParams: DiskParameters{
98+
DiskType: "hyperdisk-throughput",
99+
ReplicationType: "none",
100+
DiskEncryptionKMSKey: "foo/key",
101+
Tags: map[string]string{},
102+
Labels: map[string]string{
103+
"key1": "value1",
104+
"key2": "value2",
105+
},
106+
ProvisionedThroughputOnCreate: 1000,
107+
},
108+
},
93109
{
94110
name: "values from parameters, checking balanced pd",
95111
parameters: map[string]string{ParameterKeyType: "pd-balanced", ParameterKeyReplicationType: "regional-pd", ParameterKeyDiskEncryptionKmsKey: "foo/key"},

pkg/common/utils.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,14 @@ func ConvertStringToInt64(str string) (int64, error) {
279279
}
280280
return volumehelpers.RoundUpToB(quantity)
281281
}
282+
283+
// ConvertMiBStringToInt64 converts a GiB string to int64
284+
func ConvertMiBStringToInt64(str string) (int64, error) {
285+
// Verify regex before
286+
match, _ := regexp.MatchString("^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$", str)
287+
if !match {
288+
return 0, fmt.Errorf("invalid string %s", str)
289+
}
290+
quantity := resource.MustParse(str)
291+
return volumehelpers.RoundUpToMiB(quantity)
292+
}

pkg/common/utils_test.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,3 +757,93 @@ func TestConvertStringToInt64(t *testing.T) {
757757
})
758758
}
759759
}
760+
761+
func TestConvertMiBStringToInt64(t *testing.T) {
762+
tests := []struct {
763+
desc string
764+
inputStr string
765+
expInt64 int64
766+
expectError bool
767+
}{
768+
{
769+
"valid number string",
770+
"10000",
771+
1,
772+
false,
773+
},
774+
{
775+
"round Ki to MiB",
776+
"1000Ki",
777+
1,
778+
false,
779+
},
780+
{
781+
"round k to MiB",
782+
"1000k",
783+
1,
784+
false,
785+
},
786+
{
787+
"round Mi to MiB",
788+
"1000Mi",
789+
1000,
790+
false,
791+
},
792+
{
793+
"round M to MiB",
794+
"1000M",
795+
954,
796+
false,
797+
},
798+
{
799+
"round G to MiB",
800+
"1000G",
801+
953675,
802+
false,
803+
},
804+
{
805+
"round Gi to MiB",
806+
"10000Gi",
807+
10240000,
808+
false,
809+
},
810+
{
811+
"round decimal to MiB",
812+
"1.2Gi",
813+
1229,
814+
false,
815+
},
816+
{
817+
"round big value to MiB",
818+
"8191Pi",
819+
8795019280384,
820+
false,
821+
},
822+
{
823+
"invalid empty string",
824+
"",
825+
10000,
826+
true,
827+
},
828+
{
829+
"invalid string",
830+
"ew%65",
831+
10000,
832+
true,
833+
},
834+
}
835+
for _, tc := range tests {
836+
t.Run(tc.desc, func(t *testing.T) {
837+
actualInt64, err := ConvertMiBStringToInt64(tc.inputStr)
838+
if err != nil && !tc.expectError {
839+
t.Errorf("Got error %v converting string to int64 %s; expect no error", err, tc.inputStr)
840+
}
841+
if err == nil && tc.expectError {
842+
t.Errorf("Got no error converting string to int64 %s; expect an error", tc.inputStr)
843+
}
844+
if err == nil && actualInt64 != tc.expInt64 {
845+
t.Errorf("Got %d for converting string to int64; expect %d", actualInt64, tc.expInt64)
846+
}
847+
})
848+
}
849+
}

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,14 +196,15 @@ func (cloud *FakeCloudProvider) InsertDisk(ctx context.Context, project string,
196196
}
197197

198198
computeDisk := &computev1.Disk{
199-
Name: volKey.Name,
200-
SizeGb: common.BytesToGbRoundUp(capBytes),
201-
Description: "Disk created by GCE-PD CSI Driver",
202-
Type: cloud.GetDiskTypeURI(project, volKey, params.DiskType),
203-
SourceDiskId: volumeContentSourceVolumeID,
204-
Status: cloud.mockDiskStatus,
205-
Labels: params.Labels,
206-
ProvisionedIops: params.ProvisionedIOPSOnCreate,
199+
Name: volKey.Name,
200+
SizeGb: common.BytesToGbRoundUp(capBytes),
201+
Description: "Disk created by GCE-PD CSI Driver",
202+
Type: cloud.GetDiskTypeURI(project, volKey, params.DiskType),
203+
SourceDiskId: volumeContentSourceVolumeID,
204+
Status: cloud.mockDiskStatus,
205+
Labels: params.Labels,
206+
ProvisionedIops: params.ProvisionedIOPSOnCreate,
207+
ProvisionedThroughput: params.ProvisionedThroughputOnCreate,
207208
}
208209

209210
if snapshotID != "" {

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

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ func convertV1CustomerEncryptionKeyToBeta(v1Key *computev1.CustomerEncryptionKey
401401
}
402402
}
403403

404-
func convertV1DiskToBetaDisk(v1Disk *computev1.Disk) *computebeta.Disk {
404+
func convertV1DiskToBetaDisk(v1Disk *computev1.Disk, provisionedThroughputOnCreate int64) *computebeta.Disk {
405405
var dek *computebeta.CustomerEncryptionKey = nil
406406

407407
if v1Disk.DiskEncryptionKey != nil {
@@ -421,6 +421,9 @@ func convertV1DiskToBetaDisk(v1Disk *computev1.Disk) *computebeta.Disk {
421421
if v1Disk.ProvisionedIops > 0 {
422422
betaDisk.ProvisionedIops = v1Disk.ProvisionedIops
423423
}
424+
if provisionedThroughputOnCreate > 0 {
425+
betaDisk.ProvisionedThroughput = provisionedThroughputOnCreate
426+
}
424427

425428
return betaDisk
426429
}
@@ -448,11 +451,12 @@ func (cloud *CloudProvider) insertRegionalDisk(
448451
}
449452

450453
diskToCreate := &computev1.Disk{
451-
Name: volKey.Name,
452-
SizeGb: common.BytesToGbRoundUp(capBytes),
453-
Description: description,
454-
Type: cloud.GetDiskTypeURI(cloud.project, volKey, params.DiskType),
455-
Labels: params.Labels,
454+
Name: volKey.Name,
455+
SizeGb: common.BytesToGbRoundUp(capBytes),
456+
Description: description,
457+
Type: cloud.GetDiskTypeURI(cloud.project, volKey, params.DiskType),
458+
Labels: params.Labels,
459+
ProvisionedIops: params.ProvisionedIOPSOnCreate,
456460
}
457461
if snapshotID != "" {
458462
_, snapshotType, _, err := common.SnapshotIDToProjectKey(snapshotID)
@@ -483,7 +487,7 @@ func (cloud *CloudProvider) insertRegionalDisk(
483487

484488
if gceAPIVersion == GCEAPIVersionBeta {
485489
var insertOp *computebeta.Operation
486-
betaDiskToCreate := convertV1DiskToBetaDisk(diskToCreate)
490+
betaDiskToCreate := convertV1DiskToBetaDisk(diskToCreate, 0)
487491
betaDiskToCreate.MultiWriter = multiWriter
488492
insertOp, err = cloud.betaService.RegionDisks.Insert(project, volKey.Region, betaDiskToCreate).Context(ctx).Do()
489493
if insertOp != nil {
@@ -594,7 +598,7 @@ func (cloud *CloudProvider) insertZonalDisk(
594598

595599
if gceAPIVersion == GCEAPIVersionBeta {
596600
var insertOp *computebeta.Operation
597-
betaDiskToCreate := convertV1DiskToBetaDisk(diskToCreate)
601+
betaDiskToCreate := convertV1DiskToBetaDisk(diskToCreate, params.ProvisionedThroughputOnCreate)
598602
betaDiskToCreate.MultiWriter = multiWriter
599603
insertOp, err = cloud.betaService.Disks.Insert(project, volKey.Zone, betaDiskToCreate).Context(ctx).Do()
600604
if insertOp != nil {

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,31 @@ func TestCreateVolumeArguments(t *testing.T) {
818818
},
819819
expErrCode: codes.InvalidArgument,
820820
},
821+
{
822+
name: "success with provisionedThroughput parameter",
823+
req: &csi.CreateVolumeRequest{
824+
Name: name,
825+
CapacityRange: stdCapRange,
826+
VolumeCapabilities: stdVolCaps,
827+
Parameters: map[string]string{"labels": "key1=value1,key2=value2", "provisioned-throughput-on-create": "10000"},
828+
},
829+
expVol: &csi.Volume{
830+
CapacityBytes: common.GbToBytes(20),
831+
VolumeId: testVolumeID,
832+
VolumeContext: nil,
833+
AccessibleTopology: stdTopology,
834+
},
835+
},
836+
{
837+
name: "fail with malformed provisionedThroughput parameter",
838+
req: &csi.CreateVolumeRequest{
839+
Name: name,
840+
CapacityRange: stdCapRange,
841+
VolumeCapabilities: stdVolCaps,
842+
Parameters: map[string]string{"labels": "key1=value1,key2=value2", "provisioned-throughput-on-create": "dsfo3"},
843+
},
844+
expErrCode: codes.InvalidArgument,
845+
},
821846
}
822847

823848
// Run test cases

0 commit comments

Comments
 (0)