Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.1.1] AWS GP3 and Throughput support #11

Merged
merged 7 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## [3.1.1] - 2024-07-16
### Fixed
- `gp3` volume type support for AWS.
- `volume_throughput` support for AWS GP3 storage volume type.

## [3.1.0] - 2024-07-15
### Features
- `azure` provider is now supported.
Expand Down
5 changes: 3 additions & 2 deletions docs/data-sources/skysql_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ Read-Only:

Optional:

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

Read-Only:

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

31 changes: 17 additions & 14 deletions docs/resources/skysql_service.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,21 @@ Creates and manages a service in SkySQL
```terraform
# Create a service
resource "skysql_service" "default" {
project_id = data.skysql_projects.default.projects[0].id
service_type = "transactional"
topology = "es-single"
cloud_provider = "aws"
region = "us-east-1"
name = "myservice"
architecture = "amd64"
nodes = 1
size = "sky-2x8"
storage = 100
ssl_enabled = true
version = data.skysql_versions.default.versions[0].name
volume_type = "gp2"
project_id = data.skysql_projects.default.projects[0].id
service_type = "transactional"
topology = "es-single"
cloud_provider = "aws"
region = "us-east-1"
name = "myservice"
architecture = "amd64"
nodes = 1
size = "sky-2x8"
storage = 100
ssl_enabled = true
version = data.skysql_versions.default.versions[0].name
volume_type = "gp3"
volume_iops = 3000
volume_throughput = 125
# The service create is an asynchronous operation.
# if you want to wait for the service to be created set wait_for_creation to true
wait_for_creation = true
Expand Down Expand Up @@ -66,7 +68,8 @@ resource "skysql_service" "default" {
- `timeouts` (Block, Optional) (see [below for nested schema](#nestedblock--timeouts))
- `version` (String) The software version
- `volume_iops` (Number) The volume IOPS. This is only applicable for AWS
- `volume_type` (String) The volume type. Valid values are: gp2 and io1. This is only applicable for AWS
- `volume_throughput` (Number) The volume Throughput. This is only applicable for AWS
- `volume_type` (String) The volume type. Valid values are: gp3 and io1. This is only applicable for AWS
- `wait_for_creation` (Boolean) Whether to wait for the service to be created. Valid values are: true or false
- `wait_for_deletion` (Boolean) Whether to wait for the service to be deleted. Valid values are: true or false
- `wait_for_update` (Boolean) Whether to wait for the service to be updated. Valid values are: true or false
Expand Down
26 changes: 14 additions & 12 deletions examples/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,20 @@ data "skysql_versions" "default" {


resource "skysql_service" "default" {
service_type = "transactional"
topology = "es-single"
cloud_provider = "aws"
region = "us-east-2"
name = "myservice"
architecture = "amd64"
nodes = 1
size = "sky-2x8"
storage = 100
ssl_enabled = true
version = data.skysql_versions.default.versions[0].name
volume_type = "gp2"
service_type = "transactional"
topology = "es-single"
cloud_provider = "aws"
region = "us-east-2"
name = "myservice"
architecture = "amd64"
nodes = 1
size = "sky-2x8"
storage = 100
ssl_enabled = true
version = data.skysql_versions.default.versions[0].name
volume_type = "gp3"
volume_iops = 3000
volume_throughput = 125
allow_list = [
{
"ip" : "127.0.0.1/32",
Expand Down
3 changes: 3 additions & 0 deletions examples/privateconnect/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ resource "skysql_service" "this" {
endpoint_mechanism = "privateconnect"
endpoint_allowed_accounts = [data.aws_caller_identity.this.account_id]
wait_for_creation = true
volume_type = "gp3"
volume_iops = 3000
volume_throughput = 125
# The following line will be required when tearing down the skysql service
# deletion_protection = false
}
Expand Down
28 changes: 15 additions & 13 deletions examples/resources/skysql_service.tf
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
# Create a service
resource "skysql_service" "default" {
project_id = data.skysql_projects.default.projects[0].id
service_type = "transactional"
topology = "es-single"
cloud_provider = "aws"
region = "us-east-1"
name = "myservice"
architecture = "amd64"
nodes = 1
size = "sky-2x8"
storage = 100
ssl_enabled = true
version = data.skysql_versions.default.versions[0].name
volume_type = "gp2"
project_id = data.skysql_projects.default.projects[0].id
service_type = "transactional"
topology = "es-single"
cloud_provider = "aws"
region = "us-east-1"
name = "myservice"
architecture = "amd64"
nodes = 1
size = "sky-2x8"
storage = 100
ssl_enabled = true
version = data.skysql_versions.default.versions[0].name
volume_type = "gp3"
volume_iops = 3000
volume_throughput = 125
# The service create is an asynchronous operation.
# if you want to wait for the service to be created set wait_for_creation to true
wait_for_creation = true
Expand Down
11 changes: 9 additions & 2 deletions internal/provider/service_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ type StorageVolumeDataSourceModel struct {
Size types.Int64 `tfsdk:"size"`
VolumeType types.String `tfsdk:"volume_type"`
IOPS types.Int64 `tfsdk:"iops"`
Throughput types.Int64 `tfsdk:"throughput"`
}

func (d *ServiceDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
Expand Down Expand Up @@ -200,12 +201,17 @@ func (d *ServiceDataSource) Schema(ctx context.Context, req datasource.SchemaReq
},
"volume_type": schema.StringAttribute{
Computed: true,
Description: "The type of the storage volume. Possible values are: gp2, io1 etc",
Description: "The type of the storage volume. Possible values are: gp3, io1 etc",
},
"iops": schema.Int64Attribute{
Computed: true,
Optional: true,
Description: "The number of IOPS for the storage volume. This is only applicable for io1 volumes.",
Description: "The number of IOPS for the storage volume. This is only applicable for io1 and gp3 volumes.",
},
"throughput": schema.Int64Attribute{
Computed: true,
Optional: true,
Description: "The Throughput for the storage volume. This is only applicable for gp3 volumes.",
},
},
},
Expand Down Expand Up @@ -318,6 +324,7 @@ func (d *ServiceDataSource) Read(ctx context.Context, req datasource.ReadRequest
Size: types.Int64Value(int64(service.StorageVolume.Size)),
VolumeType: types.StringValue(service.StorageVolume.VolumeType),
IOPS: types.Int64Value(int64(service.StorageVolume.IOPS)),
Throughput: types.Int64Value(int64(service.StorageVolume.Throughput)),
}

data.OutboundIps = make([]types.String, len(service.OutboundIps))
Expand Down
74 changes: 59 additions & 15 deletions internal/provider/service_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type ServiceResourceModel struct {
Topology types.String `tfsdk:"topology"`
Storage types.Int64 `tfsdk:"storage"`
VolumeIOPS types.Int64 `tfsdk:"volume_iops"`
VolumeThroughput types.Int64 `tfsdk:"volume_throughput"`
SSLEnabled types.Bool `tfsdk:"ssl_enabled"`
NoSQLEnabled types.Bool `tfsdk:"nosql_enabled"`
VolumeType types.String `tfsdk:"volume_type"`
Expand Down Expand Up @@ -221,6 +222,13 @@ var serviceResourceSchemaV0 = schema.Schema{
int64planmodifier.UseStateForUnknown(),
},
},
"volume_throughput": schema.Int64Attribute{
Optional: true,
Description: "The volume Throughput. This is only applicable for AWS",
PlanModifiers: []planmodifier.Int64{
int64planmodifier.UseStateForUnknown(),
},
},
"ssl_enabled": schema.BoolAttribute{
Optional: true,
Computed: true,
Expand All @@ -241,7 +249,7 @@ var serviceResourceSchemaV0 = schema.Schema{
"volume_type": schema.StringAttribute{
Optional: true,
Computed: true,
Description: "The volume type. Valid values are: gp2 and io1. This is only applicable for AWS",
Description: "The volume type. Valid values are: gp3 and io1. This is only applicable for AWS",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
stringplanmodifier.RequiresReplaceIf(
Expand Down Expand Up @@ -452,6 +460,7 @@ func (r *ServiceResource) Create(ctx context.Context, req resource.CreateRequest
Topology: state.Topology.ValueString(),
Storage: uint(state.Storage.ValueInt64()),
VolumeIOPS: uint(state.VolumeIOPS.ValueInt64()),
VolumeThroughput: uint(state.VolumeThroughput.ValueInt64()),
SSLEnabled: state.SSLEnabled.ValueBool(),
NoSQLEnabled: state.NoSQLEnabled.ValueBool(),
VolumeType: state.VolumeType.ValueString(),
Expand Down Expand Up @@ -523,6 +532,11 @@ func (r *ServiceResource) Create(ctx context.Context, req resource.CreateRequest
} else {
state.VolumeIOPS = types.Int64Null()
}
if service.StorageVolume.Throughput > 0 {
state.VolumeThroughput = types.Int64Value(int64(service.StorageVolume.Throughput))
} else {
state.VolumeThroughput = types.Int64Null()
}
if service.StorageVolume.VolumeType != "" {
state.VolumeType = types.StringValue(service.StorageVolume.VolumeType)
} else {
Expand Down Expand Up @@ -679,6 +693,11 @@ func (r *ServiceResource) readServiceState(ctx context.Context, data *ServiceRes
} else {
data.VolumeIOPS = types.Int64Null()
}
if !data.VolumeThroughput.IsNull() && service.StorageVolume.Throughput > 0 {
data.VolumeThroughput = types.Int64Value(int64(service.StorageVolume.Throughput))
} else {
data.VolumeThroughput = types.Int64Null()
}
data.VolumeType = types.StringValue(service.StorageVolume.VolumeType)
if !data.ReplicationEnabled.IsNull() {
data.ReplicationEnabled = types.BoolValue(service.ReplicationEnabled)
Expand Down Expand Up @@ -805,16 +824,18 @@ func (r *ServiceResource) updateAllowListState(plan *ServiceResourceModel, state
}

func (r *ServiceResource) updateServiceStorage(ctx context.Context, plan *ServiceResourceModel, state *ServiceResourceModel, resp *resource.UpdateResponse) {
if plan.Storage.ValueInt64() != state.Storage.ValueInt64() || plan.VolumeIOPS.ValueInt64() != state.VolumeIOPS.ValueInt64() {
if plan.Storage.ValueInt64() != state.Storage.ValueInt64() || plan.VolumeIOPS.ValueInt64() != state.VolumeIOPS.ValueInt64() || plan.VolumeThroughput.ValueInt64() != state.VolumeThroughput.ValueInt64() {
tflog.Info(ctx, "Updating storage size for the service", map[string]interface{}{
"id": state.ID.ValueString(),
"from": state.Storage.ValueInt64(),
"to": plan.Storage.ValueInt64(),
"iops_from": state.VolumeIOPS.ValueInt64(),
"iops_to": plan.VolumeIOPS.ValueInt64(),
"id": state.ID.ValueString(),
"from": state.Storage.ValueInt64(),
"to": plan.Storage.ValueInt64(),
"iops_from": state.VolumeIOPS.ValueInt64(),
"iops_to": plan.VolumeIOPS.ValueInt64(),
"throughput_from": state.VolumeThroughput.ValueInt64(),
"throughput_to": plan.VolumeThroughput.ValueInt64(),
vasiliyskysql marked this conversation as resolved.
Show resolved Hide resolved
})

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

if plan.Provider.ValueString() == "aws" {
if !plan.VolumeIOPS.IsNull() && plan.VolumeType.IsNull() {

if plan.VolumeType.IsNull() {
resp.Diagnostics.AddAttributeError(path.Root("volume_type"),
"volume_type is require",
"volume_type is required when volume_iops is set. "+
"Use: io1 for volume_type if volume_iops is set")
"volume_type is required",
"volume_type is required for AWS. Use: io1 or gp3 for volume_type.")
return
}
if !plan.VolumeIOPS.IsNull() && plan.VolumeType.ValueString() != "io1" {

if plan.VolumeType.ValueString() != "io1" && plan.VolumeType.ValueString() != "gp3" {
resp.Diagnostics.AddAttributeError(path.Root("volume_type"),
"volume_type must be io1 when you want to set IOPS",
"Use: io1 for volume_type if volume_iops is set")
"volume_type is not supported",
"volume_type provided is not supported. Use: io1 or gp3 for volume_type.")
return
}

if plan.VolumeIOPS.IsNull() {
resp.Diagnostics.AddAttributeError(path.Root("volume_iops"),
"volume_iops are required",
"volume_iops are required for AWS")
return
}

if plan.VolumeType.ValueString() == "io1" && !plan.VolumeThroughput.IsNull() {
resp.Diagnostics.AddAttributeError(path.Root("volume_throughput"),
"volume_throughput is not supported for io1",
"volume_throughput is supported only for gp3 volume_type for AWS")
return
}

if plan.VolumeType.ValueString() == "gp3" && plan.VolumeThroughput.IsNull() {
resp.Diagnostics.AddAttributeError(path.Root("volume_throughput"),
"volume_throughput is required",
"volume_throughput is required for gp3 volume_type for AWS")
return
}

} else if plan.Provider.ValueString() == "gcp" {
if !(plan.VolumeType.ValueString() == "" || plan.VolumeType.IsNull() || plan.VolumeType.ValueString() == "pd-ssd") {
resp.Diagnostics.AddAttributeError(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ func TestServiceResourceDeletionProtection(t *testing.T) {
Size int `json:"size"`
VolumeType string `json:"volume_type"`
IOPS int `json:"iops"`
Throughput int `json:"throughput"`
}{
Size: int(payload.Storage),
VolumeType: payload.VolumeType,
IOPS: int(payload.VolumeIOPS),
Throughput: int(payload.VolumeThroughput),
},
OutboundIps: nil,
IsActive: true,
Expand Down
4 changes: 4 additions & 0 deletions internal/provider/service_resource_privatlink_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,12 @@ func TestServiceResourcePrivateLink(t *testing.T) {
Size int `json:"size"`
VolumeType string `json:"volume_type"`
IOPS int `json:"iops"`
Throughput int `json:"throughput"`
}{
Size: int(payload.Storage),
VolumeType: payload.VolumeType,
IOPS: int(payload.VolumeIOPS),
Throughput: int(payload.VolumeThroughput),
},
OutboundIps: nil,
IsActive: true,
Expand Down Expand Up @@ -393,10 +395,12 @@ func TestServiceResourcePrivateConnectWhenAllowedAccountsEmpty(t *testing.T) {
Size int `json:"size"`
VolumeType string `json:"volume_type"`
IOPS int `json:"iops"`
Throughput int `json:"throughput"`
}{
Size: int(payload.Storage),
VolumeType: payload.VolumeType,
IOPS: int(payload.VolumeIOPS),
Throughput: int(payload.VolumeThroughput),
},
OutboundIps: nil,
IsActive: true,
Expand Down
Loading
Loading