From 5eaa9ba6d92a41cb0c0824c38dedc33ebaac0833 Mon Sep 17 00:00:00 2001 From: Sam Levenick Date: Fri, 1 Nov 2019 20:28:48 +0000 Subject: [PATCH] Subnet logconfig prepare for 3.0.0 Signed-off-by: Modular Magician --- google/resource_compute_subnetwork.go | 134 +++++++++++- ...ource_compute_subnetwork_generated_test.go | 46 +++++ google/resource_compute_subnetwork_test.go | 190 +++++++++++++++++- .../docs/r/compute_subnetwork.html.markdown | 48 +++-- 4 files changed, 394 insertions(+), 24 deletions(-) diff --git a/google/resource_compute_subnetwork.go b/google/resource_compute_subnetwork.go index 2d49d38163d..2d8e155139b 100644 --- a/google/resource_compute_subnetwork.go +++ b/google/resource_compute_subnetwork.go @@ -25,6 +25,7 @@ import ( "github.com/apparentlymart/go-cidr/cidr" "github.com/hashicorp/terraform-plugin-sdk/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" "google.golang.org/api/compute/v1" ) @@ -101,8 +102,37 @@ func resourceComputeSubnetwork() *schema.Resource { ForceNew: true, }, "enable_flow_logs": { - Type: schema.TypeBool, + Type: schema.TypeBool, + Computed: true, + Optional: true, + Deprecated: "This field is being removed in favor of log_config. If log_config is present, flow logs are enabled.", + }, + "log_config": { + Type: schema.TypeList, + Computed: true, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "aggregation_interval": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"INTERVAL_5_SEC", "INTERVAL_30_SEC", "INTERVAL_1_MIN", "INTERVAL_5_MIN", "INTERVAL_10_MIN", "INTERVAL_15_MIN", ""}, false), + Default: "INTERVAL_5_SEC", + }, + "flow_sampling": { + Type: schema.TypeFloat, + Optional: true, + Default: 0.5, + }, + "metadata": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"EXCLUDE_ALL_METADATA", "INCLUDE_ALL_METADATA", ""}, false), + Default: "INCLUDE_ALL_METADATA", + }, + }, + }, }, "private_ip_google_access": { Type: schema.TypeBool, @@ -261,6 +291,12 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e } else if v, ok := d.GetOkExists("region"); !isEmptyValue(reflect.ValueOf(regionProp)) && (ok || !reflect.DeepEqual(v, regionProp)) { obj["region"] = regionProp } + logConfigProp, err := expandComputeSubnetworkLogConfig(d.Get("log_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("log_config"); !isEmptyValue(reflect.ValueOf(logConfigProp)) && (ok || !reflect.DeepEqual(v, logConfigProp)) { + obj["logConfig"] = logConfigProp + } url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/subnetworks") if err != nil { @@ -359,6 +395,9 @@ func resourceComputeSubnetworkRead(d *schema.ResourceData, meta interface{}) err if err := d.Set("region", flattenComputeSubnetworkRegion(res["region"], d)); err != nil { return fmt.Errorf("Error reading Subnetwork: %s", err) } + if err := d.Set("log_config", flattenComputeSubnetworkLogConfig(res["logConfig"], d)); err != nil { + return fmt.Errorf("Error reading Subnetwork: %s", err) + } if err := d.Set("self_link", ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { return fmt.Errorf("Error reading Subnetwork: %s", err) } @@ -548,6 +587,57 @@ func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) e d.SetPartial("private_ip_google_access") } + if d.HasChange("log_config") { + obj := make(map[string]interface{}) + + getUrl, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/subnetworks/{{name}}") + if err != nil { + return err + } + + project, err := getProject(d, config) + if err != nil { + return err + } + getRes, err := sendRequest(config, "GET", project, getUrl, nil) + if err != nil { + return handleNotFoundError(err, d, fmt.Sprintf("ComputeSubnetwork %q", d.Id())) + } + + obj["fingerprint"] = getRes["fingerprint"] + + logConfigProp, err := expandComputeSubnetworkLogConfig(d.Get("log_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("log_config"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, logConfigProp)) { + obj["logConfig"] = logConfigProp + } + + url, err := replaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/subnetworks/{{name}}") + if err != nil { + return err + } + res, err := sendRequestWithTimeout(config, "PATCH", project, url, obj, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return fmt.Errorf("Error updating Subnetwork %q: %s", d.Id(), err) + } + + op := &compute.Operation{} + err = Convert(res, op) + if err != nil { + return err + } + + err = computeOperationWaitTime( + config.clientCompute, op, project, "Updating Subnetwork", + int(d.Timeout(schema.TimeoutUpdate).Minutes())) + + if err != nil { + return err + } + + d.SetPartial("log_config") + } d.Partial(false) @@ -687,6 +777,27 @@ func flattenComputeSubnetworkRegion(v interface{}, d *schema.ResourceData) inter return NameFromSelfLinkStateFunc(v) } +func flattenComputeSubnetworkLogConfig(v interface{}, d *schema.ResourceData) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + + v, ok := original["enable"] + if ok && !v.(bool) { + return nil + } + + transformed := make(map[string]interface{}) + transformed["flow_sampling"] = original["flowSampling"] + transformed["aggregation_interval"] = original["aggregationInterval"] + transformed["metadata"] = original["metadata"] + return []interface{}{transformed} +} + func expandComputeSubnetworkDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { return v, nil } @@ -763,3 +874,24 @@ func expandComputeSubnetworkRegion(v interface{}, d TerraformResourceData, confi } return f.RelativeLink(), nil } + +func expandComputeSubnetworkLogConfig(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{}) + + v, ok := d.GetOkExists("enable_flow_logs") + + transformed := make(map[string]interface{}) + if !ok || v.(bool) { + transformed["enable"] = true + transformed["aggregationInterval"] = original["aggregation_interval"] + transformed["flowSampling"] = original["flow_sampling"] + transformed["metadata"] = original["metadata"] + } + + return transformed, nil +} diff --git a/google/resource_compute_subnetwork_generated_test.go b/google/resource_compute_subnetwork_generated_test.go index 2352f28f0a4..dc99e0f8050 100644 --- a/google/resource_compute_subnetwork_generated_test.go +++ b/google/resource_compute_subnetwork_generated_test.go @@ -68,6 +68,52 @@ resource "google_compute_network" "custom-test" { `, context) } +func TestAccComputeSubnetwork_subnetworkLoggingConfigExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(10), + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeSubnetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeSubnetwork_subnetworkLoggingConfigExample(context), + }, + { + ResourceName: "google_compute_subnetwork.subnet-with-logging", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccComputeSubnetwork_subnetworkLoggingConfigExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_compute_subnetwork" "subnet-with-logging" { + name = "log-test-subnetwork%{random_suffix}" + ip_cidr_range = "10.2.0.0/16" + region = "us-central1" + network = "${google_compute_network.custom-test.self_link}" + + log_config { + aggregation_interval = "INTERVAL_10_MIN" + flow_sampling = 0.5 + metadata = "INCLUDE_ALL_METADATA" + } +} + +resource "google_compute_network" "custom-test" { + name = "log-test-network%{random_suffix}" + auto_create_subnetworks = false +} +`, context) +} + func testAccCheckComputeSubnetworkDestroy(s *terraform.State) error { for name, rs := range s.RootModule().Resources { if rs.Type != "google_compute_subnetwork" { diff --git a/google/resource_compute_subnetwork_test.go b/google/resource_compute_subnetwork_test.go index c3294c5343f..95db1986404 100644 --- a/google/resource_compute_subnetwork_test.go +++ b/google/resource_compute_subnetwork_test.go @@ -214,12 +214,10 @@ func TestAccComputeSubnetwork_flowLogs(t *testing.T) { CheckDestroy: testAccCheckComputeSubnetworkDestroy, Steps: []resource.TestStep{ { - Config: testAccComputeSubnetwork_flowLogs(cnName, subnetworkName, true), + Config: testAccComputeSubnetwork_flowLogs(cnName, subnetworkName), Check: resource.ComposeTestCheckFunc( testAccCheckComputeSubnetworkExists( "google_compute_subnetwork.network-with-flow-logs", &subnetwork), - resource.TestCheckResourceAttr("google_compute_subnetwork.network-with-flow-logs", - "enable_flow_logs", "true"), ), }, { @@ -228,12 +226,75 @@ func TestAccComputeSubnetwork_flowLogs(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccComputeSubnetwork_flowLogs(cnName, subnetworkName, false), + Config: testAccComputeSubnetwork_flowLogsUpdate(cnName, subnetworkName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeSubnetworkExists( + "google_compute_subnetwork.network-with-flow-logs", &subnetwork), + ), + }, + { + ResourceName: "google_compute_subnetwork.network-with-flow-logs", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeSubnetwork_flowLogsDelete(cnName, subnetworkName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeSubnetworkExists( + "google_compute_subnetwork.network-with-flow-logs", &subnetwork), + ), + }, + { + ResourceName: "google_compute_subnetwork.network-with-flow-logs", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeSubnetwork_flowLogsMigrate(t *testing.T) { + t.Parallel() + + var subnetwork compute.Subnetwork + + cnName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + subnetworkName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeSubnetworkDestroy, + Steps: []resource.TestStep{ + { + Config: testAccComputeSubnetwork_flowLogsMigrate(cnName, subnetworkName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeSubnetworkExists( + "google_compute_subnetwork.network-with-flow-logs", &subnetwork), + ), + }, + { + ResourceName: "google_compute_subnetwork.network-with-flow-logs", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeSubnetwork_flowLogsMigrate2(cnName, subnetworkName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeSubnetworkExists( + "google_compute_subnetwork.network-with-flow-logs", &subnetwork), + ), + }, + { + ResourceName: "google_compute_subnetwork.network-with-flow-logs", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeSubnetwork_flowLogsMigrate3(cnName, subnetworkName), Check: resource.ComposeTestCheckFunc( testAccCheckComputeSubnetworkExists( "google_compute_subnetwork.network-with-flow-logs", &subnetwork), - resource.TestCheckResourceAttr("google_compute_subnetwork.network-with-flow-logs", - "enable_flow_logs", "false"), ), }, { @@ -259,6 +320,7 @@ func testAccCheckComputeSubnetworkExists(n string, subnetwork *compute.Subnetwor config := testAccProvider.Meta().(*Config) region, subnet_name := splitSubnetID(rs.Primary.ID) + found, err := config.clientCompute.Subnetworks.Get( config.Project, region, subnet_name).Do() if err != nil { @@ -382,7 +444,6 @@ resource "google_compute_subnetwork" "network-with-private-google-access" { region = "us-central1" network = "${google_compute_network.custom-test.self_link}" - enable_flow_logs = true secondary_ip_range { range_name = "tf-test-secondary-range-update" ip_cidr_range = "192.168.10.0/24" @@ -476,7 +537,51 @@ resource "google_compute_subnetwork" "network-with-private-secondary-ip-ranges" `, cnName, subnetworkName) } -func testAccComputeSubnetwork_flowLogs(cnName, subnetworkName string, enableLogs bool) string { +func testAccComputeSubnetwork_flowLogs(cnName, subnetworkName string) string { + return fmt.Sprintf(` +resource "google_compute_network" "custom-test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network-with-flow-logs" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = "${google_compute_network.custom-test.self_link}" + enable_flow_logs = true + log_config { + aggregation_interval = "INTERVAL_5_SEC" + flow_sampling = 0.5 + metadata = "INCLUDE_ALL_METADATA" + } +} +`, cnName, subnetworkName) +} + +func testAccComputeSubnetwork_flowLogsUpdate(cnName, subnetworkName string) string { + return fmt.Sprintf(` +resource "google_compute_network" "custom-test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network-with-flow-logs" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = "${google_compute_network.custom-test.self_link}" + enable_flow_logs = true + log_config { + aggregation_interval = "INTERVAL_30_SEC" + flow_sampling = 0.8 + metadata = "EXCLUDE_ALL_METADATA" + } +} +`, cnName, subnetworkName) +} + +func testAccComputeSubnetwork_flowLogsDelete(cnName, subnetworkName string) string { return fmt.Sprintf(` resource "google_compute_network" "custom-test" { name = "%s" @@ -488,7 +593,72 @@ resource "google_compute_subnetwork" "network-with-flow-logs" { ip_cidr_range = "10.0.0.0/16" region = "us-central1" network = "${google_compute_network.custom-test.self_link}" - enable_flow_logs = %v + enable_flow_logs = false +} +`, cnName, subnetworkName) +} + +func testAccComputeSubnetwork_flowLogsMigrate(cnName, subnetworkName string) string { + return fmt.Sprintf(` +resource "google_compute_network" "custom-test" { + name = "%s" + auto_create_subnetworks = false } -`, cnName, subnetworkName, enableLogs) + +resource "google_compute_subnetwork" "network-with-flow-logs" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = "${google_compute_network.custom-test.self_link}" + enable_flow_logs = true + log_config { + aggregation_interval = "INTERVAL_30_SEC" + flow_sampling = 0.6 + metadata = "INCLUDE_ALL_METADATA" + } +} +`, cnName, subnetworkName) +} + +func testAccComputeSubnetwork_flowLogsMigrate2(cnName, subnetworkName string) string { + return fmt.Sprintf(` +resource "google_compute_network" "custom-test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network-with-flow-logs" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = "${google_compute_network.custom-test.self_link}" + log_config { + aggregation_interval = "INTERVAL_30_SEC" + flow_sampling = 0.7 + metadata = "INCLUDE_ALL_METADATA" + } +} +`, cnName, subnetworkName) +} + +func testAccComputeSubnetwork_flowLogsMigrate3(cnName, subnetworkName string) string { + return fmt.Sprintf(` +resource "google_compute_network" "custom-test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "network-with-flow-logs" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = "${google_compute_network.custom-test.self_link}" + enable_flow_logs = true + log_config { + aggregation_interval = "INTERVAL_30_SEC" + flow_sampling = 0.8 + metadata = "INCLUDE_ALL_METADATA" + } +} +`, cnName, subnetworkName) } diff --git a/website/docs/r/compute_subnetwork.html.markdown b/website/docs/r/compute_subnetwork.html.markdown index f849b2a2d4c..204136b6c06 100644 --- a/website/docs/r/compute_subnetwork.html.markdown +++ b/website/docs/r/compute_subnetwork.html.markdown @@ -79,39 +79,31 @@ resource "google_compute_network" "custom-test" { } ``` -## Example Usage - Subnetwork Logging Config Beta +## Example Usage - Subnetwork Logging Config ```hcl resource "google_compute_subnetwork" "subnet-with-logging" { - provider = "google-beta" name = "log-test-subnetwork" ip_cidr_range = "10.2.0.0/16" region = "us-central1" network = "${google_compute_network.custom-test.self_link}" - enable_flow_logs = true log_config { aggregation_interval = "INTERVAL_10_MIN" - flow_sampling = 0.5 - metadata = "INCLUDE_ALL_METADATA" + flow_sampling = 0.5 + metadata = "INCLUDE_ALL_METADATA" } } resource "google_compute_network" "custom-test" { - provider = "google-beta" name = "log-test-network" auto_create_subnetworks = false } - -provider "google-beta"{ - region = "us-central1" - zone = "us-central1-a" -} ```
@@ -179,7 +171,7 @@ The following arguments are supported: creation time. * `enable_flow_logs` - - (Optional) + (Optional, Deprecated) Whether to enable flow logging for this subnetwork. * `secondary_ip_range` - @@ -201,6 +193,11 @@ The following arguments are supported: (Optional) URL of the GCP region for this subnetwork. +* `log_config` - + (Optional) + Denotes the logging options for the subnetwork flow logs. If logging is enabled + logs will be exported to Stackdriver. Structure is documented below. + * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. @@ -221,6 +218,31 @@ The `secondary_ip_range` block supports: Ranges must be unique and non-overlapping with all primary and secondary IP ranges within a network. Only IPv4 is supported. +The `log_config` block supports: + +* `aggregation_interval` - + (Optional) + Can only be specified if VPC flow logging for this subnetwork is enabled. + Toggles the aggregation interval for collecting flow logs. Increasing the + interval time will reduce the amount of generated flow logs for long + lasting connections. Default is an interval of 5 seconds per connection. + Possible values are INTERVAL_5_SEC, INTERVAL_30_SEC, INTERVAL_1_MIN, + INTERVAL_5_MIN, INTERVAL_10_MIN, INTERVAL_15_MIN + +* `flow_sampling` - + (Optional) + Can only be specified if VPC flow logging for this subnetwork is enabled. + The value of the field must be in [0, 1]. Set the sampling rate of VPC + flow logs within the subnetwork where 1.0 means all collected logs are + reported and 0.0 means no logs are reported. Default is 0.5 which means + half of all collected logs are reported. + +* `metadata` - + (Optional) + Can only be specified if VPC flow logging for this subnetwork is enabled. + Configures whether metadata fields should be added to the reported VPC + flow logs. Default is `INCLUDE_ALL_METADATA`. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: