Skip to content

Commit f35cffe

Browse files
[3.1.1] AWS GP3 and Throughput support (#7)
* [3.1.1] AWS GP3 and Throughput support
1 parent a1e40c1 commit f35cffe

19 files changed

+337
-70
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## [3.1.1] - 2024-07-16
4+
### Fixed
5+
- `gp3` volume type support for AWS.
6+
- `volume_throughput` support for AWS GP3 storage volume type.
7+
38
## [3.1.0] - 2024-07-15
49
### Features
510
- `azure` provider is now supported.

docs/data-sources/service.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,11 @@ Read-Only:
7979

8080
Optional:
8181

82-
- `iops` (Number) The number of IOPS for the storage volume. This is only applicable for io1 volumes.
82+
- `iops` (Number) The number of IOPS for the storage volume. This is only applicable for io1 and gp3 volumes.
83+
- `throughput` (Number) The Throughput for the storage volume. This is only applicable for gp3 volumes.
8384

8485
Read-Only:
8586

8687
- `size` (Number) The size of the storage volume in GB.
87-
- `volume_type` (String) The type of the storage volume. Possible values are: gp2, io1 etc
88+
- `volume_type` (String) The type of the storage volume. Possible values are: gp3, io1 etc
8889

docs/resources/service.md

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,21 @@ Creates and manages a service in SkySQL
1414
```terraform
1515
# Create a service
1616
resource "skysql_service" "default" {
17-
project_id = data.skysql_projects.default.projects[0].id
18-
service_type = "transactional"
19-
topology = "es-single"
20-
cloud_provider = "aws"
21-
region = "us-east-1"
22-
name = "myservice"
23-
architecture = "amd64"
24-
nodes = 1
25-
size = "sky-2x8"
26-
storage = 100
27-
ssl_enabled = true
28-
version = data.skysql_versions.default.versions[0].name
29-
volume_type = "gp2"
17+
project_id = data.skysql_projects.default.projects[0].id
18+
service_type = "transactional"
19+
topology = "es-single"
20+
cloud_provider = "aws"
21+
region = "us-east-1"
22+
name = "myservice"
23+
architecture = "amd64"
24+
nodes = 1
25+
size = "sky-2x8"
26+
storage = 100
27+
ssl_enabled = true
28+
version = data.skysql_versions.default.versions[0].name
29+
volume_type = "gp3"
30+
volume_iops = 3000
31+
volume_throughput = 125
3032
# The service create is an asynchronous operation.
3133
# if you want to wait for the service to be created set wait_for_creation to true
3234
wait_for_creation = true
@@ -66,7 +68,8 @@ resource "skysql_service" "default" {
6668
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
6769
- `version` (String) The software version
6870
- `volume_iops` (Number) The volume IOPS. This is only applicable for AWS
69-
- `volume_type` (String) The volume type. Valid values are: gp2 and io1. This is only applicable for AWS
71+
- `volume_throughput` (Number) The volume Throughput. This is only applicable for AWS
72+
- `volume_type` (String) The volume type. Valid values are: gp3 and io1. This is only applicable for AWS
7073
- `wait_for_creation` (Boolean) Whether to wait for the service to be created. Valid values are: true or false
7174
- `wait_for_deletion` (Boolean) Whether to wait for the service to be deleted. Valid values are: true or false
7275
- `wait_for_update` (Boolean) Whether to wait for the service to be updated. Valid values are: true or false

examples/main.tf

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
terraform {
22
required_providers {
33
skysql = {
4-
source = "registry.terraform.io/skysqlinc/skysql"
4+
source = "registry.terraform.io/skysqlinc/skysql-beta"
55
}
66
}
77
}
@@ -15,18 +15,20 @@ data "skysql_versions" "default" {
1515

1616

1717
resource "skysql_service" "default" {
18-
service_type = "transactional"
19-
topology = "es-single"
20-
cloud_provider = "aws"
21-
region = "us-east-2"
22-
name = "myservice"
23-
architecture = "amd64"
24-
nodes = 1
25-
size = "sky-2x8"
26-
storage = 100
27-
ssl_enabled = true
28-
version = data.skysql_versions.default.versions[0].name
29-
volume_type = "gp2"
18+
service_type = "transactional"
19+
topology = "es-single"
20+
cloud_provider = "aws"
21+
region = "us-east-2"
22+
name = "myservice"
23+
architecture = "amd64"
24+
nodes = 1
25+
size = "sky-2x8"
26+
storage = 100
27+
ssl_enabled = true
28+
version = data.skysql_versions.default.versions[0].name
29+
volume_type = "gp3"
30+
volume_iops = 3000
31+
volume_throughput = 125
3032
allow_list = [
3133
{
3234
"ip" : "127.0.0.1/32",

examples/privateconnect/main.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ resource "skysql_service" "this" {
2222
endpoint_mechanism = "privateconnect"
2323
endpoint_allowed_accounts = [data.aws_caller_identity.this.account_id]
2424
wait_for_creation = true
25+
volume_type = "gp3"
26+
volume_iops = 3000
27+
volume_throughput = 125
2528
# The following line will be required when tearing down the skysql service
2629
# deletion_protection = false
2730
}

examples/resources/skysql_service.tf

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
# Create a service
22
resource "skysql_service" "default" {
3-
project_id = data.skysql_projects.default.projects[0].id
4-
service_type = "transactional"
5-
topology = "es-single"
6-
cloud_provider = "aws"
7-
region = "us-east-1"
8-
name = "myservice"
9-
architecture = "amd64"
10-
nodes = 1
11-
size = "sky-2x8"
12-
storage = 100
13-
ssl_enabled = true
14-
version = data.skysql_versions.default.versions[0].name
15-
volume_type = "gp2"
3+
project_id = data.skysql_projects.default.projects[0].id
4+
service_type = "transactional"
5+
topology = "es-single"
6+
cloud_provider = "aws"
7+
region = "us-east-1"
8+
name = "myservice"
9+
architecture = "amd64"
10+
nodes = 1
11+
size = "sky-2x8"
12+
storage = 100
13+
ssl_enabled = true
14+
version = data.skysql_versions.default.versions[0].name
15+
volume_type = "gp3"
16+
volume_iops = 3000
17+
volume_throughput = 125
1618
# The service create is an asynchronous operation.
1719
# if you want to wait for the service to be created set wait_for_creation to true
1820
wait_for_creation = true

internal/provider/service_data_source.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ type StorageVolumeDataSourceModel struct {
6868
Size types.Int64 `tfsdk:"size"`
6969
VolumeType types.String `tfsdk:"volume_type"`
7070
IOPS types.Int64 `tfsdk:"iops"`
71+
Throughput types.Int64 `tfsdk:"throughput"`
7172
}
7273

7374
func (d *ServiceDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
@@ -200,12 +201,17 @@ func (d *ServiceDataSource) Schema(ctx context.Context, req datasource.SchemaReq
200201
},
201202
"volume_type": schema.StringAttribute{
202203
Computed: true,
203-
Description: "The type of the storage volume. Possible values are: gp2, io1 etc",
204+
Description: "The type of the storage volume. Possible values are: gp3, io1 etc",
204205
},
205206
"iops": schema.Int64Attribute{
206207
Computed: true,
207208
Optional: true,
208-
Description: "The number of IOPS for the storage volume. This is only applicable for io1 volumes.",
209+
Description: "The number of IOPS for the storage volume. This is only applicable for io1 and gp3 volumes.",
210+
},
211+
"throughput": schema.Int64Attribute{
212+
Computed: true,
213+
Optional: true,
214+
Description: "The Throughput for the storage volume. This is only applicable for gp3 volumes.",
209215
},
210216
},
211217
},
@@ -318,6 +324,7 @@ func (d *ServiceDataSource) Read(ctx context.Context, req datasource.ReadRequest
318324
Size: types.Int64Value(int64(service.StorageVolume.Size)),
319325
VolumeType: types.StringValue(service.StorageVolume.VolumeType),
320326
IOPS: types.Int64Value(int64(service.StorageVolume.IOPS)),
327+
Throughput: types.Int64Value(int64(service.StorageVolume.Throughput)),
321328
}
322329

323330
data.OutboundIps = make([]types.String, len(service.OutboundIps))

internal/provider/service_resource.go

Lines changed: 59 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ type ServiceResourceModel struct {
7878
Topology types.String `tfsdk:"topology"`
7979
Storage types.Int64 `tfsdk:"storage"`
8080
VolumeIOPS types.Int64 `tfsdk:"volume_iops"`
81+
VolumeThroughput types.Int64 `tfsdk:"volume_throughput"`
8182
SSLEnabled types.Bool `tfsdk:"ssl_enabled"`
8283
NoSQLEnabled types.Bool `tfsdk:"nosql_enabled"`
8384
VolumeType types.String `tfsdk:"volume_type"`
@@ -221,6 +222,13 @@ var serviceResourceSchemaV0 = schema.Schema{
221222
int64planmodifier.UseStateForUnknown(),
222223
},
223224
},
225+
"volume_throughput": schema.Int64Attribute{
226+
Optional: true,
227+
Description: "The volume Throughput. This is only applicable for AWS",
228+
PlanModifiers: []planmodifier.Int64{
229+
int64planmodifier.UseStateForUnknown(),
230+
},
231+
},
224232
"ssl_enabled": schema.BoolAttribute{
225233
Optional: true,
226234
Computed: true,
@@ -241,7 +249,7 @@ var serviceResourceSchemaV0 = schema.Schema{
241249
"volume_type": schema.StringAttribute{
242250
Optional: true,
243251
Computed: true,
244-
Description: "The volume type. Valid values are: gp2 and io1. This is only applicable for AWS",
252+
Description: "The volume type. Valid values are: gp3 and io1. This is only applicable for AWS",
245253
PlanModifiers: []planmodifier.String{
246254
stringplanmodifier.UseStateForUnknown(),
247255
stringplanmodifier.RequiresReplaceIf(
@@ -452,6 +460,7 @@ func (r *ServiceResource) Create(ctx context.Context, req resource.CreateRequest
452460
Topology: state.Topology.ValueString(),
453461
Storage: uint(state.Storage.ValueInt64()),
454462
VolumeIOPS: uint(state.VolumeIOPS.ValueInt64()),
463+
VolumeThroughput: uint(state.VolumeThroughput.ValueInt64()),
455464
SSLEnabled: state.SSLEnabled.ValueBool(),
456465
NoSQLEnabled: state.NoSQLEnabled.ValueBool(),
457466
VolumeType: state.VolumeType.ValueString(),
@@ -523,6 +532,11 @@ func (r *ServiceResource) Create(ctx context.Context, req resource.CreateRequest
523532
} else {
524533
state.VolumeIOPS = types.Int64Null()
525534
}
535+
if service.StorageVolume.Throughput > 0 {
536+
state.VolumeThroughput = types.Int64Value(int64(service.StorageVolume.Throughput))
537+
} else {
538+
state.VolumeThroughput = types.Int64Null()
539+
}
526540
if service.StorageVolume.VolumeType != "" {
527541
state.VolumeType = types.StringValue(service.StorageVolume.VolumeType)
528542
} else {
@@ -679,6 +693,11 @@ func (r *ServiceResource) readServiceState(ctx context.Context, data *ServiceRes
679693
} else {
680694
data.VolumeIOPS = types.Int64Null()
681695
}
696+
if !data.VolumeThroughput.IsNull() && service.StorageVolume.Throughput > 0 {
697+
data.VolumeThroughput = types.Int64Value(int64(service.StorageVolume.Throughput))
698+
} else {
699+
data.VolumeThroughput = types.Int64Null()
700+
}
682701
data.VolumeType = types.StringValue(service.StorageVolume.VolumeType)
683702
if !data.ReplicationEnabled.IsNull() {
684703
data.ReplicationEnabled = types.BoolValue(service.ReplicationEnabled)
@@ -805,16 +824,18 @@ func (r *ServiceResource) updateAllowListState(plan *ServiceResourceModel, state
805824
}
806825

807826
func (r *ServiceResource) updateServiceStorage(ctx context.Context, plan *ServiceResourceModel, state *ServiceResourceModel, resp *resource.UpdateResponse) {
808-
if plan.Storage.ValueInt64() != state.Storage.ValueInt64() || plan.VolumeIOPS.ValueInt64() != state.VolumeIOPS.ValueInt64() {
827+
if plan.Storage.ValueInt64() != state.Storage.ValueInt64() || plan.VolumeIOPS.ValueInt64() != state.VolumeIOPS.ValueInt64() || plan.VolumeThroughput.ValueInt64() != state.VolumeThroughput.ValueInt64() {
809828
tflog.Info(ctx, "Updating storage size for the service", map[string]interface{}{
810-
"id": state.ID.ValueString(),
811-
"from": state.Storage.ValueInt64(),
812-
"to": plan.Storage.ValueInt64(),
813-
"iops_from": state.VolumeIOPS.ValueInt64(),
814-
"iops_to": plan.VolumeIOPS.ValueInt64(),
829+
"id": state.ID.ValueString(),
830+
"from": state.Storage.ValueInt64(),
831+
"to": plan.Storage.ValueInt64(),
832+
"iops_from": state.VolumeIOPS.ValueInt64(),
833+
"iops_to": plan.VolumeIOPS.ValueInt64(),
834+
"throughput_from": state.VolumeThroughput.ValueInt64(),
835+
"throughput_to": plan.VolumeThroughput.ValueInt64(),
815836
})
816837

817-
err := r.client.ModifyServiceStorage(ctx, state.ID.ValueString(), plan.Storage.ValueInt64(), plan.VolumeIOPS.ValueInt64())
838+
err := r.client.ModifyServiceStorage(ctx, state.ID.ValueString(), plan.Storage.ValueInt64(), plan.VolumeIOPS.ValueInt64(), plan.VolumeThroughput.ValueInt64())
818839
if err != nil {
819840
resp.Diagnostics.AddError("Error updating a storage for the service",
820841
fmt.Sprintf("Unable to update a storage size for the service, got error: %s", err))
@@ -1148,19 +1169,42 @@ func (r *ServiceResource) ModifyPlan(ctx context.Context, req resource.ModifyPla
11481169
}
11491170

11501171
if plan.Provider.ValueString() == "aws" {
1151-
if !plan.VolumeIOPS.IsNull() && plan.VolumeType.IsNull() {
1172+
1173+
if plan.VolumeType.IsNull() {
11521174
resp.Diagnostics.AddAttributeError(path.Root("volume_type"),
1153-
"volume_type is require",
1154-
"volume_type is required when volume_iops is set. "+
1155-
"Use: io1 for volume_type if volume_iops is set")
1175+
"volume_type is required",
1176+
"volume_type is required for AWS. Use: io1 or gp3 for volume_type.")
11561177
return
11571178
}
1158-
if !plan.VolumeIOPS.IsNull() && plan.VolumeType.ValueString() != "io1" {
1179+
1180+
if plan.VolumeType.ValueString() != "io1" && plan.VolumeType.ValueString() != "gp3" {
11591181
resp.Diagnostics.AddAttributeError(path.Root("volume_type"),
1160-
"volume_type must be io1 when you want to set IOPS",
1161-
"Use: io1 for volume_type if volume_iops is set")
1182+
"volume_type is not supported",
1183+
"volume_type provided is not supported. Use: io1 or gp3 for volume_type.")
11621184
return
11631185
}
1186+
1187+
if plan.VolumeIOPS.IsNull() {
1188+
resp.Diagnostics.AddAttributeError(path.Root("volume_iops"),
1189+
"volume_iops are required",
1190+
"volume_iops are required for AWS")
1191+
return
1192+
}
1193+
1194+
if plan.VolumeType.ValueString() == "io1" && !plan.VolumeThroughput.IsNull() {
1195+
resp.Diagnostics.AddAttributeError(path.Root("volume_throughput"),
1196+
"volume_throughput is not supported for io1",
1197+
"volume_throughput is supported only for gp3 volume_type for AWS")
1198+
return
1199+
}
1200+
1201+
if plan.VolumeType.ValueString() == "gp3" && plan.VolumeThroughput.IsNull() {
1202+
resp.Diagnostics.AddAttributeError(path.Root("volume_throughput"),
1203+
"volume_throughput is required",
1204+
"volume_throughput is required for gp3 volume_type for AWS")
1205+
return
1206+
}
1207+
11641208
} else if plan.Provider.ValueString() == "gcp" {
11651209
if !(plan.VolumeType.ValueString() == "" || plan.VolumeType.IsNull() || plan.VolumeType.ValueString() == "pd-ssd") {
11661210
resp.Diagnostics.AddAttributeError(

internal/provider/service_resource_deletion_protection_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,12 @@ func TestServiceResourceDeletionProtection(t *testing.T) {
8383
Size int `json:"size"`
8484
VolumeType string `json:"volume_type"`
8585
IOPS int `json:"iops"`
86+
Throughput int `json:"throughput"`
8687
}{
8788
Size: int(payload.Storage),
8889
VolumeType: payload.VolumeType,
8990
IOPS: int(payload.VolumeIOPS),
91+
Throughput: int(payload.VolumeThroughput),
9092
},
9193
OutboundIps: nil,
9294
IsActive: true,

internal/provider/service_resource_privatlink_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,12 @@ func TestServiceResourcePrivateLink(t *testing.T) {
8282
Size int `json:"size"`
8383
VolumeType string `json:"volume_type"`
8484
IOPS int `json:"iops"`
85+
Throughput int `json:"throughput"`
8586
}{
8687
Size: int(payload.Storage),
8788
VolumeType: payload.VolumeType,
8889
IOPS: int(payload.VolumeIOPS),
90+
Throughput: int(payload.VolumeThroughput),
8991
},
9092
OutboundIps: nil,
9193
IsActive: true,
@@ -393,10 +395,12 @@ func TestServiceResourcePrivateConnectWhenAllowedAccountsEmpty(t *testing.T) {
393395
Size int `json:"size"`
394396
VolumeType string `json:"volume_type"`
395397
IOPS int `json:"iops"`
398+
Throughput int `json:"throughput"`
396399
}{
397400
Size: int(payload.Storage),
398401
VolumeType: payload.VolumeType,
399402
IOPS: int(payload.VolumeIOPS),
403+
Throughput: int(payload.VolumeThroughput),
400404
},
401405
OutboundIps: nil,
402406
IsActive: true,

0 commit comments

Comments
 (0)