blob: 6b23fad0ecb86a1679a4566a3eef58564f1cbe90 [file] [log] [blame]
// 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 filestore
import (
"context"
"fmt"
"log"
"net/http"
"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-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
"github.com/hashicorp/terraform-provider-google-beta/google-beta/verify"
)
func ResourceFilestoreInstance() *schema.Resource {
return &schema.Resource{
Create: resourceFilestoreInstanceCreate,
Read: resourceFilestoreInstanceRead,
Update: resourceFilestoreInstanceUpdate,
Delete: resourceFilestoreInstanceDelete,
Importer: &schema.ResourceImporter{
State: resourceFilestoreInstanceImport,
},
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(20 * time.Minute),
Update: schema.DefaultTimeout(20 * time.Minute),
Delete: schema.DefaultTimeout(20 * time.Minute),
},
SchemaVersion: 1,
StateUpgraders: []schema.StateUpgrader{
{
Type: resourceFilestoreInstanceResourceV0().CoreConfigSchema().ImpliedType(),
Upgrade: ResourceFilestoreInstanceUpgradeV0,
Version: 0,
},
},
CustomizeDiff: customdiff.All(
tpgresource.SetLabelsDiff,
tpgresource.DefaultProviderProject,
),
Schema: map[string]*schema.Schema{
"file_shares": {
Type: schema.TypeList,
Required: true,
Description: `File system shares on the instance. For this version, only a
single file share is supported.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"capacity_gb": {
Type: schema.TypeInt,
Required: true,
Description: `File share capacity in GiB. This must be at least 1024 GiB
for the standard tier, or 2560 GiB for the premium tier.`,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The name of the fileshare (16 characters or less)`,
},
"nfs_export_options": {
Type: schema.TypeList,
Optional: true,
Description: `Nfs Export Options. There is a limit of 10 export options per file share.`,
MaxItems: 10,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"access_mode": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidateEnum([]string{"READ_ONLY", "READ_WRITE", ""}),
Description: `Either READ_ONLY, for allowing only read requests on the exported directory,
or READ_WRITE, for allowing both read and write requests. The default is READ_WRITE. Default value: "READ_WRITE" Possible values: ["READ_ONLY", "READ_WRITE"]`,
Default: "READ_WRITE",
},
"anon_gid": {
Type: schema.TypeInt,
Optional: true,
Description: `An integer representing the anonymous group id with a default value of 65534.
Anon_gid may only be set with squashMode of ROOT_SQUASH. An error will be returned
if this field is specified for other squashMode settings.`,
},
"anon_uid": {
Type: schema.TypeInt,
Optional: true,
Description: `An integer representing the anonymous user id with a default value of 65534.
Anon_uid may only be set with squashMode of ROOT_SQUASH. An error will be returned
if this field is specified for other squashMode settings.`,
},
"ip_ranges": {
Type: schema.TypeList,
Optional: true,
Description: `List of either IPv4 addresses, or ranges in CIDR notation which may mount the file share.
Overlapping IP ranges are not allowed, both within and across NfsExportOptions. An error will be returned.
The limit is 64 IP ranges/addresses for each FileShareConfig among all NfsExportOptions.`,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"squash_mode": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidateEnum([]string{"NO_ROOT_SQUASH", "ROOT_SQUASH", ""}),
Description: `Either NO_ROOT_SQUASH, for allowing root access on the exported directory, or ROOT_SQUASH,
for not allowing root access. The default is NO_ROOT_SQUASH. Default value: "NO_ROOT_SQUASH" Possible values: ["NO_ROOT_SQUASH", "ROOT_SQUASH"]`,
Default: "NO_ROOT_SQUASH",
},
},
},
},
"source_backup": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: `The resource name of the backup, in the format
projects/{projectId}/locations/{locationId}/backups/{backupId},
that this file share has been restored from.`,
},
},
},
},
"name": {
Type: schema.TypeString,
Required: true,
Description: `The resource name of the instance.`,
},
"networks": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
Description: `VPC networks to which the instance is connected. For this version,
only a single network is supported.`,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"modes": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
Description: `IP versions for which the instance has
IP addresses assigned. Possible values: ["ADDRESS_MODE_UNSPECIFIED", "MODE_IPV4", "MODE_IPV6"]`,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: verify.ValidateEnum([]string{"ADDRESS_MODE_UNSPECIFIED", "MODE_IPV4", "MODE_IPV6"}),
},
},
"network": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName,
Description: `The name of the GCE VPC network to which the
instance is connected.`,
},
"connect_mode": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidateEnum([]string{"DIRECT_PEERING", "PRIVATE_SERVICE_ACCESS", ""}),
Description: `The network connect mode of the Filestore instance.
If not provided, the connect mode defaults to
DIRECT_PEERING. Default value: "DIRECT_PEERING" Possible values: ["DIRECT_PEERING", "PRIVATE_SERVICE_ACCESS"]`,
Default: "DIRECT_PEERING",
},
"reserved_ip_range": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
Description: `A /29 CIDR block that identifies the range of IP
addresses reserved for this instance.`,
},
"ip_addresses": {
Type: schema.TypeList,
Computed: true,
Description: `A list of IPv4 or IPv6 addresses.`,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
"tier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The service tier of the instance.
Possible values include: STANDARD, PREMIUM, BASIC_HDD, BASIC_SSD, HIGH_SCALE_SSD, ZONAL, REGIONAL and ENTERPRISE`,
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: `A description of the instance.`,
},
"kms_key_name": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Description: `KMS key name used for data encryption.`,
},
"labels": {
Type: schema.TypeMap,
Optional: true,
Description: `Resource labels to represent user-provided metadata.
**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},
},
"location": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
Description: `The name of the location of the instance. This can be a region for ENTERPRISE tier instances.`,
ExactlyOneOf: []string{},
},
"protocol": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: verify.ValidateEnum([]string{"NFS_V3", "NFS_V4_1", ""}),
Description: `Either NFSv3, for using NFS version 3 as file sharing protocol,
or NFSv4.1, for using NFS version 4.1 as file sharing protocol.
NFSv4.1 can be used with HIGH_SCALE_SSD, ZONAL, REGIONAL and ENTERPRISE.
The default is NFSv3. Default value: "NFS_V3" Possible values: ["NFS_V3", "NFS_V4_1"]`,
Default: "NFS_V3",
},
"zone": {
Type: schema.TypeString,
Computed: true,
Optional: true,
Deprecated: "`zone` is deprecated and will be removed in a future major release. Use `location` instead.",
ForceNew: true,
Description: `The name of the Filestore zone of the instance.`,
ExactlyOneOf: []string{},
},
"create_time": {
Type: schema.TypeString,
Computed: true,
Description: `Creation timestamp in RFC3339 text format.`,
},
"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},
},
"etag": {
Type: schema.TypeString,
Computed: true,
Description: `Server-specified ETag for the instance resource to prevent
simultaneous updates from overwriting each other.`,
},
"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},
},
"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
UseJSONNumber: true,
}
}
func resourceFilestoreInstanceCreate(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{})
descriptionProp, err := expandFilestoreInstanceDescription(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
}
tierProp, err := expandFilestoreInstanceTier(d.Get("tier"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("tier"); !tpgresource.IsEmptyValue(reflect.ValueOf(tierProp)) && (ok || !reflect.DeepEqual(v, tierProp)) {
obj["tier"] = tierProp
}
protocolProp, err := expandFilestoreInstanceProtocol(d.Get("protocol"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("protocol"); !tpgresource.IsEmptyValue(reflect.ValueOf(protocolProp)) && (ok || !reflect.DeepEqual(v, protocolProp)) {
obj["protocol"] = protocolProp
}
fileSharesProp, err := expandFilestoreInstanceFileShares(d.Get("file_shares"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("file_shares"); !tpgresource.IsEmptyValue(reflect.ValueOf(fileSharesProp)) && (ok || !reflect.DeepEqual(v, fileSharesProp)) {
obj["fileShares"] = fileSharesProp
}
networksProp, err := expandFilestoreInstanceNetworks(d.Get("networks"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("networks"); !tpgresource.IsEmptyValue(reflect.ValueOf(networksProp)) && (ok || !reflect.DeepEqual(v, networksProp)) {
obj["networks"] = networksProp
}
kmsKeyNameProp, err := expandFilestoreInstanceKmsKeyName(d.Get("kms_key_name"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("kms_key_name"); !tpgresource.IsEmptyValue(reflect.ValueOf(kmsKeyNameProp)) && (ok || !reflect.DeepEqual(v, kmsKeyNameProp)) {
obj["kmsKeyName"] = kmsKeyNameProp
}
labelsProp, err := expandFilestoreInstanceEffectiveLabels(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, "{{FilestoreBasePath}}projects/{{project}}/locations/{{location}}/instances?instanceId={{name}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Creating new Instance: %#v", obj)
billingProject := ""
project, err := tpgresource.GetProject(d, config)
if err != nil {
return fmt.Errorf("Error fetching project for Instance: %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
}
headers := make(http.Header)
if d.Get("location") == "" {
zone, err := tpgresource.GetZone(d, config)
if err != nil {
return err
}
err = d.Set("location", zone)
if err != nil {
return err
}
}
if strings.Contains(url, "locations//") {
// re-compute url now that location must be set
url, err = tpgresource.ReplaceVars(d, config, "{{FilestoreBasePath}}projects/{{project}}/locations/{{location}}/instances?instanceId={{name}}")
if err != nil {
return err
}
}
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),
Headers: headers,
ErrorAbortPredicates: []transport_tpg.RetryErrorPredicateFunc{transport_tpg.Is429QuotaError},
})
if err != nil {
return fmt.Errorf("Error creating Instance: %s", err)
}
// Store the ID now
id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/instances/{{name}}")
if err != nil {
return fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)
// Use the resource in the operation response to populate
// identity fields and d.Id() before read
var opRes map[string]interface{}
err = FilestoreOperationWaitTimeWithResponse(
config, res, &opRes, project, "Creating Instance", userAgent,
d.Timeout(schema.TimeoutCreate))
if err != nil {
// The resource didn't actually create
d.SetId("")
return fmt.Errorf("Error waiting to create Instance: %s", err)
}
// This may have caused the ID to update - update it if so.
id, err = tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/instances/{{name}}")
if err != nil {
return fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)
log.Printf("[DEBUG] Finished creating Instance %q: %#v", d.Id(), res)
return resourceFilestoreInstanceRead(d, meta)
}
func resourceFilestoreInstanceRead(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, "{{FilestoreBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}")
if err != nil {
return err
}
billingProject := ""
project, err := tpgresource.GetProject(d, config)
if err != nil {
return fmt.Errorf("Error fetching project for Instance: %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
}
headers := make(http.Header)
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
Config: config,
Method: "GET",
Project: billingProject,
RawURL: url,
UserAgent: userAgent,
Headers: headers,
ErrorAbortPredicates: []transport_tpg.RetryErrorPredicateFunc{transport_tpg.Is429QuotaError},
})
if err != nil {
return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("FilestoreInstance %q", d.Id()))
}
if err := d.Set("project", project); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("description", flattenFilestoreInstanceDescription(res["description"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("create_time", flattenFilestoreInstanceCreateTime(res["createTime"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("tier", flattenFilestoreInstanceTier(res["tier"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("protocol", flattenFilestoreInstanceProtocol(res["protocol"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("labels", flattenFilestoreInstanceLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("file_shares", flattenFilestoreInstanceFileShares(res["fileShares"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("networks", flattenFilestoreInstanceNetworks(res["networks"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("etag", flattenFilestoreInstanceEtag(res["etag"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("kms_key_name", flattenFilestoreInstanceKmsKeyName(res["kmsKeyName"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("terraform_labels", flattenFilestoreInstanceTerraformLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
if err := d.Set("effective_labels", flattenFilestoreInstanceEffectiveLabels(res["labels"], d, config)); err != nil {
return fmt.Errorf("Error reading Instance: %s", err)
}
return nil
}
func resourceFilestoreInstanceUpdate(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 Instance: %s", err)
}
billingProject = project
obj := make(map[string]interface{})
descriptionProp, err := expandFilestoreInstanceDescription(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
}
fileSharesProp, err := expandFilestoreInstanceFileShares(d.Get("file_shares"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("file_shares"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, fileSharesProp)) {
obj["fileShares"] = fileSharesProp
}
labelsProp, err := expandFilestoreInstanceEffectiveLabels(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, "{{FilestoreBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}")
if err != nil {
return err
}
log.Printf("[DEBUG] Updating Instance %q: %#v", d.Id(), obj)
headers := make(http.Header)
updateMask := []string{}
if d.HasChange("description") {
updateMask = append(updateMask, "description")
}
if d.HasChange("file_shares") {
updateMask = append(updateMask, "fileShares")
}
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),
Headers: headers,
ErrorAbortPredicates: []transport_tpg.RetryErrorPredicateFunc{transport_tpg.Is429QuotaError},
})
if err != nil {
return fmt.Errorf("Error updating Instance %q: %s", d.Id(), err)
} else {
log.Printf("[DEBUG] Finished updating Instance %q: %#v", d.Id(), res)
}
err = FilestoreOperationWaitTime(
config, res, project, "Updating Instance", userAgent,
d.Timeout(schema.TimeoutUpdate))
if err != nil {
return err
}
}
return resourceFilestoreInstanceRead(d, meta)
}
func resourceFilestoreInstanceDelete(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 Instance: %s", err)
}
billingProject = project
url, err := tpgresource.ReplaceVars(d, config, "{{FilestoreBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}")
if err != nil {
return err
}
var obj map[string]interface{}
// err == nil indicates that the billing_project value was found
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
billingProject = bp
}
headers := make(http.Header)
log.Printf("[DEBUG] Deleting Instance %q", d.Id())
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),
Headers: headers,
ErrorAbortPredicates: []transport_tpg.RetryErrorPredicateFunc{transport_tpg.Is429QuotaError},
})
if err != nil {
return transport_tpg.HandleNotFoundError(err, d, "Instance")
}
err = FilestoreOperationWaitTime(
config, res, project, "Deleting Instance", userAgent,
d.Timeout(schema.TimeoutDelete))
if err != nil {
return err
}
log.Printf("[DEBUG] Finished deleting Instance %q: %#v", d.Id(), res)
return nil
}
func resourceFilestoreInstanceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
config := meta.(*transport_tpg.Config)
if err := tpgresource.ParseImportId([]string{
"^projects/(?P<project>[^/]+)/locations/(?P<location>[^/]+)/instances/(?P<name>[^/]+)$",
"^(?P<project>[^/]+)/(?P<location>[^/]+)/(?P<name>[^/]+)$",
"^(?P<location>[^/]+)/(?P<name>[^/]+)$",
}, d, config); err != nil {
return nil, err
}
// Replace import id for the resource id
id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/instances/{{name}}")
if err != nil {
return nil, fmt.Errorf("Error constructing id: %s", err)
}
d.SetId(id)
return []*schema.ResourceData{d}, nil
}
func flattenFilestoreInstanceDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceTier(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceProtocol(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil || tpgresource.IsEmptyValue(reflect.ValueOf(v)) {
return "NFS_V3"
}
return v
}
func flattenFilestoreInstanceLabels(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 flattenFilestoreInstanceFileShares(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{}{
"name": flattenFilestoreInstanceFileSharesName(original["name"], d, config),
"capacity_gb": flattenFilestoreInstanceFileSharesCapacityGb(original["capacityGb"], d, config),
"source_backup": flattenFilestoreInstanceFileSharesSourceBackup(original["sourceBackup"], d, config),
"nfs_export_options": flattenFilestoreInstanceFileSharesNfsExportOptions(original["nfsExportOptions"], d, config),
})
}
return transformed
}
func flattenFilestoreInstanceFileSharesName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceFileSharesCapacityGb(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 flattenFilestoreInstanceFileSharesSourceBackup(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceFileSharesNfsExportOptions(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{}{
"ip_ranges": flattenFilestoreInstanceFileSharesNfsExportOptionsIpRanges(original["ipRanges"], d, config),
"access_mode": flattenFilestoreInstanceFileSharesNfsExportOptionsAccessMode(original["accessMode"], d, config),
"squash_mode": flattenFilestoreInstanceFileSharesNfsExportOptionsSquashMode(original["squashMode"], d, config),
"anon_uid": flattenFilestoreInstanceFileSharesNfsExportOptionsAnonUid(original["anonUid"], d, config),
"anon_gid": flattenFilestoreInstanceFileSharesNfsExportOptionsAnonGid(original["anonGid"], d, config),
})
}
return transformed
}
func flattenFilestoreInstanceFileSharesNfsExportOptionsIpRanges(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceFileSharesNfsExportOptionsAccessMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceFileSharesNfsExportOptionsSquashMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceFileSharesNfsExportOptionsAnonUid(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 flattenFilestoreInstanceFileSharesNfsExportOptionsAnonGid(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 flattenFilestoreInstanceNetworks(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{}{
"network": flattenFilestoreInstanceNetworksNetwork(original["network"], d, config),
"modes": flattenFilestoreInstanceNetworksModes(original["modes"], d, config),
"reserved_ip_range": flattenFilestoreInstanceNetworksReservedIpRange(original["reservedIpRange"], d, config),
"ip_addresses": flattenFilestoreInstanceNetworksIpAddresses(original["ipAddresses"], d, config),
"connect_mode": flattenFilestoreInstanceNetworksConnectMode(original["connectMode"], d, config),
})
}
return transformed
}
func flattenFilestoreInstanceNetworksNetwork(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceNetworksModes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceNetworksReservedIpRange(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return d.Get("networks.0.reserved_ip_range")
}
func flattenFilestoreInstanceNetworksIpAddresses(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceNetworksConnectMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil || tpgresource.IsEmptyValue(reflect.ValueOf(v)) {
return "DIRECT_PEERING"
}
return v
}
func flattenFilestoreInstanceEtag(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceKmsKeyName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func flattenFilestoreInstanceTerraformLabels(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 flattenFilestoreInstanceEffectiveLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}
func expandFilestoreInstanceDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceTier(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceProtocol(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileShares(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{})
transformedName, err := expandFilestoreInstanceFileSharesName(original["name"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["name"] = transformedName
}
transformedCapacityGb, err := expandFilestoreInstanceFileSharesCapacityGb(original["capacity_gb"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedCapacityGb); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["capacityGb"] = transformedCapacityGb
}
transformedSourceBackup, err := expandFilestoreInstanceFileSharesSourceBackup(original["source_backup"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedSourceBackup); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["sourceBackup"] = transformedSourceBackup
}
transformedNfsExportOptions, err := expandFilestoreInstanceFileSharesNfsExportOptions(original["nfs_export_options"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedNfsExportOptions); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["nfsExportOptions"] = transformedNfsExportOptions
}
req = append(req, transformed)
}
return req, nil
}
func expandFilestoreInstanceFileSharesName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileSharesCapacityGb(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileSharesSourceBackup(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileSharesNfsExportOptions(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{})
transformedIpRanges, err := expandFilestoreInstanceFileSharesNfsExportOptionsIpRanges(original["ip_ranges"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedIpRanges); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["ipRanges"] = transformedIpRanges
}
transformedAccessMode, err := expandFilestoreInstanceFileSharesNfsExportOptionsAccessMode(original["access_mode"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAccessMode); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["accessMode"] = transformedAccessMode
}
transformedSquashMode, err := expandFilestoreInstanceFileSharesNfsExportOptionsSquashMode(original["squash_mode"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedSquashMode); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["squashMode"] = transformedSquashMode
}
transformedAnonUid, err := expandFilestoreInstanceFileSharesNfsExportOptionsAnonUid(original["anon_uid"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAnonUid); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["anonUid"] = transformedAnonUid
}
transformedAnonGid, err := expandFilestoreInstanceFileSharesNfsExportOptionsAnonGid(original["anon_gid"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAnonGid); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["anonGid"] = transformedAnonGid
}
req = append(req, transformed)
}
return req, nil
}
func expandFilestoreInstanceFileSharesNfsExportOptionsIpRanges(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileSharesNfsExportOptionsAccessMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileSharesNfsExportOptionsSquashMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileSharesNfsExportOptionsAnonUid(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceFileSharesNfsExportOptionsAnonGid(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceNetworks(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{})
transformedNetwork, err := expandFilestoreInstanceNetworksNetwork(original["network"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedNetwork); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["network"] = transformedNetwork
}
transformedModes, err := expandFilestoreInstanceNetworksModes(original["modes"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedModes); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["modes"] = transformedModes
}
transformedReservedIpRange, err := expandFilestoreInstanceNetworksReservedIpRange(original["reserved_ip_range"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedReservedIpRange); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["reservedIpRange"] = transformedReservedIpRange
}
transformedIpAddresses, err := expandFilestoreInstanceNetworksIpAddresses(original["ip_addresses"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedIpAddresses); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["ipAddresses"] = transformedIpAddresses
}
transformedConnectMode, err := expandFilestoreInstanceNetworksConnectMode(original["connect_mode"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedConnectMode); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["connectMode"] = transformedConnectMode
}
req = append(req, transformed)
}
return req, nil
}
func expandFilestoreInstanceNetworksNetwork(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceNetworksModes(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceNetworksReservedIpRange(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceNetworksIpAddresses(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceNetworksConnectMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceKmsKeyName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
func expandFilestoreInstanceEffectiveLabels(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) {
if v == nil {
return map[string]string{}, nil
}
m := make(map[string]string)
for k, val := range v.(map[string]interface{}) {
m[k] = val.(string)
}
return m, nil
}
func resourceFilestoreInstanceResourceV0() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"file_shares": {
Type: schema.TypeList,
Required: true,
Description: `File system shares on the instance. For this version, only a
single file share is supported.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"capacity_gb": {
Type: schema.TypeInt,
Required: true,
Description: `File share capacity in GiB. This must be at least 1024 GiB
for the standard tier, or 2560 GiB for the premium tier.`,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The name of the fileshare (16 characters or less)`,
},
"nfs_export_options": {
Type: schema.TypeList,
Optional: true,
Description: `Nfs Export Options. There is a limit of 10 export options per file share.`,
MaxItems: 10,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"access_mode": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"READ_ONLY", "READ_WRITE", ""}, false),
Description: `Either READ_ONLY, for allowing only read requests on the exported directory,
or READ_WRITE, for allowing both read and write requests. The default is READ_WRITE. Default value: "READ_WRITE" Possible values: ["READ_ONLY", "READ_WRITE"]`,
Default: "READ_WRITE",
},
"anon_gid": {
Type: schema.TypeInt,
Optional: true,
Description: `An integer representing the anonymous group id with a default value of 65534.
Anon_gid may only be set with squashMode of ROOT_SQUASH. An error will be returned
if this field is specified for other squashMode settings.`,
},
"anon_uid": {
Type: schema.TypeInt,
Optional: true,
Description: `An integer representing the anonymous user id with a default value of 65534.
Anon_uid may only be set with squashMode of ROOT_SQUASH. An error will be returned
if this field is specified for other squashMode settings.`,
},
"ip_ranges": {
Type: schema.TypeList,
Optional: true,
Description: `List of either IPv4 addresses, or ranges in CIDR notation which may mount the file share.
Overlapping IP ranges are not allowed, both within and across NfsExportOptions. An error will be returned.
The limit is 64 IP ranges/addresses for each FileShareConfig among all NfsExportOptions.`,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"squash_mode": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringInSlice([]string{"NO_ROOT_SQUASH", "ROOT_SQUASH", ""}, false),
Description: `Either NO_ROOT_SQUASH, for allowing root access on the exported directory, or ROOT_SQUASH,
for not allowing root access. The default is NO_ROOT_SQUASH. Default value: "NO_ROOT_SQUASH" Possible values: ["NO_ROOT_SQUASH", "ROOT_SQUASH"]`,
Default: "NO_ROOT_SQUASH",
},
},
},
},
},
},
},
"name": {
Type: schema.TypeString,
Required: true,
Description: `The resource name of the instance.`,
},
"networks": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
Description: `VPC networks to which the instance is connected. For this version,
only a single network is supported.`,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"modes": {
Type: schema.TypeList,
Required: true,
ForceNew: true,
Description: `IP versions for which the instance has
IP addresses assigned. Possible values: ["ADDRESS_MODE_UNSPECIFIED", "MODE_IPV4", "MODE_IPV6"]`,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{"ADDRESS_MODE_UNSPECIFIED", "MODE_IPV4", "MODE_IPV6"}, false),
},
},
"network": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The name of the GCE VPC network to which the
instance is connected.`,
},
"connect_mode": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"DIRECT_PEERING", "PRIVATE_SERVICE_ACCESS", ""}, false),
Description: `The network connect mode of the Filestore instance.
If not provided, the connect mode defaults to
DIRECT_PEERING. Default value: "DIRECT_PEERING" Possible values: ["DIRECT_PEERING", "PRIVATE_SERVICE_ACCESS"]`,
Default: "DIRECT_PEERING",
},
"reserved_ip_range": {
Type: schema.TypeString,
Computed: true,
Optional: true,
Description: `A /29 CIDR block that identifies the range of IP
addresses reserved for this instance.`,
},
"ip_addresses": {
Type: schema.TypeList,
Computed: true,
Description: `A list of IPv4 or IPv6 addresses.`,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
"tier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"TIER_UNSPECIFIED", "STANDARD", "PREMIUM", "BASIC_HDD", "BASIC_SSD", "HIGH_SCALE_SSD", "ZONAL"}, false),
Description: `The service tier of the instance. Possible values: ["TIER_UNSPECIFIED", "STANDARD", "PREMIUM", "BASIC_HDD", "BASIC_SSD", "HIGH_SCALE_SSD", "ZONAL"]`,
},
"zone": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: `The name of the Filestore zone of the instance.`,
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: `A description of the instance.`,
},
"labels": {
Type: schema.TypeMap,
Optional: true,
Description: `Resource labels to represent user-provided metadata.`,
Elem: &schema.Schema{Type: schema.TypeString},
},
"create_time": {
Type: schema.TypeString,
Computed: true,
Description: `Creation timestamp in RFC3339 text format.`,
},
"etag": {
Type: schema.TypeString,
Computed: true,
Description: `Server-specified ETag for the instance resource to prevent
simultaneous updates from overwriting each other.`,
},
"project": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
},
}
}
func ResourceFilestoreInstanceUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
log.Printf("[DEBUG] Attributes before migration: %#v", rawState)
rawState["location"] = rawState["zone"]
log.Printf("[DEBUG] Attributes after migration: %#v", rawState)
return rawState, nil
}