From d4afa91c4d61804e73543d61ec02877f9889f718 Mon Sep 17 00:00:00 2001 From: The Magician Date: Fri, 12 Jan 2024 11:29:08 -0800 Subject: [PATCH] Added volume module for Google Cloud NetApp Volume (#9513) (#16990) * added volume module * Added updated function and network fix * updated update test fields. * updated unixPermissions field. * updated test file for snapshot_policy * updated description. updated test file with basic example and function name. * removed the *_UNSPECIFIED values for inputs Default values for minutes, hours, days and day_of_week in snapshot block Updated tests to incorporate suggestions by shuya Fixes some indentation in tests Updates some test to get better test coverage commented restoreParamters as suggested by Shuya. * updated tests to use us-west1 region * updated region to us-west2 [upstream:bd6b1b34069c41459496f838c32a8014af9a8dc2] Signed-off-by: Modular Magician --- .changelog/9513.txt | 3 + google/provider/provider_mmv1_resources.go | 5 +- .../services/netapp/resource_netapp_volume.go | 1949 +++++++++++++++++ .../resource_netapp_volume_generated_test.go | 121 + .../netapp/resource_netapp_volume_sweeper.go | 139 ++ .../netapp/resource_netapp_volume_test.go | 330 +++ website/docs/r/netapp_volume.html.markdown | 401 ++++ 7 files changed, 2946 insertions(+), 2 deletions(-) create mode 100644 .changelog/9513.txt create mode 100644 google/services/netapp/resource_netapp_volume.go create mode 100644 google/services/netapp/resource_netapp_volume_generated_test.go create mode 100644 google/services/netapp/resource_netapp_volume_sweeper.go create mode 100644 google/services/netapp/resource_netapp_volume_test.go create mode 100644 website/docs/r/netapp_volume.html.markdown diff --git a/.changelog/9513.txt b/.changelog/9513.txt new file mode 100644 index 00000000000..f2620bd2960 --- /dev/null +++ b/.changelog/9513.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +`google_netapp_volume` +``` diff --git a/google/provider/provider_mmv1_resources.go b/google/provider/provider_mmv1_resources.go index f6a6665de1d..29e93914098 100644 --- a/google/provider/provider_mmv1_resources.go +++ b/google/provider/provider_mmv1_resources.go @@ -377,9 +377,9 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ } // Resources -// Generated resources: 365 +// Generated resources: 366 // Generated IAM resources: 219 -// Total generated resources: 584 +// Total generated resources: 585 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -816,6 +816,7 @@ var generatedResources = map[string]*schema.Resource{ "google_monitoring_custom_service": monitoring.ResourceMonitoringService(), "google_monitoring_slo": monitoring.ResourceMonitoringSlo(), "google_monitoring_uptime_check_config": monitoring.ResourceMonitoringUptimeCheckConfig(), + "google_netapp_volume": netapp.ResourceNetappVolume(), "google_netapp_active_directory": netapp.ResourceNetappactiveDirectory(), "google_netapp_backup_policy": netapp.ResourceNetappbackupPolicy(), "google_netapp_backup_vault": netapp.ResourceNetappbackupVault(), diff --git a/google/services/netapp/resource_netapp_volume.go b/google/services/netapp/resource_netapp_volume.go new file mode 100644 index 00000000000..12580d08290 --- /dev/null +++ b/google/services/netapp/resource_netapp_volume.go @@ -0,0 +1,1949 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package netapp + +import ( + "fmt" + "log" + "reflect" + "strings" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" + "github.com/hashicorp/terraform-provider-google/google/verify" +) + +func ResourceNetappVolume() *schema.Resource { + return &schema.Resource{ + Create: resourceNetappVolumeCreate, + Read: resourceNetappVolumeRead, + Update: resourceNetappVolumeUpdate, + Delete: resourceNetappVolumeDelete, + + Importer: &schema.ResourceImporter{ + State: resourceNetappVolumeImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + tpgresource.SetLabelsDiff, + tpgresource.DefaultProviderProject, + ), + + Schema: map[string]*schema.Schema{ + "capacity_gib": { + Type: schema.TypeString, + Required: true, + Description: `Capacity of the volume (in GiB).`, + }, + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Name of the pool location. Usually a region name, expect for some STANDARD service level pools which require a zone name.`, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The name of the volume. Needs to be unique per location.`, + }, + "protocols": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Description: `The protocol of the volume. Allowed combinations are '['NFSV3']', '['NFSV4']', '['SMB']', '['NFSV3', 'NFSV4']', '['SMB', 'NFSV3']' and '['SMB', 'NFSV4']'. Possible values: ["NFSV3", "NFSV4", "SMB"]`, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidateEnum([]string{"NFSV3", "NFSV4", "SMB"}), + }, + }, + "share_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Share name (SMB) or export path (NFS) of the volume. Needs to be unique per location.`, + }, + "storage_pool": { + Type: schema.TypeString, + Required: true, + Description: `Name of the storage pool to create the volume in. Pool needs enough spare capacity to accomodate the volume.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `An optional description of this resource.`, + }, + "export_policy": { + Type: schema.TypeList, + Optional: true, + Description: `Export policy of the volume for NFSV3 and/or NFSV4.1 access.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rules": { + Type: schema.TypeList, + Required: true, + Description: `Export rules (up to 5) control NFS volume access.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidateEnum([]string{"READ_ONLY", "READ_WRITE", "READ_NONE", ""}), + Description: `Defines the access type for clients matching the 'allowedClients' specification. Possible values: ["READ_ONLY", "READ_WRITE", "READ_NONE"]`, + }, + "allowed_clients": { + Type: schema.TypeString, + Optional: true, + Description: `Defines the client ingress specification (allowed clients) as a comma seperated list with IPv4 CIDRs or IPv4 host addresses.`, + }, + "has_root_access": { + Type: schema.TypeString, + Optional: true, + Description: `If enabled, the root user (UID = 0) of the specified clients doesn't get mapped to nobody (UID = 65534). This is also known as no_root_squash.`, + }, + "kerberos5_read_only": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled (true) the rule defines a read only access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'authentication' kerberos security mode.`, + }, + "kerberos5_read_write": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled (true) the rule defines read and write access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'authentication' kerberos security mode. The 'kerberos5ReadOnly' value is ignored if this is enabled.`, + }, + "kerberos5i_read_only": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled (true) the rule defines a read only access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'integrity' kerberos security mode.`, + }, + "kerberos5i_read_write": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled (true) the rule defines read and write access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'integrity' kerberos security mode. The 'kerberos5iReadOnly' value is ignored if this is enabled.`, + }, + "kerberos5p_read_only": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled (true) the rule defines a read only access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'privacy' kerberos security mode.`, + }, + "kerberos5p_read_write": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled (true) the rule defines read and write access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'privacy' kerberos security mode. The 'kerberos5pReadOnly' value is ignored if this is enabled.`, + }, + "nfsv3": { + Type: schema.TypeBool, + Optional: true, + Description: `Enable to apply the export rule to NFSV3 clients.`, + }, + "nfsv4": { + Type: schema.TypeBool, + Optional: true, + Description: `Enable to apply the export rule to NFSV4.1 clients.`, + }, + }, + }, + }, + }, + }, + }, + "kerberos_enabled": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Description: `Flag indicating if the volume is a kerberos volume or not, export policy rules control kerberos security modes (krb5, krb5i, krb5p).`, + Default: false, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `Labels as key value pairs. Example: '{ "owner": "Bob", "department": "finance", "purpose": "testing" }'. + + +**Note**: This field is non-authoritative, and will only manage the labels present in your configuration. +Please refer to the field 'effective_labels' for all of the labels present on the resource.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "restricted_actions": { + Type: schema.TypeList, + Optional: true, + Description: `List of actions that are restricted on this volume. Possible values: ["DELETE"]`, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidateEnum([]string{"DELETE"}), + }, + }, + "security_style": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + ValidateFunc: verify.ValidateEnum([]string{"NTFS", "UNIX", ""}), + Description: `Security Style of the Volume. Use UNIX to use UNIX or NFSV4 ACLs for file permissions. +Use NTFS to use NTFS ACLs for file permissions. Can only be set for volumes which use SMB together with NFS as protocol. Possible values: ["NTFS", "UNIX"]`, + }, + "smb_settings": { + Type: schema.TypeList, + Optional: true, + Description: `Settings for volumes with SMB access. Possible values: ["ENCRYPT_DATA", "BROWSABLE", "CHANGE_NOTIFY", "NON_BROWSABLE", "OPLOCKS", "SHOW_SNAPSHOT", "SHOW_PREVIOUS_VERSIONS", "ACCESS_BASED_ENUMERATION", "CONTINUOUSLY_AVAILABLE"]`, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidateEnum([]string{"ENCRYPT_DATA", "BROWSABLE", "CHANGE_NOTIFY", "NON_BROWSABLE", "OPLOCKS", "SHOW_SNAPSHOT", "SHOW_PREVIOUS_VERSIONS", "ACCESS_BASED_ENUMERATION", "CONTINUOUSLY_AVAILABLE"}), + }, + }, + "snapshot_directory": { + Type: schema.TypeBool, + Optional: true, + Description: `If enabled, a NFS volume will contain a read-only .snapshot directory which provides access to each of the volume's snapshots. Will enable "Previous Versions" support for SMB.`, + }, + "snapshot_policy": { + Type: schema.TypeList, + Optional: true, + Description: `Snapshot policy defines the schedule for automatic snapshot creation. +To disable automatic snapshot creation you have to remove the whole snapshot_policy block.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "daily_schedule": { + Type: schema.TypeList, + Optional: true, + Description: `Daily schedule policy.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "snapshots_to_keep": { + Type: schema.TypeInt, + Required: true, + Description: `The maximum number of snapshots to keep for the daily schedule.`, + }, + "hour": { + Type: schema.TypeInt, + Optional: true, + Description: `Set the hour to create the snapshot (0-23), defaults to midnight (0).`, + Default: 0, + }, + "minute": { + Type: schema.TypeInt, + Optional: true, + Description: `Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0).`, + Default: 0, + }, + }, + }, + }, + "enabled": { + Type: schema.TypeBool, + Optional: true, + Description: `Enables automated snapshot creation according to defined schedule. Default is false. +To disable automatic snapshot creation you have to remove the whole snapshot_policy block.`, + Default: false, + }, + "hourly_schedule": { + Type: schema.TypeList, + Optional: true, + Description: `Hourly schedule policy.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "snapshots_to_keep": { + Type: schema.TypeInt, + Required: true, + Description: `The maximum number of snapshots to keep for the hourly schedule.`, + }, + "minute": { + Type: schema.TypeInt, + Optional: true, + Description: `Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0).`, + Default: 0, + }, + }, + }, + }, + "monthly_schedule": { + Type: schema.TypeList, + Optional: true, + Description: `Monthly schedule policy.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "snapshots_to_keep": { + Type: schema.TypeInt, + Required: true, + Description: `The maximum number of snapshots to keep for the monthly schedule`, + }, + "days_of_month": { + Type: schema.TypeString, + Optional: true, + Description: `Set the day or days of the month to make a snapshot (1-31). Accepts a comma separated number of days. Defaults to '1'.`, + Default: "1", + }, + "hour": { + Type: schema.TypeInt, + Optional: true, + Description: `Set the hour to create the snapshot (0-23), defaults to midnight (0).`, + Default: 0, + }, + "minute": { + Type: schema.TypeInt, + Optional: true, + Description: `Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0).`, + Default: 0, + }, + }, + }, + }, + "weekly_schedule": { + Type: schema.TypeList, + Optional: true, + Description: `Weekly schedule policy.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "snapshots_to_keep": { + Type: schema.TypeInt, + Required: true, + Description: `The maximum number of snapshots to keep for the weekly schedule.`, + }, + "day": { + Type: schema.TypeString, + Optional: true, + Description: `Set the day or days of the week to make a snapshot. Accepts a comma separated days of the week. Defaults to 'Sunday'.`, + Default: "Sunday", + }, + "hour": { + Type: schema.TypeInt, + Optional: true, + Description: `Set the hour to create the snapshot (0-23), defaults to midnight (0).`, + Default: 0, + }, + "minute": { + Type: schema.TypeInt, + Optional: true, + Description: `Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0).`, + Default: 0, + }, + }, + }, + }, + }, + }, + }, + "unix_permissions": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: `Unix permission the mount point will be created with. Default is 0770. Applicable for UNIX security style volumes only.`, + }, + "active_directory": { + Type: schema.TypeString, + Computed: true, + Description: `Reports the resource name of the Active Directory policy being used. Inherited from storage pool.`, + }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "encryption_type": { + Type: schema.TypeString, + Computed: true, + Description: `Reports the data-at-rest encryption type of the volume. Inherited from storage pool.`, + }, + "has_replication": { + Type: schema.TypeBool, + Computed: true, + Description: `Indicates whether the volume is part of a volume replication relationship.`, + }, + "kms_config": { + Type: schema.TypeString, + Computed: true, + Description: `Reports the CMEK policy resurce name being used for volume encryption. Inherited from storage pool.`, + }, + "ldap_enabled": { + Type: schema.TypeBool, + Computed: true, + Description: `Flag indicating if the volume is NFS LDAP enabled or not. Inherited from storage pool.`, + }, + "mount_options": { + Type: schema.TypeList, + Computed: true, + Description: `Reports mount instructions for this volume.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "export": { + Type: schema.TypeString, + Computed: true, + Description: `Export path of the volume.`, + }, + "export_full": { + Type: schema.TypeString, + Computed: true, + Description: `Full export path of the volume. + +Format for NFS volumes: ':/' + +Format for SMB volumes: '\\\\netbios_prefix-four_random_hex_letters.domain_name\\shareName'`, + }, + "instructions": { + Type: schema.TypeString, + Computed: true, + Description: `Human-readable mount instructions.`, + }, + "protocol": { + Type: schema.TypeString, + Computed: true, + Description: `Protocol to mount with.`, + }, + }, + }, + }, + "network": { + Type: schema.TypeString, + Computed: true, + Description: `VPC network name with format: 'projects/{{project}}/global/networks/{{network}}'. Inherited from storage pool.`, + }, + "psa_range": { + Type: schema.TypeString, + Computed: true, + Description: `Name of the Private Service Access allocated range. Inherited from storage pool.`, + }, + "service_level": { + Type: schema.TypeString, + Computed: true, + Description: `Service level of the volume. Inherited from storage pool.`, + }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "used_gib": { + Type: schema.TypeString, + Computed: true, + Description: `Used capacity of the volume (in GiB). This is computed periodically and it does not represent the realtime usage.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceNetappVolumeCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + shareNameProp, err := expandNetappVolumeShareName(d.Get("share_name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("share_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(shareNameProp)) && (ok || !reflect.DeepEqual(v, shareNameProp)) { + obj["shareName"] = shareNameProp + } + storagePoolProp, err := expandNetappVolumeStoragePool(d.Get("storage_pool"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("storage_pool"); !tpgresource.IsEmptyValue(reflect.ValueOf(storagePoolProp)) && (ok || !reflect.DeepEqual(v, storagePoolProp)) { + obj["storagePool"] = storagePoolProp + } + capacityGibProp, err := expandNetappVolumeCapacityGib(d.Get("capacity_gib"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("capacity_gib"); !tpgresource.IsEmptyValue(reflect.ValueOf(capacityGibProp)) && (ok || !reflect.DeepEqual(v, capacityGibProp)) { + obj["capacityGib"] = capacityGibProp + } + exportPolicyProp, err := expandNetappVolumeExportPolicy(d.Get("export_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("export_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(exportPolicyProp)) && (ok || !reflect.DeepEqual(v, exportPolicyProp)) { + obj["exportPolicy"] = exportPolicyProp + } + protocolsProp, err := expandNetappVolumeProtocols(d.Get("protocols"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("protocols"); !tpgresource.IsEmptyValue(reflect.ValueOf(protocolsProp)) && (ok || !reflect.DeepEqual(v, protocolsProp)) { + obj["protocols"] = protocolsProp + } + smbSettingsProp, err := expandNetappVolumeSmbSettings(d.Get("smb_settings"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("smb_settings"); !tpgresource.IsEmptyValue(reflect.ValueOf(smbSettingsProp)) && (ok || !reflect.DeepEqual(v, smbSettingsProp)) { + obj["smbSettings"] = smbSettingsProp + } + unixPermissionsProp, err := expandNetappVolumeUnixPermissions(d.Get("unix_permissions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("unix_permissions"); !tpgresource.IsEmptyValue(reflect.ValueOf(unixPermissionsProp)) && (ok || !reflect.DeepEqual(v, unixPermissionsProp)) { + obj["unixPermissions"] = unixPermissionsProp + } + descriptionProp, err := expandNetappVolumeDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + snapshotDirectoryProp, err := expandNetappVolumeSnapshotDirectory(d.Get("snapshot_directory"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("snapshot_directory"); !tpgresource.IsEmptyValue(reflect.ValueOf(snapshotDirectoryProp)) && (ok || !reflect.DeepEqual(v, snapshotDirectoryProp)) { + obj["snapshotDirectory"] = snapshotDirectoryProp + } + securityStyleProp, err := expandNetappVolumeSecurityStyle(d.Get("security_style"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("security_style"); !tpgresource.IsEmptyValue(reflect.ValueOf(securityStyleProp)) && (ok || !reflect.DeepEqual(v, securityStyleProp)) { + obj["securityStyle"] = securityStyleProp + } + kerberosEnabledProp, err := expandNetappVolumeKerberosEnabled(d.Get("kerberos_enabled"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("kerberos_enabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(kerberosEnabledProp)) && (ok || !reflect.DeepEqual(v, kerberosEnabledProp)) { + obj["kerberosEnabled"] = kerberosEnabledProp + } + restrictedActionsProp, err := expandNetappVolumeRestrictedActions(d.Get("restricted_actions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("restricted_actions"); !tpgresource.IsEmptyValue(reflect.ValueOf(restrictedActionsProp)) && (ok || !reflect.DeepEqual(v, restrictedActionsProp)) { + obj["restrictedActions"] = restrictedActionsProp + } + snapshotPolicyProp, err := expandNetappVolumeSnapshotPolicy(d.Get("snapshot_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("snapshot_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(snapshotPolicyProp)) && (ok || !reflect.DeepEqual(v, snapshotPolicyProp)) { + obj["snapshotPolicy"] = snapshotPolicyProp + } + labelsProp, err := expandNetappVolumeEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes?volumeId={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new Volume: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Volume: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return fmt.Errorf("Error creating Volume: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/volumes/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = NetappOperationWaitTime( + config, res, project, "Creating Volume", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create Volume: %s", err) + } + + log.Printf("[DEBUG] Finished creating Volume %q: %#v", d.Id(), res) + + return resourceNetappVolumeRead(d, meta) +} + +func resourceNetappVolumeRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Volume: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("NetappVolume %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + + if err := d.Set("share_name", flattenNetappVolumeShareName(res["shareName"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("psa_range", flattenNetappVolumePsaRange(res["psaRange"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("storage_pool", flattenNetappVolumeStoragePool(res["storagePool"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("network", flattenNetappVolumeNetwork(res["network"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("service_level", flattenNetappVolumeServiceLevel(res["serviceLevel"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("capacity_gib", flattenNetappVolumeCapacityGib(res["capacityGib"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("export_policy", flattenNetappVolumeExportPolicy(res["exportPolicy"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("protocols", flattenNetappVolumeProtocols(res["protocols"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("smb_settings", flattenNetappVolumeSmbSettings(res["smbSettings"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("unix_permissions", flattenNetappVolumeUnixPermissions(res["unixPermissions"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("labels", flattenNetappVolumeLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("description", flattenNetappVolumeDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("snapshot_directory", flattenNetappVolumeSnapshotDirectory(res["snapshotDirectory"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("used_gib", flattenNetappVolumeUsedGib(res["usedGib"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("security_style", flattenNetappVolumeSecurityStyle(res["securityStyle"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("kerberos_enabled", flattenNetappVolumeKerberosEnabled(res["kerberosEnabled"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("ldap_enabled", flattenNetappVolumeLdapEnabled(res["ldapEnabled"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("active_directory", flattenNetappVolumeActiveDirectory(res["activeDirectory"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("kms_config", flattenNetappVolumeKmsConfig(res["kmsConfig"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("encryption_type", flattenNetappVolumeEncryptionType(res["encryptionType"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("has_replication", flattenNetappVolumeHasReplication(res["hasReplication"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("restricted_actions", flattenNetappVolumeRestrictedActions(res["restrictedActions"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("mount_options", flattenNetappVolumeMountOptions(res["mountOptions"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + if err := d.Set("snapshot_policy", flattenNetappVolumeSnapshotPolicy(res["snapshotPolicy"], 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) + } + if err := d.Set("effective_labels", flattenNetappVolumeEffectiveLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading Volume: %s", err) + } + + return nil +} + +func resourceNetappVolumeUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Volume: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + storagePoolProp, err := expandNetappVolumeStoragePool(d.Get("storage_pool"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("storage_pool"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, storagePoolProp)) { + obj["storagePool"] = storagePoolProp + } + capacityGibProp, err := expandNetappVolumeCapacityGib(d.Get("capacity_gib"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("capacity_gib"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, capacityGibProp)) { + obj["capacityGib"] = capacityGibProp + } + exportPolicyProp, err := expandNetappVolumeExportPolicy(d.Get("export_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("export_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, exportPolicyProp)) { + obj["exportPolicy"] = exportPolicyProp + } + smbSettingsProp, err := expandNetappVolumeSmbSettings(d.Get("smb_settings"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("smb_settings"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, smbSettingsProp)) { + obj["smbSettings"] = smbSettingsProp + } + unixPermissionsProp, err := expandNetappVolumeUnixPermissions(d.Get("unix_permissions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("unix_permissions"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, unixPermissionsProp)) { + obj["unixPermissions"] = unixPermissionsProp + } + descriptionProp, err := expandNetappVolumeDescription(d.Get("description"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { + obj["description"] = descriptionProp + } + snapshotDirectoryProp, err := expandNetappVolumeSnapshotDirectory(d.Get("snapshot_directory"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("snapshot_directory"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, snapshotDirectoryProp)) { + obj["snapshotDirectory"] = snapshotDirectoryProp + } + restrictedActionsProp, err := expandNetappVolumeRestrictedActions(d.Get("restricted_actions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("restricted_actions"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, restrictedActionsProp)) { + obj["restrictedActions"] = restrictedActionsProp + } + snapshotPolicyProp, err := expandNetappVolumeSnapshotPolicy(d.Get("snapshot_policy"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("snapshot_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, snapshotPolicyProp)) { + obj["snapshotPolicy"] = snapshotPolicyProp + } + labelsProp, err := expandNetappVolumeEffectiveLabels(d.Get("effective_labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("effective_labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating Volume %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("storage_pool") { + updateMask = append(updateMask, "storagePool") + } + + if d.HasChange("capacity_gib") { + updateMask = append(updateMask, "capacityGib") + } + + if d.HasChange("export_policy") { + updateMask = append(updateMask, "exportPolicy") + } + + if d.HasChange("smb_settings") { + updateMask = append(updateMask, "smbSettings") + } + + if d.HasChange("unix_permissions") { + updateMask = append(updateMask, "unixPermissions") + } + + if d.HasChange("description") { + updateMask = append(updateMask, "description") + } + + if d.HasChange("snapshot_directory") { + updateMask = append(updateMask, "snapshotDirectory") + } + + if d.HasChange("restricted_actions") { + updateMask = append(updateMask, "restrictedActions") + } + + if d.HasChange("snapshot_policy") { + updateMask = append(updateMask, "snapshotPolicy") + } + + if d.HasChange("effective_labels") { + updateMask = append(updateMask, "labels") + } + // updateMask is a URL parameter but not present in the schema, so ReplaceVars + // won't set it + url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) + if err != nil { + return err + } + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + // if updateMask is empty we are not updating anything so skip the post + if len(updateMask) > 0 { + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + + if err != nil { + return fmt.Errorf("Error updating Volume %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating Volume %q: %#v", d.Id(), res) + } + + err = NetappOperationWaitTime( + config, res, project, "Updating Volume", userAgent, + d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return err + } + } + + return resourceNetappVolumeRead(d, meta) +} + +func resourceNetappVolumeDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for Volume: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting Volume %q", d.Id()) + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "Volume") + } + + err = NetappOperationWaitTime( + config, res, project, "Deleting Volume", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting Volume %q: %#v", d.Id(), res) + return nil +} + +func resourceNetappVolumeImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "^projects/(?P[^/]+)/locations/(?P[^/]+)/volumes/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$", + "^(?P[^/]+)/(?P[^/]+)$", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/volumes/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenNetappVolumeShareName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumePsaRange(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeStoragePool(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeNetwork(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeServiceLevel(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeCapacityGib(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicy(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["rules"] = + flattenNetappVolumeExportPolicyRules(original["rules"], d, config) + return []interface{}{transformed} +} +func flattenNetappVolumeExportPolicyRules(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "allowed_clients": flattenNetappVolumeExportPolicyRulesAllowedClients(original["allowedClients"], d, config), + "has_root_access": flattenNetappVolumeExportPolicyRulesHasRootAccess(original["hasRootAccess"], d, config), + "access_type": flattenNetappVolumeExportPolicyRulesAccessType(original["accessType"], d, config), + "nfsv3": flattenNetappVolumeExportPolicyRulesNfsv3(original["nfsv3"], d, config), + "nfsv4": flattenNetappVolumeExportPolicyRulesNfsv4(original["nfsv4"], d, config), + "kerberos5_read_only": flattenNetappVolumeExportPolicyRulesKerberos5ReadOnly(original["kerberos5ReadOnly"], d, config), + "kerberos5_read_write": flattenNetappVolumeExportPolicyRulesKerberos5ReadWrite(original["kerberos5ReadWrite"], d, config), + "kerberos5i_read_only": flattenNetappVolumeExportPolicyRulesKerberos5iReadOnly(original["kerberos5iReadOnly"], d, config), + "kerberos5i_read_write": flattenNetappVolumeExportPolicyRulesKerberos5iReadWrite(original["kerberos5iReadWrite"], d, config), + "kerberos5p_read_only": flattenNetappVolumeExportPolicyRulesKerberos5pReadOnly(original["kerberos5pReadOnly"], d, config), + "kerberos5p_read_write": flattenNetappVolumeExportPolicyRulesKerberos5pReadWrite(original["kerberos5pReadWrite"], d, config), + }) + } + return transformed +} +func flattenNetappVolumeExportPolicyRulesAllowedClients(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesHasRootAccess(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesAccessType(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesNfsv3(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesNfsv4(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesKerberos5ReadOnly(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesKerberos5ReadWrite(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesKerberos5iReadOnly(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesKerberos5iReadWrite(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesKerberos5pReadOnly(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeExportPolicyRulesKerberos5pReadWrite(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeProtocols(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeSmbSettings(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeUnixPermissions(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenNetappVolumeDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeSnapshotDirectory(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeUsedGib(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeSecurityStyle(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeKerberosEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeLdapEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeActiveDirectory(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeKmsConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeEncryptionType(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeHasReplication(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeRestrictedActions(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeMountOptions(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "export": flattenNetappVolumeMountOptionsExport(original["export"], d, config), + "export_full": flattenNetappVolumeMountOptionsExportFull(original["exportFull"], d, config), + "instructions": flattenNetappVolumeMountOptionsInstructions(original["instructions"], d, config), + "protocol": flattenNetappVolumeMountOptionsProtocol(original["protocol"], d, config), + }) + } + return transformed +} +func flattenNetappVolumeMountOptionsExport(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeMountOptionsExportFull(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeMountOptionsInstructions(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeMountOptionsProtocol(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeSnapshotPolicy(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["enabled"] = + flattenNetappVolumeSnapshotPolicyEnabled(original["enabled"], d, config) + transformed["hourly_schedule"] = + flattenNetappVolumeSnapshotPolicyHourlySchedule(original["hourlySchedule"], d, config) + transformed["daily_schedule"] = + flattenNetappVolumeSnapshotPolicyDailySchedule(original["dailySchedule"], d, config) + transformed["weekly_schedule"] = + flattenNetappVolumeSnapshotPolicyWeeklySchedule(original["weeklySchedule"], d, config) + transformed["monthly_schedule"] = + flattenNetappVolumeSnapshotPolicyMonthlySchedule(original["monthlySchedule"], d, config) + return []interface{}{transformed} +} +func flattenNetappVolumeSnapshotPolicyEnabled(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeSnapshotPolicyHourlySchedule(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["snapshots_to_keep"] = + flattenNetappVolumeSnapshotPolicyHourlyScheduleSnapshotsToKeep(original["snapshotsToKeep"], d, config) + transformed["minute"] = + flattenNetappVolumeSnapshotPolicyHourlyScheduleMinute(original["minute"], d, config) + return []interface{}{transformed} +} +func flattenNetappVolumeSnapshotPolicyHourlyScheduleSnapshotsToKeep(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 flattenNetappVolumeSnapshotPolicyHourlyScheduleMinute(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 flattenNetappVolumeSnapshotPolicyDailySchedule(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["snapshots_to_keep"] = + flattenNetappVolumeSnapshotPolicyDailyScheduleSnapshotsToKeep(original["snapshotsToKeep"], d, config) + transformed["minute"] = + flattenNetappVolumeSnapshotPolicyDailyScheduleMinute(original["minute"], d, config) + transformed["hour"] = + flattenNetappVolumeSnapshotPolicyDailyScheduleHour(original["hour"], d, config) + return []interface{}{transformed} +} +func flattenNetappVolumeSnapshotPolicyDailyScheduleSnapshotsToKeep(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 flattenNetappVolumeSnapshotPolicyDailyScheduleMinute(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 flattenNetappVolumeSnapshotPolicyDailyScheduleHour(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 flattenNetappVolumeSnapshotPolicyWeeklySchedule(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["snapshots_to_keep"] = + flattenNetappVolumeSnapshotPolicyWeeklyScheduleSnapshotsToKeep(original["snapshotsToKeep"], d, config) + transformed["minute"] = + flattenNetappVolumeSnapshotPolicyWeeklyScheduleMinute(original["minute"], d, config) + transformed["hour"] = + flattenNetappVolumeSnapshotPolicyWeeklyScheduleHour(original["hour"], d, config) + transformed["day"] = + flattenNetappVolumeSnapshotPolicyWeeklyScheduleDay(original["day"], d, config) + return []interface{}{transformed} +} +func flattenNetappVolumeSnapshotPolicyWeeklyScheduleSnapshotsToKeep(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 flattenNetappVolumeSnapshotPolicyWeeklyScheduleMinute(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 flattenNetappVolumeSnapshotPolicyWeeklyScheduleHour(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 flattenNetappVolumeSnapshotPolicyWeeklyScheduleDay(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetappVolumeSnapshotPolicyMonthlySchedule(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["snapshots_to_keep"] = + flattenNetappVolumeSnapshotPolicyMonthlyScheduleSnapshotsToKeep(original["snapshotsToKeep"], d, config) + transformed["minute"] = + flattenNetappVolumeSnapshotPolicyMonthlyScheduleMinute(original["minute"], d, config) + transformed["hour"] = + flattenNetappVolumeSnapshotPolicyMonthlyScheduleHour(original["hour"], d, config) + transformed["days_of_month"] = + flattenNetappVolumeSnapshotPolicyMonthlyScheduleDaysOfMonth(original["daysOfMonth"], d, config) + return []interface{}{transformed} +} +func flattenNetappVolumeSnapshotPolicyMonthlyScheduleSnapshotsToKeep(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 flattenNetappVolumeSnapshotPolicyMonthlyScheduleMinute(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 flattenNetappVolumeSnapshotPolicyMonthlyScheduleHour(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 flattenNetappVolumeSnapshotPolicyMonthlyScheduleDaysOfMonth(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 + } + + transformed := make(map[string]interface{}) + if l, ok := d.GetOkExists("terraform_labels"); ok { + for k := range l.(map[string]interface{}) { + transformed[k] = v.(map[string]interface{})[k] + } + } + + return transformed +} + +func flattenNetappVolumeEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandNetappVolumeShareName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeStoragePool(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeCapacityGib(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicy(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{}) + + transformedRules, err := expandNetappVolumeExportPolicyRules(original["rules"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRules); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["rules"] = transformedRules + } + + return transformed, nil +} + +func expandNetappVolumeExportPolicyRules(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedAllowedClients, err := expandNetappVolumeExportPolicyRulesAllowedClients(original["allowed_clients"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowedClients); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["allowedClients"] = transformedAllowedClients + } + + transformedHasRootAccess, err := expandNetappVolumeExportPolicyRulesHasRootAccess(original["has_root_access"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHasRootAccess); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["hasRootAccess"] = transformedHasRootAccess + } + + transformedAccessType, err := expandNetappVolumeExportPolicyRulesAccessType(original["access_type"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAccessType); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["accessType"] = transformedAccessType + } + + transformedNfsv3, err := expandNetappVolumeExportPolicyRulesNfsv3(original["nfsv3"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNfsv3); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["nfsv3"] = transformedNfsv3 + } + + transformedNfsv4, err := expandNetappVolumeExportPolicyRulesNfsv4(original["nfsv4"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedNfsv4); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["nfsv4"] = transformedNfsv4 + } + + transformedKerberos5ReadOnly, err := expandNetappVolumeExportPolicyRulesKerberos5ReadOnly(original["kerberos5_read_only"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKerberos5ReadOnly); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["kerberos5ReadOnly"] = transformedKerberos5ReadOnly + } + + transformedKerberos5ReadWrite, err := expandNetappVolumeExportPolicyRulesKerberos5ReadWrite(original["kerberos5_read_write"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKerberos5ReadWrite); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["kerberos5ReadWrite"] = transformedKerberos5ReadWrite + } + + transformedKerberos5iReadOnly, err := expandNetappVolumeExportPolicyRulesKerberos5iReadOnly(original["kerberos5i_read_only"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKerberos5iReadOnly); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["kerberos5iReadOnly"] = transformedKerberos5iReadOnly + } + + transformedKerberos5iReadWrite, err := expandNetappVolumeExportPolicyRulesKerberos5iReadWrite(original["kerberos5i_read_write"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKerberos5iReadWrite); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["kerberos5iReadWrite"] = transformedKerberos5iReadWrite + } + + transformedKerberos5pReadOnly, err := expandNetappVolumeExportPolicyRulesKerberos5pReadOnly(original["kerberos5p_read_only"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKerberos5pReadOnly); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["kerberos5pReadOnly"] = transformedKerberos5pReadOnly + } + + transformedKerberos5pReadWrite, err := expandNetappVolumeExportPolicyRulesKerberos5pReadWrite(original["kerberos5p_read_write"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKerberos5pReadWrite); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["kerberos5pReadWrite"] = transformedKerberos5pReadWrite + } + + req = append(req, transformed) + } + return req, nil +} + +func expandNetappVolumeExportPolicyRulesAllowedClients(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesHasRootAccess(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesAccessType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesNfsv3(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesNfsv4(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesKerberos5ReadOnly(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesKerberos5ReadWrite(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesKerberos5iReadOnly(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesKerberos5iReadWrite(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesKerberos5pReadOnly(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeExportPolicyRulesKerberos5pReadWrite(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeProtocols(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSmbSettings(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeUnixPermissions(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotDirectory(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSecurityStyle(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeKerberosEnabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeRestrictedActions(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicy(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{}) + + transformedEnabled, err := expandNetappVolumeSnapshotPolicyEnabled(original["enabled"], d, config) + if err != nil { + return nil, err + } else { + transformed["enabled"] = transformedEnabled + } + + transformedHourlySchedule, err := expandNetappVolumeSnapshotPolicyHourlySchedule(original["hourly_schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHourlySchedule); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["hourlySchedule"] = transformedHourlySchedule + } + + transformedDailySchedule, err := expandNetappVolumeSnapshotPolicyDailySchedule(original["daily_schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDailySchedule); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["dailySchedule"] = transformedDailySchedule + } + + transformedWeeklySchedule, err := expandNetappVolumeSnapshotPolicyWeeklySchedule(original["weekly_schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedWeeklySchedule); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["weeklySchedule"] = transformedWeeklySchedule + } + + transformedMonthlySchedule, err := expandNetappVolumeSnapshotPolicyMonthlySchedule(original["monthly_schedule"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMonthlySchedule); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["monthlySchedule"] = transformedMonthlySchedule + } + + return transformed, nil +} + +func expandNetappVolumeSnapshotPolicyEnabled(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyHourlySchedule(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{}) + + transformedSnapshotsToKeep, err := expandNetappVolumeSnapshotPolicyHourlyScheduleSnapshotsToKeep(original["snapshots_to_keep"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSnapshotsToKeep); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["snapshotsToKeep"] = transformedSnapshotsToKeep + } + + transformedMinute, err := expandNetappVolumeSnapshotPolicyHourlyScheduleMinute(original["minute"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMinute); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["minute"] = transformedMinute + } + + return transformed, nil +} + +func expandNetappVolumeSnapshotPolicyHourlyScheduleSnapshotsToKeep(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyHourlyScheduleMinute(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyDailySchedule(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{}) + + transformedSnapshotsToKeep, err := expandNetappVolumeSnapshotPolicyDailyScheduleSnapshotsToKeep(original["snapshots_to_keep"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSnapshotsToKeep); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["snapshotsToKeep"] = transformedSnapshotsToKeep + } + + transformedMinute, err := expandNetappVolumeSnapshotPolicyDailyScheduleMinute(original["minute"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMinute); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["minute"] = transformedMinute + } + + transformedHour, err := expandNetappVolumeSnapshotPolicyDailyScheduleHour(original["hour"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHour); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["hour"] = transformedHour + } + + return transformed, nil +} + +func expandNetappVolumeSnapshotPolicyDailyScheduleSnapshotsToKeep(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyDailyScheduleMinute(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyDailyScheduleHour(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyWeeklySchedule(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{}) + + transformedSnapshotsToKeep, err := expandNetappVolumeSnapshotPolicyWeeklyScheduleSnapshotsToKeep(original["snapshots_to_keep"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSnapshotsToKeep); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["snapshotsToKeep"] = transformedSnapshotsToKeep + } + + transformedMinute, err := expandNetappVolumeSnapshotPolicyWeeklyScheduleMinute(original["minute"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMinute); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["minute"] = transformedMinute + } + + transformedHour, err := expandNetappVolumeSnapshotPolicyWeeklyScheduleHour(original["hour"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHour); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["hour"] = transformedHour + } + + transformedDay, err := expandNetappVolumeSnapshotPolicyWeeklyScheduleDay(original["day"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDay); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["day"] = transformedDay + } + + return transformed, nil +} + +func expandNetappVolumeSnapshotPolicyWeeklyScheduleSnapshotsToKeep(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyWeeklyScheduleMinute(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyWeeklyScheduleHour(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyWeeklyScheduleDay(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyMonthlySchedule(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{}) + + transformedSnapshotsToKeep, err := expandNetappVolumeSnapshotPolicyMonthlyScheduleSnapshotsToKeep(original["snapshots_to_keep"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSnapshotsToKeep); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["snapshotsToKeep"] = transformedSnapshotsToKeep + } + + transformedMinute, err := expandNetappVolumeSnapshotPolicyMonthlyScheduleMinute(original["minute"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedMinute); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["minute"] = transformedMinute + } + + transformedHour, err := expandNetappVolumeSnapshotPolicyMonthlyScheduleHour(original["hour"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedHour); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["hour"] = transformedHour + } + + transformedDaysOfMonth, err := expandNetappVolumeSnapshotPolicyMonthlyScheduleDaysOfMonth(original["days_of_month"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDaysOfMonth); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["daysOfMonth"] = transformedDaysOfMonth + } + + return transformed, nil +} + +func expandNetappVolumeSnapshotPolicyMonthlyScheduleSnapshotsToKeep(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyMonthlyScheduleMinute(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyMonthlyScheduleHour(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetappVolumeSnapshotPolicyMonthlyScheduleDaysOfMonth(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 + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} diff --git a/google/services/netapp/resource_netapp_volume_generated_test.go b/google/services/netapp/resource_netapp_volume_generated_test.go new file mode 100644 index 00000000000..0eafdbbd68c --- /dev/null +++ b/google/services/netapp/resource_netapp_volume_generated_test.go @@ -0,0 +1,121 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package netapp_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestAccNetappVolume_volumeBasicExample(t *testing.T) { + t.Parallel() + + 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: testAccCheckNetappVolumeDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetappVolume_volumeBasicExample(context), + }, + { + ResourceName: "google_netapp_volume.test_volume", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetappVolume_volumeBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_netapp_storage_pool" "default" { + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "test_volume" { + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "100" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default.name + protocols = ["NFSV3"] +} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +} + +func testAccCheckNetappVolumeDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_netapp_volume" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("NetappVolume still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/services/netapp/resource_netapp_volume_sweeper.go b/google/services/netapp/resource_netapp_volume_sweeper.go new file mode 100644 index 00000000000..2698a8b4761 --- /dev/null +++ b/google/services/netapp/resource_netapp_volume_sweeper.go @@ -0,0 +1,139 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package netapp + +import ( + "context" + "log" + "strings" + "testing" + + "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/sweeper" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + sweeper.AddTestSweepers("NetappVolume", testSweepNetappVolume) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepNetappVolume(region string) error { + resourceName := "NetappVolume" + log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) + + config, err := sweeper.SharedConfigForRegion(region) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) + return err + } + + err = config.LoadAndValidate(context.Background()) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) + return err + } + + t := &testing.T{} + billingId := envvar.GetTestBillingAccountFromEnv(t) + + // Setup variables to replace in list template + d := &tpgresource.ResourceDataMock{ + FieldsInSchema: map[string]interface{}{ + "project": config.Project, + "region": region, + "location": region, + "zone": "-", + "billing_account": billingId, + }, + } + + listTemplate := strings.Split("https://netapp.googleapis.com/v1/projects/{{project}}/locations/{{location}}/volumes", "?")[0] + listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) + return nil + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: config.Project, + RawURL: listUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) + return nil + } + + resourceList, ok := res["volumes"] + if !ok { + log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") + return nil + } + + rl := resourceList.([]interface{}) + + log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) + // Keep count of items that aren't sweepable for logging. + nonPrefixCount := 0 + for _, ri := range rl { + obj := ri.(map[string]interface{}) + if obj["name"] == nil { + log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) + return nil + } + + name := tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) + // Skip resources that shouldn't be sweeped + if !sweeper.IsSweepableTestResource(name) { + nonPrefixCount++ + continue + } + + deleteTemplate := "https://netapp.googleapis.com/v1/projects/{{project}}/locations/{{location}}/volumes/{{name}}" + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google/services/netapp/resource_netapp_volume_test.go b/google/services/netapp/resource_netapp_volume_test.go new file mode 100644 index 00000000000..8659767dfbd --- /dev/null +++ b/google/services/netapp/resource_netapp_volume_test.go @@ -0,0 +1,330 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package netapp_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetappVolume_volumeBasicExample_update(t *testing.T) { + t.Parallel() + + 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: testAccCheckNetappVolumeDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetappVolume_volumeBasicExample_basic(context), + }, + { + ResourceName: "google_netapp_volume.test_volume", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels"}, + }, { + Config: testAccNetappVolume_volumeBasicExample_full(context), + }, + { + ResourceName: "google_netapp_volume.test_volume", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels"}, + }, + { + Config: testAccNetappVolume_volumeBasicExample_update(context), + }, + { + ResourceName: "google_netapp_volume.test_volume", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels"}, + }, + { + Config: testAccNetappVolume_volumeBasicExample_updatesnapshot(context), + }, + { + ResourceName: "google_netapp_volume.test_volume", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccNetappVolume_volumeBasicExample_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_netapp_storage_pool" "default" { + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "test_volume" { + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "100" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default.name + protocols = ["NFSV3"] +} + +data "google_compute_network" "default" { + name = "%{network_name}" +} +`, context) +} + +func testAccNetappVolume_volumeBasicExample_full(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_netapp_storage_pool" "default" { + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "default2" { + name = "tf-test-pool%{random_suffix}" + location = "us-west2" + service_level = "EXTREME" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "test_volume" { + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "100" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default.name + protocols = ["NFSV3"] + smb_settings = [] + unix_permissions = "0770" + labels = { + key= "test" + value= "pool" + } + description = "This is a test description" + snapshot_directory = false + security_style = "UNIX" + kerberos_enabled = false + export_policy { + rules { + access_type = "READ_ONLY" + allowed_clients = "0.0.0.0/0" + has_root_access = "false" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + rules { + access_type = "READ_WRITE" + allowed_clients = "10.2.3.4,10.2.3.5" + has_root_access = "true" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + } + restricted_actions = [] + snapshot_policy { + daily_schedule { + snapshots_to_keep = 2 + } + enabled = true + hourly_schedule { + snapshots_to_keep = 2 + } + monthly_schedule { + snapshots_to_keep = 4 + } + weekly_schedule { + snapshots_to_keep = 2 + } + } +} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + `, context) +} + +func testAccNetappVolume_volumeBasicExample_update(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_netapp_storage_pool" "default" { + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "default2" { + name = "tf-test-pool%{random_suffix}" + location = "us-west2" + service_level = "EXTREME" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "test_volume" { + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "200" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default2.name + protocols = ["NFSV3"] + smb_settings = [] + unix_permissions = "0740" + labels = {} + description = "" + snapshot_directory = true + security_style = "UNIX" + kerberos_enabled = false + export_policy { + rules { + access_type = "READ_WRITE" + allowed_clients = "0.0.0.0/0" + has_root_access = "true" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + } + restricted_actions = ["DELETE"] + snapshot_policy { + enabled = true + daily_schedule { + hour = 1 + minute = 2 + snapshots_to_keep = 1 + } + hourly_schedule { + minute = 10 + snapshots_to_keep = 1 + } + monthly_schedule { + days_of_month = "2" + hour = 3 + minute = 4 + snapshots_to_keep = 1 + } + weekly_schedule { + day = "Monday" + hour = 5 + minute = 6 + snapshots_to_keep = 1 + } + } +} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + `, context) +} + +func testAccNetappVolume_volumeBasicExample_updatesnapshot(context map[string]interface{}) string { + return acctest.Nprintf(` + +resource "google_netapp_storage_pool" "default" { + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "default2" { + name = "tf-test-pool%{random_suffix}" + location = "us-west2" + service_level = "EXTREME" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "test_volume" { + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "200" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default2.name + protocols = ["NFSV3"] + smb_settings = [] + unix_permissions = "0740" + labels = {} + description = "" + snapshot_directory = true + security_style = "UNIX" + kerberos_enabled = false + export_policy { + rules { + access_type = "READ_WRITE" + allowed_clients = "0.0.0.0/0" + has_root_access = "true" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + } + restricted_actions = ["DELETE"] + } + +data "google_compute_network" "default" { + name = "%{network_name}" +} + `, context) +} diff --git a/website/docs/r/netapp_volume.html.markdown b/website/docs/r/netapp_volume.html.markdown new file mode 100644 index 00000000000..4fe659dc535 --- /dev/null +++ b/website/docs/r/netapp_volume.html.markdown @@ -0,0 +1,401 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Netapp" +description: |- + A volume is a file system container in a storage pool that stores application, database, and user data. +--- + +# google\_netapp\_volume + +A volume is a file system container in a storage pool that stores application, database, and user data. + +You can create a volume's capacity using the available capacity in the storage pool and you can define and resize the capacity without disruption to any processes. + +Storage pool settings apply to the volumes contained within them automatically. + + +To get more information about Volume, see: + +* [API documentation](https://cloud.google.com/netapp/volumes/docs/reference/rest/v1/projects.locations.volumes) +* How-to Guides + * [Quickstart](https://cloud.google.com/netapp/volumes/docs/get-started/quickstarts/create-volume) + * [Documentation](https://cloud.google.com/netapp/volumes/docs/configure-and-use/volumes/overview) + + +## Example Usage - Volume Basic + + +```hcl +resource "google_netapp_storage_pool" "default" { + name = "test-pool" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "test_volume" { + location = "us-west2" + name = "test-volume" + capacity_gib = "100" + share_name = "test-volume" + storage_pool = google_netapp_storage_pool.default.name + protocols = ["NFSV3"] +} + +data "google_compute_network" "default" { + name = "test-network" +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `share_name` - + (Required) + Share name (SMB) or export path (NFS) of the volume. Needs to be unique per location. + +* `storage_pool` - + (Required) + Name of the storage pool to create the volume in. Pool needs enough spare capacity to accomodate the volume. + +* `capacity_gib` - + (Required) + Capacity of the volume (in GiB). + +* `protocols` - + (Required) + The protocol of the volume. Allowed combinations are `['NFSV3']`, `['NFSV4']`, `['SMB']`, `['NFSV3', 'NFSV4']`, `['SMB', 'NFSV3']` and `['SMB', 'NFSV4']`. + Each value may be one of: `NFSV3`, `NFSV4`, `SMB`. + +* `location` - + (Required) + Name of the pool location. Usually a region name, expect for some STANDARD service level pools which require a zone name. + +* `name` - + (Required) + The name of the volume. Needs to be unique per location. + + +- - - + + +* `export_policy` - + (Optional) + Export policy of the volume for NFSV3 and/or NFSV4.1 access. + Structure is [documented below](#nested_export_policy). + +* `smb_settings` - + (Optional) + Settings for volumes with SMB access. + Each value may be one of: `ENCRYPT_DATA`, `BROWSABLE`, `CHANGE_NOTIFY`, `NON_BROWSABLE`, `OPLOCKS`, `SHOW_SNAPSHOT`, `SHOW_PREVIOUS_VERSIONS`, `ACCESS_BASED_ENUMERATION`, `CONTINUOUSLY_AVAILABLE`. + +* `unix_permissions` - + (Optional) + Unix permission the mount point will be created with. Default is 0770. Applicable for UNIX security style volumes only. + +* `labels` - + (Optional) + Labels as key value pairs. Example: `{ "owner": "Bob", "department": "finance", "purpose": "testing" }`. + + **Note**: This field is non-authoritative, and will only manage the labels present in your configuration. + Please refer to the field `effective_labels` for all of the labels present on the resource. + +* `description` - + (Optional) + An optional description of this resource. + +* `snapshot_directory` - + (Optional) + If enabled, a NFS volume will contain a read-only .snapshot directory which provides access to each of the volume's snapshots. Will enable "Previous Versions" support for SMB. + +* `security_style` - + (Optional) + Security Style of the Volume. Use UNIX to use UNIX or NFSV4 ACLs for file permissions. + Use NTFS to use NTFS ACLs for file permissions. Can only be set for volumes which use SMB together with NFS as protocol. + Possible values are: `NTFS`, `UNIX`. + +* `kerberos_enabled` - + (Optional) + Flag indicating if the volume is a kerberos volume or not, export policy rules control kerberos security modes (krb5, krb5i, krb5p). + +* `restricted_actions` - + (Optional) + List of actions that are restricted on this volume. + Each value may be one of: `DELETE`. + +* `snapshot_policy` - + (Optional) + Snapshot policy defines the schedule for automatic snapshot creation. + To disable automatic snapshot creation you have to remove the whole snapshot_policy block. + Structure is [documented below](#nested_snapshot_policy). + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `export_policy` block supports: + +* `rules` - + (Required) + Export rules (up to 5) control NFS volume access. + Structure is [documented below](#nested_rules). + + +The `rules` block supports: + +* `allowed_clients` - + (Optional) + Defines the client ingress specification (allowed clients) as a comma seperated list with IPv4 CIDRs or IPv4 host addresses. + +* `has_root_access` - + (Optional) + If enabled, the root user (UID = 0) of the specified clients doesn't get mapped to nobody (UID = 65534). This is also known as no_root_squash. + +* `access_type` - + (Optional) + Defines the access type for clients matching the `allowedClients` specification. + Possible values are: `READ_ONLY`, `READ_WRITE`, `READ_NONE`. + +* `nfsv3` - + (Optional) + Enable to apply the export rule to NFSV3 clients. + +* `nfsv4` - + (Optional) + Enable to apply the export rule to NFSV4.1 clients. + +* `kerberos5_read_only` - + (Optional) + If enabled (true) the rule defines a read only access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'authentication' kerberos security mode. + +* `kerberos5_read_write` - + (Optional) + If enabled (true) the rule defines read and write access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'authentication' kerberos security mode. The 'kerberos5ReadOnly' value is ignored if this is enabled. + +* `kerberos5i_read_only` - + (Optional) + If enabled (true) the rule defines a read only access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'integrity' kerberos security mode. + +* `kerberos5i_read_write` - + (Optional) + If enabled (true) the rule defines read and write access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'integrity' kerberos security mode. The 'kerberos5iReadOnly' value is ignored if this is enabled. + +* `kerberos5p_read_only` - + (Optional) + If enabled (true) the rule defines a read only access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'privacy' kerberos security mode. + +* `kerberos5p_read_write` - + (Optional) + If enabled (true) the rule defines read and write access for clients matching the 'allowedClients' specification. It enables nfs clients to mount using 'privacy' kerberos security mode. The 'kerberos5pReadOnly' value is ignored if this is enabled. + +The `snapshot_policy` block supports: + +* `enabled` - + (Optional) + Enables automated snapshot creation according to defined schedule. Default is false. + To disable automatic snapshot creation you have to remove the whole snapshot_policy block. + +* `hourly_schedule` - + (Optional) + Hourly schedule policy. + Structure is [documented below](#nested_hourly_schedule). + +* `daily_schedule` - + (Optional) + Daily schedule policy. + Structure is [documented below](#nested_daily_schedule). + +* `weekly_schedule` - + (Optional) + Weekly schedule policy. + Structure is [documented below](#nested_weekly_schedule). + +* `monthly_schedule` - + (Optional) + Monthly schedule policy. + Structure is [documented below](#nested_monthly_schedule). + + +The `hourly_schedule` block supports: + +* `snapshots_to_keep` - + (Required) + The maximum number of snapshots to keep for the hourly schedule. + +* `minute` - + (Optional) + Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0). + +The `daily_schedule` block supports: + +* `snapshots_to_keep` - + (Required) + The maximum number of snapshots to keep for the daily schedule. + +* `minute` - + (Optional) + Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0). + +* `hour` - + (Optional) + Set the hour to create the snapshot (0-23), defaults to midnight (0). + +The `weekly_schedule` block supports: + +* `snapshots_to_keep` - + (Required) + The maximum number of snapshots to keep for the weekly schedule. + +* `minute` - + (Optional) + Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0). + +* `hour` - + (Optional) + Set the hour to create the snapshot (0-23), defaults to midnight (0). + +* `day` - + (Optional) + Set the day or days of the week to make a snapshot. Accepts a comma separated days of the week. Defaults to 'Sunday'. + +The `monthly_schedule` block supports: + +* `snapshots_to_keep` - + (Required) + The maximum number of snapshots to keep for the monthly schedule + +* `minute` - + (Optional) + Set the minute of the hour to create the snapshot (0-59), defaults to the top of the hour (0). + +* `hour` - + (Optional) + Set the hour to create the snapshot (0-23), defaults to midnight (0). + +* `days_of_month` - + (Optional) + Set the day or days of the month to make a snapshot (1-31). Accepts a comma separated number of days. Defaults to '1'. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/volumes/{{name}}` + +* `psa_range` - + Name of the Private Service Access allocated range. Inherited from storage pool. + +* `network` - + VPC network name with format: `projects/{{project}}/global/networks/{{network}}`. Inherited from storage pool. + +* `service_level` - + Service level of the volume. Inherited from storage pool. + +* `used_gib` - + Used capacity of the volume (in GiB). This is computed periodically and it does not represent the realtime usage. + +* `ldap_enabled` - + Flag indicating if the volume is NFS LDAP enabled or not. Inherited from storage pool. + +* `active_directory` - + Reports the resource name of the Active Directory policy being used. Inherited from storage pool. + +* `kms_config` - + Reports the CMEK policy resurce name being used for volume encryption. Inherited from storage pool. + +* `encryption_type` - + Reports the data-at-rest encryption type of the volume. Inherited from storage pool. + +* `has_replication` - + Indicates whether the volume is part of a volume replication relationship. + +* `mount_options` - + Reports mount instructions for this volume. + Structure is [documented below](#nested_mount_options). + +* `terraform_labels` - + The combination of labels configured directly on the resource + and default labels configured on the provider. + +* `effective_labels` - + All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services. + + +The `mount_options` block contains: + +* `export` - + (Output) + Export path of the volume. + +* `export_full` - + (Output) + Full export path of the volume. + Format for NFS volumes: `:/` + Format for SMB volumes: `\\\\netbios_prefix-four_random_hex_letters.domain_name\\shareName` + +* `instructions` - + (Output) + Human-readable mount instructions. + +* `protocol` - + (Output) + Protocol to mount with. + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 20 minutes. +- `update` - Default is 20 minutes. +- `delete` - Default is 20 minutes. + +## Import + + +Volume can be imported using any of these accepted formats: + +* `projects/{{project}}/locations/{{location}}/volumes/{{name}}` +* `{{project}}/{{location}}/{{name}}` +* `{{location}}/{{name}}` + + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Volume using one of the formats above. For example: + +```tf +import { + id = "projects/{{project}}/locations/{{location}}/volumes/{{name}}" + to = google_netapp_volume.default +} +``` + +When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), Volume can be imported using one of the formats above. For example: + +``` +$ terraform import google_netapp_volume.default projects/{{project}}/locations/{{location}}/volumes/{{name}} +$ terraform import google_netapp_volume.default {{project}}/{{location}}/{{name}} +$ terraform import google_netapp_volume.default {{location}}/{{name}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).