From 9a9e5ea57d893c17f531effb07c5b0c170a3bfc7 Mon Sep 17 00:00:00 2001 From: The Magician Date: Wed, 26 Jul 2023 12:05:19 -0700 Subject: [PATCH] Move regional SSL policies to GA (#8443) (#15299) Signed-off-by: Modular Magician --- .changelog/8443.txt | 4 + google/provider/provider.go | 5 +- ...resource_compute_region_ssl_policy_test.go | 225 +++++++ .../resource_compute_region_ssl_policy.go | 581 ++++++++++++++++++ ...ource_compute_region_ssl_policy_sweeper.go | 139 +++++ .../r/compute_region_ssl_policy.html.markdown | 4 +- 6 files changed, 953 insertions(+), 5 deletions(-) create mode 100644 .changelog/8443.txt create mode 100644 google/services/compute/resource_compute_region_ssl_policy.go create mode 100644 google/services/compute/resource_compute_region_ssl_policy_sweeper.go diff --git a/.changelog/8443.txt b/.changelog/8443.txt new file mode 100644 index 00000000000..a590445da4a --- /dev/null +++ b/.changelog/8443.txt @@ -0,0 +1,4 @@ +```release-note:new-resource +`google_compute_region_ssl_policy` (GA) + +``` diff --git a/google/provider/provider.go b/google/provider/provider.go index a347c26a34b..9617954db05 100644 --- a/google/provider/provider.go +++ b/google/provider/provider.go @@ -947,9 +947,9 @@ func DatasourceMapWithErrors() (map[string]*schema.Resource, error) { }) } -// Generated resources: 302 +// Generated resources: 303 // Generated IAM resources: 204 -// Total generated resources: 506 +// Total generated resources: 507 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1146,6 +1146,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_compute_region_network_endpoint_group": compute.ResourceComputeRegionNetworkEndpointGroup(), "google_compute_region_per_instance_config": compute.ResourceComputeRegionPerInstanceConfig(), "google_compute_region_ssl_certificate": compute.ResourceComputeRegionSslCertificate(), + "google_compute_region_ssl_policy": compute.ResourceComputeRegionSslPolicy(), "google_compute_region_target_http_proxy": compute.ResourceComputeRegionTargetHttpProxy(), "google_compute_region_target_https_proxy": compute.ResourceComputeRegionTargetHttpsProxy(), "google_compute_region_target_tcp_proxy": compute.ResourceComputeRegionTargetTcpProxy(), diff --git a/google/resource_compute_region_ssl_policy_test.go b/google/resource_compute_region_ssl_policy_test.go index 9821d4cf9b2..0f1a7a81d79 100644 --- a/google/resource_compute_region_ssl_policy_test.go +++ b/google/resource_compute_region_ssl_policy_test.go @@ -1,3 +1,228 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package google + +import ( + "fmt" + "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" + + "google.golang.org/api/compute/v1" +) + +func TestAccComputeRegionSslPolicy_update(t *testing.T) { + t.Parallel() + + var sslPolicy compute.SslPolicy + sslPolicyName := fmt.Sprintf("test-ssl-policy-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeSslPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionSslUpdate1(sslPolicyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionSslPolicyExists( + t, "google_compute_region_ssl_policy.update", &sslPolicy), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "profile", "MODERN"), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "min_tls_version", "TLS_1_0"), + ), + }, + { + ResourceName: "google_compute_region_ssl_policy.update", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeRegionSslUpdate2(sslPolicyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionSslPolicyExists( + t, "google_compute_region_ssl_policy.update", &sslPolicy), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "profile", "RESTRICTED"), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "min_tls_version", "TLS_1_2"), + ), + }, + { + ResourceName: "google_compute_region_ssl_policy.update", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeRegionSslPolicy_update_to_custom(t *testing.T) { + t.Parallel() + + var sslPolicy compute.SslPolicy + sslPolicyName := fmt.Sprintf("test-ssl-policy-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeSslPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionSslUpdate1(sslPolicyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionSslPolicyExists( + t, "google_compute_region_ssl_policy.update", &sslPolicy), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "profile", "MODERN"), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "min_tls_version", "TLS_1_0"), + ), + }, + { + ResourceName: "google_compute_region_ssl_policy.update", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeRegionSslUpdate3(sslPolicyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionSslPolicyExists( + t, "google_compute_region_ssl_policy.update", &sslPolicy), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "profile", "CUSTOM"), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "min_tls_version", "TLS_1_1"), + ), + }, + { + ResourceName: "google_compute_region_ssl_policy.update", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComputeRegionSslPolicy_update_from_custom(t *testing.T) { + t.Parallel() + + var sslPolicy compute.SslPolicy + sslPolicyName := fmt.Sprintf("test-ssl-policy-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeSslPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionSslUpdate3(sslPolicyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionSslPolicyExists( + t, "google_compute_region_ssl_policy.update", &sslPolicy), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "profile", "CUSTOM"), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "min_tls_version", "TLS_1_1"), + ), + }, + { + ResourceName: "google_compute_region_ssl_policy.update", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccComputeRegionSslUpdate1(sslPolicyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionSslPolicyExists( + t, "google_compute_region_ssl_policy.update", &sslPolicy), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "profile", "MODERN"), + resource.TestCheckResourceAttr( + "google_compute_region_ssl_policy.update", "min_tls_version", "TLS_1_0"), + ), + }, + { + ResourceName: "google_compute_region_ssl_policy.update", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckComputeRegionSslPolicyExists(t *testing.T, n string, sslPolicy *compute.SslPolicy) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + config := acctest.GoogleProviderConfig(t) + + project, err := acctest.GetTestProject(rs.Primary, config) + if err != nil { + return err + } + + name := rs.Primary.Attributes["name"] + + found, err := config.NewComputeClient(config.UserAgent).RegionSslPolicies.Get( + project, "us-central1", name).Do() + if err != nil { + return fmt.Errorf("Error Reading SSL Policy %s: %s", name, err) + } + + if found.Name != name { + return fmt.Errorf("SSL Policy not found") + } + + *sslPolicy = *found + + return nil + } +} + +func testAccComputeRegionSslUpdate1(resourceName string) string { + return fmt.Sprintf(` +resource "google_compute_region_ssl_policy" "update" { + name = "%s" + description = "Generated by TF provider acceptance test" + min_tls_version = "TLS_1_0" + profile = "MODERN" + region = "us-central1" +} +`, resourceName) +} + +func testAccComputeRegionSslUpdate2(resourceName string) string { + return fmt.Sprintf(` +resource "google_compute_region_ssl_policy" "update" { + name = "%s" + description = "Generated by TF provider acceptance test" + min_tls_version = "TLS_1_2" + profile = "RESTRICTED" + region = "us-central1" +} +`, resourceName) +} + +func testAccComputeRegionSslUpdate3(resourceName string) string { + return fmt.Sprintf(` +resource "google_compute_region_ssl_policy" "update" { + name = "%s" + description = "Generated by TF provider acceptance test" + min_tls_version = "TLS_1_1" + profile = "CUSTOM" + region = "us-central1" + custom_features = ["TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"] +} +`, resourceName) +} diff --git a/google/services/compute/resource_compute_region_ssl_policy.go b/google/services/compute/resource_compute_region_ssl_policy.go new file mode 100644 index 00000000000..2a4e939709b --- /dev/null +++ b/google/services/compute/resource_compute_region_ssl_policy.go @@ -0,0 +1,581 @@ +// 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 compute + +import ( + "context" + "fmt" + "log" + "reflect" + "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 regionSslPolicyCustomizeDiff(_ context.Context, diff *schema.ResourceDiff, v interface{}) error { + profile := diff.Get("profile") + customFeaturesCount := diff.Get("custom_features.#") + + // Validate that policy configs aren't incompatible during all phases + // CUSTOM profile demands non-zero custom_features, and other profiles (i.e., not CUSTOM) demand zero custom_features + if diff.HasChange("profile") || diff.HasChange("custom_features") { + if profile.(string) == "CUSTOM" && customFeaturesCount.(int) == 0 { + return fmt.Errorf("Error in SSL Policy %s: the profile is set to %s but no custom_features are set.", diff.Get("name"), profile.(string)) + } else if profile.(string) != "CUSTOM" && customFeaturesCount.(int) != 0 { + return fmt.Errorf("Error in SSL Policy %s: the profile is set to %s but using custom_features requires the profile to be CUSTOM.", diff.Get("name"), profile.(string)) + } + return nil + } + return nil +} + +func ResourceComputeRegionSslPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceComputeRegionSslPolicyCreate, + Read: resourceComputeRegionSslPolicyRead, + Update: resourceComputeRegionSslPolicyUpdate, + Delete: resourceComputeRegionSslPolicyDelete, + + Importer: &schema.ResourceImporter{ + State: resourceComputeRegionSslPolicyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(20 * time.Minute), + Update: schema.DefaultTimeout(20 * time.Minute), + Delete: schema.DefaultTimeout(20 * time.Minute), + }, + + CustomizeDiff: customdiff.All( + regionSslPolicyCustomizeDiff, + ), + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Name of the resource. Provided by the client when the resource is +created. The name must be 1-63 characters long, and comply with +RFC1035. Specifically, the name must be 1-63 characters long and match +the regular expression '[a-z]([-a-z0-9]*[a-z0-9])?' which means the +first character must be a lowercase letter, and all following +characters must be a dash, lowercase letter, or digit, except the last +character, which cannot be a dash.`, + }, + "region": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + Description: `The region where the regional SSL policy resides.`, + }, + "custom_features": { + Type: schema.TypeSet, + Optional: true, + Description: `A list of features enabled when the selected profile is CUSTOM. The +method returns the set of features that can be specified in this +list. This field must be empty if the profile is not CUSTOM. + +See the [official documentation](https://cloud.google.com/compute/docs/load-balancing/ssl-policies#profilefeaturesupport) +for which ciphers are available to use. **Note**: this argument +*must* be present when using the 'CUSTOM' profile. This argument +*must not* be present when using any other profile.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: `An optional description of this resource.`, + }, + "min_tls_version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidateEnum([]string{"TLS_1_0", "TLS_1_1", "TLS_1_2", ""}), + Description: `The minimum version of SSL protocol that can be used by the clients +to establish a connection with the load balancer. Default value: "TLS_1_0" Possible values: ["TLS_1_0", "TLS_1_1", "TLS_1_2"]`, + Default: "TLS_1_0", + }, + "profile": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidateEnum([]string{"COMPATIBLE", "MODERN", "RESTRICTED", "CUSTOM", ""}), + Description: `Profile specifies the set of SSL features that can be used by the +load balancer when negotiating SSL with clients. If using 'CUSTOM', +the set of SSL features to enable must be specified in the +'customFeatures' field. + +See the [official documentation](https://cloud.google.com/compute/docs/load-balancing/ssl-policies#profilefeaturesupport) +for information on what cipher suites each profile provides. If +'CUSTOM' is used, the 'custom_features' attribute **must be set**. Default value: "COMPATIBLE" Possible values: ["COMPATIBLE", "MODERN", "RESTRICTED", "CUSTOM"]`, + Default: "COMPATIBLE", + }, + "creation_timestamp": { + Type: schema.TypeString, + Computed: true, + Description: `Creation timestamp in RFC3339 text format.`, + }, + "enabled_features": { + Type: schema.TypeSet, + Computed: true, + Description: `The list of features enabled in the SSL policy.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Set: schema.HashString, + }, + "fingerprint": { + Type: schema.TypeString, + Computed: true, + Description: `Fingerprint of this resource. A hash of the contents stored in this +object. This field is used in optimistic locking.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "self_link": { + Type: schema.TypeString, + Computed: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceComputeRegionSslPolicyCreate(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 := expandComputeRegionSslPolicyDescription(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 + } + nameProp, err := expandComputeRegionSslPolicyName(d.Get("name"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { + obj["name"] = nameProp + } + profileProp, err := expandComputeRegionSslPolicyProfile(d.Get("profile"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("profile"); !tpgresource.IsEmptyValue(reflect.ValueOf(profileProp)) && (ok || !reflect.DeepEqual(v, profileProp)) { + obj["profile"] = profileProp + } + minTlsVersionProp, err := expandComputeRegionSslPolicyMinTlsVersion(d.Get("min_tls_version"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("min_tls_version"); !tpgresource.IsEmptyValue(reflect.ValueOf(minTlsVersionProp)) && (ok || !reflect.DeepEqual(v, minTlsVersionProp)) { + obj["minTlsVersion"] = minTlsVersionProp + } + customFeaturesProp, err := expandComputeRegionSslPolicyCustomFeatures(d.Get("custom_features"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("custom_features"); ok || !reflect.DeepEqual(v, customFeaturesProp) { + obj["customFeatures"] = customFeaturesProp + } + fingerprintProp, err := expandComputeRegionSslPolicyFingerprint(d.Get("fingerprint"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(fingerprintProp)) && (ok || !reflect.DeepEqual(v, fingerprintProp)) { + obj["fingerprint"] = fingerprintProp + } + regionProp, err := expandComputeRegionSslPolicyRegion(d.Get("region"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("region"); !tpgresource.IsEmptyValue(reflect.ValueOf(regionProp)) && (ok || !reflect.DeepEqual(v, regionProp)) { + obj["region"] = regionProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/sslPolicies") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new RegionSslPolicy: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for RegionSslPolicy: %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 RegionSslPolicy: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/regions/{{region}}/sslPolicies/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = ComputeOperationWaitTime( + config, res, project, "Creating RegionSslPolicy", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create RegionSslPolicy: %s", err) + } + + log.Printf("[DEBUG] Finished creating RegionSslPolicy %q: %#v", d.Id(), res) + + return resourceComputeRegionSslPolicyRead(d, meta) +} + +func resourceComputeRegionSslPolicyRead(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, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/sslPolicies/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for RegionSslPolicy: %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("ComputeRegionSslPolicy %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + + if err := d.Set("creation_timestamp", flattenComputeRegionSslPolicyCreationTimestamp(res["creationTimestamp"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("description", flattenComputeRegionSslPolicyDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("name", flattenComputeRegionSslPolicyName(res["name"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("profile", flattenComputeRegionSslPolicyProfile(res["profile"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("min_tls_version", flattenComputeRegionSslPolicyMinTlsVersion(res["minTlsVersion"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("enabled_features", flattenComputeRegionSslPolicyEnabledFeatures(res["enabledFeatures"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("custom_features", flattenComputeRegionSslPolicyCustomFeatures(res["customFeatures"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("fingerprint", flattenComputeRegionSslPolicyFingerprint(res["fingerprint"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("region", flattenComputeRegionSslPolicyRegion(res["region"], d, config)); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + if err := d.Set("self_link", tpgresource.ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { + return fmt.Errorf("Error reading RegionSslPolicy: %s", err) + } + + return nil +} + +func resourceComputeRegionSslPolicyUpdate(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 RegionSslPolicy: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + profileProp, err := expandComputeRegionSslPolicyProfile(d.Get("profile"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("profile"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, profileProp)) { + obj["profile"] = profileProp + } + minTlsVersionProp, err := expandComputeRegionSslPolicyMinTlsVersion(d.Get("min_tls_version"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("min_tls_version"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, minTlsVersionProp)) { + obj["minTlsVersion"] = minTlsVersionProp + } + customFeaturesProp, err := expandComputeRegionSslPolicyCustomFeatures(d.Get("custom_features"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("custom_features"); ok || !reflect.DeepEqual(v, customFeaturesProp) { + obj["customFeatures"] = customFeaturesProp + } + fingerprintProp, err := expandComputeRegionSslPolicyFingerprint(d.Get("fingerprint"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("fingerprint"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, fingerprintProp)) { + obj["fingerprint"] = fingerprintProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/sslPolicies/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating RegionSslPolicy %q: %#v", d.Id(), obj) + + // 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: "PATCH", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + + if err != nil { + return fmt.Errorf("Error updating RegionSslPolicy %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating RegionSslPolicy %q: %#v", d.Id(), res) + } + + err = ComputeOperationWaitTime( + config, res, project, "Updating RegionSslPolicy", userAgent, + d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return err + } + + return resourceComputeRegionSslPolicyRead(d, meta) +} + +func resourceComputeRegionSslPolicyDelete(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 RegionSslPolicy: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/sslPolicies/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting RegionSslPolicy %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, "RegionSslPolicy") + } + + err = ComputeOperationWaitTime( + config, res, project, "Deleting RegionSslPolicy", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting RegionSslPolicy %q: %#v", d.Id(), res) + return nil +} + +func resourceComputeRegionSslPolicyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "projects/(?P[^/]+)/regions/(?P[^/]+)/sslPolicies/(?P[^/]+)", + "(?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}}/regions/{{region}}/sslPolicies/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenComputeRegionSslPolicyCreationTimestamp(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenComputeRegionSslPolicyDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenComputeRegionSslPolicyName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenComputeRegionSslPolicyProfile(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenComputeRegionSslPolicyMinTlsVersion(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenComputeRegionSslPolicyEnabledFeatures(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeRegionSslPolicyCustomFeatures(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + return schema.NewSet(schema.HashString, v.([]interface{})) +} + +func flattenComputeRegionSslPolicyFingerprint(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenComputeRegionSslPolicyRegion(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + return tpgresource.ConvertSelfLinkToV1(v.(string)) +} + +func expandComputeRegionSslPolicyDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionSslPolicyName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionSslPolicyProfile(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionSslPolicyMinTlsVersion(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionSslPolicyCustomFeatures(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + v = v.(*schema.Set).List() + return v, nil +} + +func expandComputeRegionSslPolicyFingerprint(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandComputeRegionSslPolicyRegion(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + f, err := tpgresource.ParseGlobalFieldValue("regions", v.(string), "project", d, config, true) + if err != nil { + return nil, fmt.Errorf("Invalid value for region: %s", err) + } + return f.RelativeLink(), nil +} diff --git a/google/services/compute/resource_compute_region_ssl_policy_sweeper.go b/google/services/compute/resource_compute_region_ssl_policy_sweeper.go new file mode 100644 index 00000000000..c08f437fe35 --- /dev/null +++ b/google/services/compute/resource_compute_region_ssl_policy_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 compute + +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("ComputeRegionSslPolicy", testSweepComputeRegionSslPolicy) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepComputeRegionSslPolicy(region string) error { + resourceName := "ComputeRegionSslPolicy" + 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://compute.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/sslPolicies", "?")[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["items"] + 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://compute.googleapis.com/compute/v1/projects/{{project}}/regions/{{region}}/sslPolicies/{{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/website/docs/r/compute_region_ssl_policy.html.markdown b/website/docs/r/compute_region_ssl_policy.html.markdown index c6736d2dc46..c22eb1c4a3c 100644 --- a/website/docs/r/compute_region_ssl_policy.html.markdown +++ b/website/docs/r/compute_region_ssl_policy.html.markdown @@ -22,12 +22,10 @@ description: |- Represents a Regional SSL policy. SSL policies give you the ability to control the features of SSL that your SSL proxy or HTTPS load balancer negotiates. -~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. -See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. To get more information about RegionSslPolicy, see: -* [API documentation](https://cloud.google.com/compute/docs/reference/rest/beta/regionSslPolicies) +* [API documentation](https://cloud.google.com/compute/docs/reference/rest/v1/regionSslPolicies) * How-to Guides * [Using SSL Policies](https://cloud.google.com/compute/docs/load-balancing/ssl-policies)