diff --git a/.changelog/6718.txt b/.changelog/6718.txt new file mode 100644 index 00000000000..8117906275d --- /dev/null +++ b/.changelog/6718.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +vpcaccess - promoted `machine_type`, `min_instances`, `max_instances`, and `subnet` in `google_vpc_access_connector` to GA +``` diff --git a/google/resource_vpc_access_connector.go b/google/resource_vpc_access_connector.go index b537161ab49..0030940c205 100644 --- a/google/resource_vpc_access_connector.go +++ b/google/resource_vpc_access_connector.go @@ -53,6 +53,20 @@ func resourceVPCAccessConnector() *schema.Resource { Description: `The range of internal addresses that follows RFC 4632 notation. Example: '10.132.0.0/28'.`, RequiredWith: []string{"network"}, }, + "machine_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Machine type of VM Instance underlying connector. Default is e2-micro`, + Default: "e2-micro", + }, + "max_instances": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + ForceNew: true, + Description: `Maximum value of instances in autoscaling group underlying the connector.`, + }, "max_throughput": { Type: schema.TypeInt, Optional: true, @@ -61,6 +75,13 @@ func resourceVPCAccessConnector() *schema.Resource { Description: `Maximum throughput of the connector in Mbps, must be greater than 'min_throughput'. Default is 300.`, Default: 300, }, + "min_instances": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + ForceNew: true, + Description: `Minimum value of instances in autoscaling group underlying the connector.`, + }, "min_throughput": { Type: schema.TypeInt, Optional: true, @@ -76,7 +97,7 @@ func resourceVPCAccessConnector() *schema.Resource { ForceNew: true, DiffSuppressFunc: compareResourceNames, Description: `Name or self_link of the VPC network. Required if 'ip_cidr_range' is set.`, - ExactlyOneOf: []string{"network"}, + ExactlyOneOf: []string{"network", "subnet.0.name"}, }, "region": { Type: schema.TypeString, @@ -85,6 +106,32 @@ func resourceVPCAccessConnector() *schema.Resource { ForceNew: true, Description: `Region where the VPC Access connector resides. If it is not provided, the provider region is used.`, }, + "subnet": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `The subnet in which to house the connector`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `Subnet name (relative, not fully qualified). E.g. if the full subnet selfLink is +https://compute.googleapis.com/compute/v1/projects/{project}/regions/{region}/subnetworks/{subnetName} the correct input for this field would be {subnetName}"`, + ExactlyOneOf: []string{"network", "subnet.0.name"}, + }, + "project_id": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + Description: `Project in which the subnet exists. If not set, this project is assumed to be the project for which the connector create request was issued.`, + }, + }, + }, + }, "self_link": { Type: schema.TypeString, Computed: true, @@ -132,18 +179,42 @@ func resourceVPCAccessConnectorCreate(d *schema.ResourceData, meta interface{}) } else if v, ok := d.GetOkExists("ip_cidr_range"); !isEmptyValue(reflect.ValueOf(ipCidrRangeProp)) && (ok || !reflect.DeepEqual(v, ipCidrRangeProp)) { obj["ipCidrRange"] = ipCidrRangeProp } + machineTypeProp, err := expandVPCAccessConnectorMachineType(d.Get("machine_type"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("machine_type"); !isEmptyValue(reflect.ValueOf(machineTypeProp)) && (ok || !reflect.DeepEqual(v, machineTypeProp)) { + obj["machineType"] = machineTypeProp + } minThroughputProp, err := expandVPCAccessConnectorMinThroughput(d.Get("min_throughput"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("min_throughput"); !isEmptyValue(reflect.ValueOf(minThroughputProp)) && (ok || !reflect.DeepEqual(v, minThroughputProp)) { obj["minThroughput"] = minThroughputProp } + minInstancesProp, err := expandVPCAccessConnectorMinInstances(d.Get("min_instances"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("min_instances"); !isEmptyValue(reflect.ValueOf(minInstancesProp)) && (ok || !reflect.DeepEqual(v, minInstancesProp)) { + obj["minInstances"] = minInstancesProp + } + maxInstancesProp, err := expandVPCAccessConnectorMaxInstances(d.Get("max_instances"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("max_instances"); !isEmptyValue(reflect.ValueOf(maxInstancesProp)) && (ok || !reflect.DeepEqual(v, maxInstancesProp)) { + obj["maxInstances"] = maxInstancesProp + } maxThroughputProp, err := expandVPCAccessConnectorMaxThroughput(d.Get("max_throughput"), d, config) if err != nil { return err } else if v, ok := d.GetOkExists("max_throughput"); !isEmptyValue(reflect.ValueOf(maxThroughputProp)) && (ok || !reflect.DeepEqual(v, maxThroughputProp)) { obj["maxThroughput"] = maxThroughputProp } + subnetProp, err := expandVPCAccessConnectorSubnet(d.Get("subnet"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("subnet"); !isEmptyValue(reflect.ValueOf(subnetProp)) && (ok || !reflect.DeepEqual(v, subnetProp)) { + obj["subnet"] = subnetProp + } obj, err = resourceVPCAccessConnectorEncoder(d, meta, obj) if err != nil { @@ -281,12 +352,24 @@ func resourceVPCAccessConnectorRead(d *schema.ResourceData, meta interface{}) er if err := d.Set("state", flattenVPCAccessConnectorState(res["state"], d, config)); err != nil { return fmt.Errorf("Error reading Connector: %s", err) } + if err := d.Set("machine_type", flattenVPCAccessConnectorMachineType(res["machineType"], d, config)); err != nil { + return fmt.Errorf("Error reading Connector: %s", err) + } if err := d.Set("min_throughput", flattenVPCAccessConnectorMinThroughput(res["minThroughput"], d, config)); err != nil { return fmt.Errorf("Error reading Connector: %s", err) } + if err := d.Set("min_instances", flattenVPCAccessConnectorMinInstances(res["minInstances"], d, config)); err != nil { + return fmt.Errorf("Error reading Connector: %s", err) + } + if err := d.Set("max_instances", flattenVPCAccessConnectorMaxInstances(res["maxInstances"], d, config)); err != nil { + return fmt.Errorf("Error reading Connector: %s", err) + } if err := d.Set("max_throughput", flattenVPCAccessConnectorMaxThroughput(res["maxThroughput"], d, config)); err != nil { return fmt.Errorf("Error reading Connector: %s", err) } + if err := d.Set("subnet", flattenVPCAccessConnectorSubnet(res["subnet"], d, config)); err != nil { + return fmt.Errorf("Error reading Connector: %s", err) + } return nil } @@ -379,6 +462,10 @@ func flattenVPCAccessConnectorState(v interface{}, d *schema.ResourceData, confi return v } +func flattenVPCAccessConnectorMachineType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenVPCAccessConnectorMinThroughput(v interface{}, d *schema.ResourceData, config *Config) interface{} { // Handles the string fixed64 format if strVal, ok := v.(string); ok { @@ -396,6 +483,40 @@ func flattenVPCAccessConnectorMinThroughput(v interface{}, d *schema.ResourceDat return v // let terraform core handle it otherwise } +func flattenVPCAccessConnectorMinInstances(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := 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 flattenVPCAccessConnectorMaxInstances(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := 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 flattenVPCAccessConnectorMaxThroughput(v interface{}, d *schema.ResourceData, config *Config) interface{} { // Handles the string fixed64 format if strVal, ok := v.(string); ok { @@ -413,6 +534,29 @@ func flattenVPCAccessConnectorMaxThroughput(v interface{}, d *schema.ResourceDat return v // let terraform core handle it otherwise } +func flattenVPCAccessConnectorSubnet(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenVPCAccessConnectorSubnetName(original["name"], d, config) + transformed["project_id"] = + flattenVPCAccessConnectorSubnetProjectId(original["projectId"], d, config) + return []interface{}{transformed} +} +func flattenVPCAccessConnectorSubnetName(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenVPCAccessConnectorSubnetProjectId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func expandVPCAccessConnectorName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -425,14 +569,60 @@ func expandVPCAccessConnectorIpCidrRange(v interface{}, d TerraformResourceData, return v, nil } +func expandVPCAccessConnectorMachineType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandVPCAccessConnectorMinThroughput(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } +func expandVPCAccessConnectorMinInstances(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandVPCAccessConnectorMaxInstances(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandVPCAccessConnectorMaxThroughput(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } +func expandVPCAccessConnectorSubnet(v interface{}, d TerraformResourceData, config *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{}) + + transformedName, err := expandVPCAccessConnectorSubnetName(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !isEmptyValue(val) { + transformed["name"] = transformedName + } + + transformedProjectId, err := expandVPCAccessConnectorSubnetProjectId(original["project_id"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProjectId); val.IsValid() && !isEmptyValue(val) { + transformed["projectId"] = transformedProjectId + } + + return transformed, nil +} + +func expandVPCAccessConnectorSubnetName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandVPCAccessConnectorSubnetProjectId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func resourceVPCAccessConnectorEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { delete(obj, "name") return obj, nil diff --git a/google/resource_vpc_access_connector_generated_test.go b/google/resource_vpc_access_connector_generated_test.go index 99943c2d919..cb440e8b4b5 100644 --- a/google/resource_vpc_access_connector_generated_test.go +++ b/google/resource_vpc_access_connector_generated_test.go @@ -58,6 +58,55 @@ resource "google_vpc_access_connector" "connector" { `, context) } +func TestAccVPCAccessConnector_vpcAccessConnectorSharedVPCExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVPCAccessConnectorDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccVPCAccessConnector_vpcAccessConnectorSharedVPCExample(context), + }, + { + ResourceName: "google_vpc_access_connector.connector", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"self_link", "region"}, + }, + }, + }) +} + +func testAccVPCAccessConnector_vpcAccessConnectorSharedVPCExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_vpc_access_connector" "connector" { + name = "tf-test-vpc-con%{random_suffix}" + subnet { + name = google_compute_subnetwork.custom_test.name + } + machine_type = "e2-standard-4" +} + +resource "google_compute_subnetwork" "custom_test" { + name = "tf-test-vpc-con%{random_suffix}" + ip_cidr_range = "10.2.0.0/28" + region = "us-central1" + network = google_compute_network.custom_test.id +} + +resource "google_compute_network" "custom_test" { + name = "tf-test-vpc-con%{random_suffix}" + auto_create_subnetworks = false +} +`, context) +} + func testAccCheckVPCAccessConnectorDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { for name, rs := range s.RootModule().Resources { diff --git a/google/resource_vpc_access_connector_test.go b/google/resource_vpc_access_connector_test.go index 71664db3c87..938b5f792f1 100644 --- a/google/resource_vpc_access_connector_test.go +++ b/google/resource_vpc_access_connector_test.go @@ -1 +1,58 @@ package google + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccVPCAccessConnector_vpcAccessConnectorThroughput(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVPCAccessConnectorDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccVPCAccessConnector_vpcAccessConnectorThroughput(context), + }, + { + ResourceName: "google_vpc_access_connector.connector", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccVPCAccessConnector_vpcAccessConnectorThroughput(context map[string]interface{}) string { + return Nprintf(` +resource "google_vpc_access_connector" "connector" { + name = "tf-test-vpc-con%{random_suffix}" + subnet { + name = google_compute_subnetwork.custom_test.name + } + machine_type = "e2-standard-4" + min_instances = 2 + max_instances = 3 + region = "us-central1" +} + +resource "google_compute_subnetwork" "custom_test" { + name = "tf-test-vpc-con%{random_suffix}" + ip_cidr_range = "10.2.0.0/28" + region = "us-central1" + network = google_compute_network.custom_test.id +} + +resource "google_compute_network" "custom_test" { + name = "tf-test-vpc-con%{random_suffix}" + auto_create_subnetworks = false +} +`, context) +} diff --git a/website/docs/r/vpc_access_connector.html.markdown b/website/docs/r/vpc_access_connector.html.markdown index da97840ae67..fd0f1e578e6 100644 --- a/website/docs/r/vpc_access_connector.html.markdown +++ b/website/docs/r/vpc_access_connector.html.markdown @@ -54,7 +54,6 @@ resource "google_vpc_access_connector" "connector" { ```hcl resource "google_vpc_access_connector" "connector" { - provider = google-beta name = "vpc-con" subnet { name = google_compute_subnetwork.custom_test.name @@ -63,7 +62,6 @@ resource "google_vpc_access_connector" "connector" { } resource "google_compute_subnetwork" "custom_test" { - provider = google-beta name = "vpc-con" ip_cidr_range = "10.2.0.0/28" region = "us-central1" @@ -71,7 +69,6 @@ resource "google_compute_subnetwork" "custom_test" { } resource "google_compute_network" "custom_test" { - provider = google-beta name = "vpc-con" auto_create_subnetworks = false } @@ -99,7 +96,7 @@ The following arguments are supported: The range of internal addresses that follows RFC 4632 notation. Example: `10.132.0.0/28`. * `machine_type` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) Machine type of VM Instance underlying connector. Default is e2-micro * `min_throughput` - @@ -107,11 +104,11 @@ The following arguments are supported: Minimum throughput of the connector in Mbps. Default and min is 200. * `min_instances` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) Minimum value of instances in autoscaling group underlying the connector. * `max_instances` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) Maximum value of instances in autoscaling group underlying the connector. * `max_throughput` - @@ -119,7 +116,7 @@ The following arguments are supported: Maximum throughput of the connector in Mbps, must be greater than `min_throughput`. Default is 300. * `subnet` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) The subnet in which to house the connector Structure is [documented below](#nested_subnet). @@ -134,12 +131,12 @@ The following arguments are supported: The `subnet` block supports: * `name` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) Subnet name (relative, not fully qualified). E.g. if the full subnet selfLink is https://compute.googleapis.com/compute/v1/projects/{project}/regions/{region}/subnetworks/{subnetName} the correct input for this field would be {subnetName}" * `project_id` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) Project in which the subnet exists. If not set, this project is assumed to be the project for which the connector create request was issued. ## Attributes Reference