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

Add performance config field to Filestore instance #20218

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
3 changes: 3 additions & 0 deletions .changelog/12245.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
filestore: added `performance_config` field to `google_filestore_instance`
```
217 changes: 217 additions & 0 deletions google/services/filestore/resource_filestore_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,57 @@ Please refer to the field 'effective_labels' for all of the labels present on th
Description: `The name of the location of the instance. This can be a region for ENTERPRISE tier instances.`,
ExactlyOneOf: []string{},
},
"performance_config": {
Type: schema.TypeList,
Optional: true,
Description: `Performance configuration for the instance. If not provided,
the default performance settings will be used.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"fixed_iops": {
Type: schema.TypeList,
Optional: true,
Description: `The instance will have a fixed provisioned IOPS value,
which will remain constant regardless of instance
capacity.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"max_iops": {
Type: schema.TypeInt,
Optional: true,
Description: `The number of IOPS to provision for the instance.
max_iops must be in multiple of 1000.`,
},
},
},
ConflictsWith: []string{},
},
"iops_per_tb": {
Type: schema.TypeList,
Optional: true,
Description: `The instance provisioned IOPS will change dynamically
based on the capacity of the instance.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"max_iops_per_tb": {
Type: schema.TypeInt,
Optional: true,
Description: `The instance max IOPS will be calculated by multiplying
the capacity of the instance (TB) by max_iops_per_tb,
and rounding to the nearest 1000. The instance max IOPS
will be changed dynamically based on the instance
capacity.`,
},
},
},
ConflictsWith: []string{},
},
},
},
},
"protocol": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -367,6 +418,12 @@ func resourceFilestoreInstanceCreate(d *schema.ResourceData, meta interface{}) e
} else if v, ok := d.GetOkExists("deletion_protection_reason"); !tpgresource.IsEmptyValue(reflect.ValueOf(deletionProtectionReasonProp)) && (ok || !reflect.DeepEqual(v, deletionProtectionReasonProp)) {
obj["deletionProtectionReason"] = deletionProtectionReasonProp
}
performanceConfigProp, err := expandFilestoreInstancePerformanceConfig(d.Get("performance_config"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("performance_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(performanceConfigProp)) && (ok || !reflect.DeepEqual(v, performanceConfigProp)) {
obj["performanceConfig"] = performanceConfigProp
}
labelsProp, err := expandFilestoreInstanceEffectiveLabels(d.Get("effective_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -534,6 +591,9 @@ func resourceFilestoreInstanceRead(d *schema.ResourceData, meta interface{}) err
if err := d.Set("deletion_protection_reason", flattenFilestoreInstanceDeletionProtectionReason(res["deletionProtectionReason"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("performance_config", flattenFilestoreInstancePerformanceConfig(res["performanceConfig"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("terraform_labels", flattenFilestoreInstanceTerraformLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
Expand Down Expand Up @@ -584,6 +644,12 @@ func resourceFilestoreInstanceUpdate(d *schema.ResourceData, meta interface{}) e
} else if v, ok := d.GetOkExists("deletion_protection_reason"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, deletionProtectionReasonProp)) {
obj["deletionProtectionReason"] = deletionProtectionReasonProp
}
performanceConfigProp, err := expandFilestoreInstancePerformanceConfig(d.Get("performance_config"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("performance_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, performanceConfigProp)) {
obj["performanceConfig"] = performanceConfigProp
}
labelsProp, err := expandFilestoreInstanceEffectiveLabels(d.Get("effective_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -616,6 +682,10 @@ func resourceFilestoreInstanceUpdate(d *schema.ResourceData, meta interface{}) e
updateMask = append(updateMask, "deletionProtectionReason")
}

if d.HasChange("performance_config") {
updateMask = append(updateMask, "performanceConfig")
}

if d.HasChange("effective_labels") {
updateMask = append(updateMask, "labels")
}
Expand Down Expand Up @@ -951,6 +1021,81 @@ func flattenFilestoreInstanceDeletionProtectionReason(v interface{}, d *schema.R
return v
}

func flattenFilestoreInstancePerformanceConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["iops_per_tb"] =
flattenFilestoreInstancePerformanceConfigIopsPerTb(original["iopsPerTb"], d, config)
transformed["fixed_iops"] =
flattenFilestoreInstancePerformanceConfigFixedIops(original["fixedIops"], d, config)
return []interface{}{transformed}
}
func flattenFilestoreInstancePerformanceConfigIopsPerTb(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["max_iops_per_tb"] =
flattenFilestoreInstancePerformanceConfigIopsPerTbMaxIopsPerTb(original["maxIopsPerTb"], d, config)
return []interface{}{transformed}
}
func flattenFilestoreInstancePerformanceConfigIopsPerTbMaxIopsPerTb(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
return intVal
}
}

// number values are represented as float64
if floatVal, ok := v.(float64); ok {
intVal := int(floatVal)
return intVal
}

return v // let terraform core handle it otherwise
}

func flattenFilestoreInstancePerformanceConfigFixedIops(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["max_iops"] =
flattenFilestoreInstancePerformanceConfigFixedIopsMaxIops(original["maxIops"], d, config)
return []interface{}{transformed}
}
func flattenFilestoreInstancePerformanceConfigFixedIopsMaxIops(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
return intVal
}
}

// number values are represented as float64
if floatVal, ok := v.(float64); ok {
intVal := int(floatVal)
return intVal
}

return v // let terraform core handle it otherwise
}

func flattenFilestoreInstanceTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return v
Expand Down Expand Up @@ -1189,6 +1334,78 @@ func expandFilestoreInstanceDeletionProtectionReason(v interface{}, d tpgresourc
return v, nil
}

func expandFilestoreInstancePerformanceConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedIopsPerTb, err := expandFilestoreInstancePerformanceConfigIopsPerTb(original["iops_per_tb"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedIopsPerTb); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["iopsPerTb"] = transformedIopsPerTb
}

transformedFixedIops, err := expandFilestoreInstancePerformanceConfigFixedIops(original["fixed_iops"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedFixedIops); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["fixedIops"] = transformedFixedIops
}

return transformed, nil
}

func expandFilestoreInstancePerformanceConfigIopsPerTb(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedMaxIopsPerTb, err := expandFilestoreInstancePerformanceConfigIopsPerTbMaxIopsPerTb(original["max_iops_per_tb"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedMaxIopsPerTb); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["maxIopsPerTb"] = transformedMaxIopsPerTb
}

return transformed, nil
}

func expandFilestoreInstancePerformanceConfigIopsPerTbMaxIopsPerTb(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandFilestoreInstancePerformanceConfigFixedIops(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedMaxIops, err := expandFilestoreInstancePerformanceConfigFixedIopsMaxIops(original["max_iops"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedMaxIops); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["maxIops"] = transformedMaxIops
}

return transformed, nil
}

func expandFilestoreInstancePerformanceConfigFixedIopsMaxIops(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandFilestoreInstanceEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
Expand Down
124 changes: 124 additions & 0 deletions google/services/filestore/resource_filestore_instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,127 @@ resource "google_filestore_instance" "instance" {
}
`, name, location, tier, deletionProtection, deletionProtectionReason)
}

func TestAccFilestoreInstance_performanceConfig(t *testing.T) {
t.Parallel()

name := fmt.Sprintf("tf-test-%d", acctest.RandInt(t))
location := "us-central1"
tier := "REGIONAL"

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckFilestoreInstanceDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccFilestoreInstance_fixedIopsPerformanceConfig(name, location, tier),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("google_filestore_instance.instance", "performance_config.0.fixed_iops.0.max_iops", "17000"),
),
},
{
ResourceName: "google_filestore_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone"},
},
{
Config: testAccFilestoreInstance_iopsPerTbPerformanceConfig(name, location, tier),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("google_filestore_instance.instance", "performance_config.0.iops_per_tb.0.max_iops_per_tb", "17000"),
),
},
{
ResourceName: "google_filestore_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone"},
},
{
Config: testAccFilestoreInstance_defaultConfig(name, location, tier),
},
{
ResourceName: "google_filestore_instance.instance",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"zone"},
},
},
})
}

func testAccFilestoreInstance_fixedIopsPerformanceConfig(name, location, tier string) string {
return fmt.Sprintf(`
resource "google_filestore_instance" "instance" {
name = "%s"
location = "%s"
tier = "%s"
description = "An instance created during testing."

file_shares {
capacity_gb = 1024
name = "share"
}

networks {
network = "default"
modes = ["MODE_IPV4"]
}

performance_config {
fixed_iops {
max_iops = 17000
}
}
}
`, name, location, tier)
}

func testAccFilestoreInstance_iopsPerTbPerformanceConfig(name, location, tier string) string {
return fmt.Sprintf(`
resource "google_filestore_instance" "instance" {
name = "%s"
zone = "%s"
tier = "%s"
description = "An instance created during testing."

file_shares {
capacity_gb = 1024
name = "share"
}

networks {
network = "default"
modes = ["MODE_IPV4"]
}

performance_config {
iops_per_tb {
max_iops_per_tb = 17000
}
}
}
`, name, location, tier)
}

func testAccFilestoreInstance_defaultConfig(name, location, tier string) string {
return fmt.Sprintf(`
resource "google_filestore_instance" "instance" {
name = "%s"
zone = "%s"
tier = "%s"
description = "An instance created during testing."

file_shares {
capacity_gb = 1024
name = "share"
}

networks {
network = "default"
modes = ["MODE_IPV4"]
}
}
`, name, location, tier)
}
Loading