Skip to content
New issue

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

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

Already on GitHub? # to your account

add AutoTier support for netapp storagePools and Volumes #19454

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/11645.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
netapp: added `allow_auto_tiering` field to StoragePool and `tiering_policy` field to Volume resource
```
24 changes: 24 additions & 0 deletions google/services/netapp/resource_netapp_storage_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ func ResourceNetappStoragePool() *schema.Resource {
Optional: true,
Description: `Specifies the Active Directory policy to be used. Format: 'projects/{{project}}/locations/{{location}}/activeDirectories/{{name}}'.
The policy needs to be in the same location as the storage pool.`,
},
"allow_auto_tiering": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
Description: `Optional. True if the storage pool supports Auto Tiering enabled volumes. Default is false.
Auto-tiering can be enabled after storage pool creation but it can't be disabled once enabled.`,
},
"description": {
Type: schema.TypeString,
Expand Down Expand Up @@ -211,6 +218,12 @@ func resourceNetappStoragePoolCreate(d *schema.ResourceData, meta interface{}) e
} else if v, ok := d.GetOkExists("ldap_enabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(ldapEnabledProp)) && (ok || !reflect.DeepEqual(v, ldapEnabledProp)) {
obj["ldapEnabled"] = ldapEnabledProp
}
allowAutoTieringProp, err := expandNetappStoragePoolAllowAutoTiering(d.Get("allow_auto_tiering"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("allow_auto_tiering"); !tpgresource.IsEmptyValue(reflect.ValueOf(allowAutoTieringProp)) && (ok || !reflect.DeepEqual(v, allowAutoTieringProp)) {
obj["allowAutoTiering"] = allowAutoTieringProp
}
labelsProp, err := expandNetappStoragePoolEffectiveLabels(d.Get("effective_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -349,6 +362,9 @@ func resourceNetappStoragePoolRead(d *schema.ResourceData, meta interface{}) err
if err := d.Set("encryption_type", flattenNetappStoragePoolEncryptionType(res["encryptionType"], d, config)); err != nil {
return fmt.Errorf("Error reading StoragePool: %s", err)
}
if err := d.Set("allow_auto_tiering", flattenNetappStoragePoolAllowAutoTiering(res["allowAutoTiering"], d, config)); err != nil {
return fmt.Errorf("Error reading StoragePool: %s", err)
}
if err := d.Set("terraform_labels", flattenNetappStoragePoolTerraformLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading StoragePool: %s", err)
}
Expand Down Expand Up @@ -676,6 +692,10 @@ func flattenNetappStoragePoolEncryptionType(v interface{}, d *schema.ResourceDat
return v
}

func flattenNetappStoragePoolAllowAutoTiering(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenNetappStoragePoolTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return v
Expand Down Expand Up @@ -723,6 +743,10 @@ func expandNetappStoragePoolLdapEnabled(v interface{}, d tpgresource.TerraformRe
return v, nil
}

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

func expandNetappStoragePoolEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
Expand Down
68 changes: 68 additions & 0 deletions google/services/netapp/resource_netapp_storage_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,71 @@ resource "google_netapp_storage_pool" "test_pool" {
}
`, context)
}

func TestAccNetappStoragePool_autoTieredStoragePoolCreateExample_update(t *testing.T) {
context := map[string]interface{}{
"network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "gcnv-network-config-1", acctest.ServiceNetworkWithParentService("netapp.servicenetworking.goog")),
"random_suffix": acctest.RandString(t, 10),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckNetappStoragePoolDestroyProducer(t),
ExternalProviders: map[string]resource.ExternalProvider{
"time": {},
},
Steps: []resource.TestStep{
{
Config: testAccNetappStoragePool_autoTieredStoragePoolCreateExample_full(context),
},
{
ResourceName: "google_netapp_storage_pool.test_pool",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels"},
},
},
})
}

func testAccNetappStoragePool_autoTieredStoragePoolCreateExample_full(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_compute_network" "peering_network" {
name = "tf-test-network%{random_suffix}"
}

# Create an IP address
resource "google_compute_global_address" "private_ip_alloc" {
name = "tf-test-address%{random_suffix}"
purpose = "VPC_PEERING"
address_type = "INTERNAL"
prefix_length = 16
network = google_compute_network.peering_network.id
}

# Create a private connection
resource "google_service_networking_connection" "default" {
network = google_compute_network.peering_network.id
service = "netapp.servicenetworking.goog"
reserved_peering_ranges = [google_compute_global_address.private_ip_alloc.name]
}

resource "google_netapp_storage_pool" "test_pool" {
name = "tf-test-pool%{random_suffix}"
location = "us-east4"
service_level = "PREMIUM"
capacity_gib = "2048"
network = google_compute_network.peering_network.id
active_directory = ""
description = "this is a test description"
kms_config = ""
labels = {
key= "test"
value= "pool"
}
ldap_enabled = false
allow_auto_tiering = true
}
`, context)
}
125 changes: 125 additions & 0 deletions google/services/netapp/resource_netapp_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,29 @@ To disable automatic snapshot creation you have to remove the whole snapshot_pol
},
},
},
"tiering_policy": {
Type: schema.TypeList,
Optional: true,
Description: `Tiering policy for the volume.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"cooling_threshold_days": {
Type: schema.TypeInt,
Optional: true,
Description: `Optional. Time in days to mark the volume's data block as cold and make it eligible for tiering, can be range from 7-183.
Default is 31.`,
},
"tier_action": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidateEnum([]string{"ENABLED", "PAUSED", ""}),
Description: `Optional. Flag indicating if the volume has tiering policy enable/pause. Default is PAUSED. Default value: "PAUSED" Possible values: ["ENABLED", "PAUSED"]`,
Default: "PAUSED",
},
},
},
},
"unix_permissions": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -436,6 +459,11 @@ To disable automatic snapshot creation you have to remove the whole snapshot_pol
Computed: true,
Description: `Reports the resource name of the Active Directory policy being used. Inherited from storage pool.`,
},
"cold_tier_size_gib": {
Type: schema.TypeString,
Computed: true,
Description: `Output only. Size of the volume cold tier data in GiB.`,
},
"create_time": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -667,6 +695,12 @@ func resourceNetappVolumeCreate(d *schema.ResourceData, meta interface{}) error
} else if v, ok := d.GetOkExists("multiple_endpoints"); !tpgresource.IsEmptyValue(reflect.ValueOf(multipleEndpointsProp)) && (ok || !reflect.DeepEqual(v, multipleEndpointsProp)) {
obj["multipleEndpoints"] = multipleEndpointsProp
}
tieringPolicyProp, err := expandNetappVolumeTieringPolicy(d.Get("tiering_policy"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("tiering_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(tieringPolicyProp)) && (ok || !reflect.DeepEqual(v, tieringPolicyProp)) {
obj["tieringPolicy"] = tieringPolicyProp
}
labelsProp, err := expandNetappVolumeEffectiveLabels(d.Get("effective_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -868,6 +902,12 @@ func resourceNetappVolumeRead(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("multiple_endpoints", flattenNetappVolumeMultipleEndpoints(res["multipleEndpoints"], d, config)); err != nil {
return fmt.Errorf("Error reading Volume: %s", err)
}
if err := d.Set("cold_tier_size_gib", flattenNetappVolumeColdTierSizeGib(res["coldTierSizeGib"], d, config)); err != nil {
return fmt.Errorf("Error reading Volume: %s", err)
}
if err := d.Set("tiering_policy", flattenNetappVolumeTieringPolicy(res["tieringPolicy"], d, config)); err != nil {
return fmt.Errorf("Error reading Volume: %s", err)
}
if err := d.Set("terraform_labels", flattenNetappVolumeTerraformLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading Volume: %s", err)
}
Expand Down Expand Up @@ -966,6 +1006,12 @@ func resourceNetappVolumeUpdate(d *schema.ResourceData, meta interface{}) error
} else if v, ok := d.GetOkExists("multiple_endpoints"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, multipleEndpointsProp)) {
obj["multipleEndpoints"] = multipleEndpointsProp
}
tieringPolicyProp, err := expandNetappVolumeTieringPolicy(d.Get("tiering_policy"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("tiering_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, tieringPolicyProp)) {
obj["tieringPolicy"] = tieringPolicyProp
}
labelsProp, err := expandNetappVolumeEffectiveLabels(d.Get("effective_labels"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -1032,6 +1078,11 @@ func resourceNetappVolumeUpdate(d *schema.ResourceData, meta interface{}) error
updateMask = append(updateMask, "multipleEndpoints")
}

if d.HasChange("tiering_policy") {
updateMask = append(updateMask, "tiering_policy.cooling_threshold_days",
"tiering_policy.tier_action")
}

if d.HasChange("effective_labels") {
updateMask = append(updateMask, "labels")
}
Expand Down Expand Up @@ -1719,6 +1770,46 @@ func flattenNetappVolumeMultipleEndpoints(v interface{}, d *schema.ResourceData,
return v
}

func flattenNetappVolumeColdTierSizeGib(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenNetappVolumeTieringPolicy(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["cooling_threshold_days"] =
flattenNetappVolumeTieringPolicyCoolingThresholdDays(original["coolingThresholdDays"], d, config)
transformed["tier_action"] =
flattenNetappVolumeTieringPolicyTierAction(original["tierAction"], d, config)
return []interface{}{transformed}
}
func flattenNetappVolumeTieringPolicyCoolingThresholdDays(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 flattenNetappVolumeTieringPolicyTierAction(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenNetappVolumeTerraformLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return v
Expand Down Expand Up @@ -2266,6 +2357,40 @@ func expandNetappVolumeMultipleEndpoints(v interface{}, d tpgresource.TerraformR
return v, nil
}

func expandNetappVolumeTieringPolicy(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{})

transformedCoolingThresholdDays, err := expandNetappVolumeTieringPolicyCoolingThresholdDays(original["cooling_threshold_days"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedCoolingThresholdDays); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["coolingThresholdDays"] = transformedCoolingThresholdDays
}

transformedTierAction, err := expandNetappVolumeTieringPolicyTierAction(original["tier_action"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedTierAction); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["tierAction"] = transformedTierAction
}

return transformed, nil
}

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

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

func expandNetappVolumeEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
Expand Down
Loading