From 9c8a3acbc77bf3ed1a807c041e8e4d0412232e89 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Wed, 2 Aug 2023 16:28:19 +0000 Subject: [PATCH] Adding ServiceConnectionPolicies resource in NetworkConnectivity. (#8273) * adding both resources, basic test for serviceClass it's working, need to fix the test scenario for policy * fix the test scenario and the service class resource properties * adding a testing update, just adding the labels for the resource * added the resource service connection map, and it's basic test, need to evaluate * Revert "added the resource service connection map, and it's basic test, need to evaluate" This reverts commit 4240e1d81e5901221cee1f1db7c03c8fbc58e3a6. * removing the service class in one test scenario and using a static value * fix a typo * removing serviceClass and fix the tests * removing ga tag and updatinga etag for fingerprint type * updating the code, to remove the static value from the docs, need to test * adding a file to tpgtools override at product level * adding function to help with env var, but the patch on tests it's failing * adding the variable to be used in the docs * fixing the test, the network field cannot be immutable * removing the env_var service class and adding a static value * updating the value used from tests and documentation * removing unused resources for docs and tests * fix typos, not used variables and run the fmt * adding description to the basic test * fixed yaml variable override * removing unused resources for tests, and making the test fails with network as immutable * adding encoder to help network field be immutable and be sent on patch method Signed-off-by: Modular Magician --- .changelog/8273.txt | 3 + google/config_test_utils.go | 1 + google/fwmodels/provider_model.go | 2 +- google/fwprovider/framework_provider.go | 6 + google/fwtransport/framework_config.go | 10 + google/gcp_sweeper_test.go | 1 + google/provider/provider.go | 12 +- ...tivity_service_connection_policies_test.go | 111 ++++ ...ervice_connection_policy_generated_test.go | 124 ++++ .../network_connectivity_operation.go | 74 +++ ..._connectivity_service_connection_policy.go | 626 ++++++++++++++++++ ...ivity_service_connection_policy_sweeper.go | 139 ++++ google/transport/config.go | 9 + google/transport/provider_dcl_endpoints.go | 20 - ...ty_service_connection_policy.html.markdown | 162 +++++ 15 files changed, 1277 insertions(+), 23 deletions(-) create mode 100644 .changelog/8273.txt create mode 100644 google/resource_network_connectivity_service_connection_policies_test.go create mode 100644 google/resource_network_connectivity_service_connection_policy_generated_test.go create mode 100644 google/services/networkconnectivity/network_connectivity_operation.go create mode 100644 google/services/networkconnectivity/resource_network_connectivity_service_connection_policy.go create mode 100644 google/services/networkconnectivity/resource_network_connectivity_service_connection_policy_sweeper.go create mode 100644 website/docs/r/network_connectivity_service_connection_policy.html.markdown diff --git a/.changelog/8273.txt b/.changelog/8273.txt new file mode 100644 index 00000000000..4b2f74c3275 --- /dev/null +++ b/.changelog/8273.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +google_network_connectivity_service_connection_policy +``` diff --git a/google/config_test_utils.go b/google/config_test_utils.go index 249ffc7d704..5721b074a68 100644 --- a/google/config_test_utils.go +++ b/google/config_test_utils.go @@ -90,6 +90,7 @@ func configureTestBasePaths(c *transport_tpg.Config, url string) { c.MemcacheBasePath = url c.MLEngineBasePath = url c.MonitoringBasePath = url + c.NetworkConnectivityBasePath = url c.NetworkManagementBasePath = url c.NetworkSecurityBasePath = url c.NetworkServicesBasePath = url diff --git a/google/fwmodels/provider_model.go b/google/fwmodels/provider_model.go index e1e69257f84..e84e91a5b9c 100644 --- a/google/fwmodels/provider_model.go +++ b/google/fwmodels/provider_model.go @@ -91,6 +91,7 @@ type ProviderModel struct { MemcacheCustomEndpoint types.String `tfsdk:"memcache_custom_endpoint"` MLEngineCustomEndpoint types.String `tfsdk:"ml_engine_custom_endpoint"` MonitoringCustomEndpoint types.String `tfsdk:"monitoring_custom_endpoint"` + NetworkConnectivityCustomEndpoint types.String `tfsdk:"network_connectivity_custom_endpoint"` NetworkManagementCustomEndpoint types.String `tfsdk:"network_management_custom_endpoint"` NetworkSecurityCustomEndpoint types.String `tfsdk:"network_security_custom_endpoint"` NetworkServicesCustomEndpoint types.String `tfsdk:"network_services_custom_endpoint"` @@ -141,7 +142,6 @@ type ProviderModel struct { CloudResourceManagerCustomEndpoint types.String `tfsdk:"cloud_resource_manager_custom_endpoint"` EventarcCustomEndpoint types.String `tfsdk:"eventarc_custom_endpoint"` FirebaserulesCustomEndpoint types.String `tfsdk:"firebaserules_custom_endpoint"` - NetworkConnectivityCustomEndpoint types.String `tfsdk:"network_connectivity_custom_endpoint"` OrgPolicyCustomEndpoint types.String `tfsdk:"org_policy_custom_endpoint"` RecaptchaEnterpriseCustomEndpoint types.String `tfsdk:"recaptcha_enterprise_custom_endpoint"` } diff --git a/google/fwprovider/framework_provider.go b/google/fwprovider/framework_provider.go index 7fe2a4aad2d..6500587addf 100644 --- a/google/fwprovider/framework_provider.go +++ b/google/fwprovider/framework_provider.go @@ -515,6 +515,12 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, transport_tpg.CustomEndpointValidator(), }, }, + "network_connectivity_custom_endpoint": &schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + transport_tpg.CustomEndpointValidator(), + }, + }, "network_management_custom_endpoint": &schema.StringAttribute{ Optional: true, Validators: []validator.String{ diff --git a/google/fwtransport/framework_config.go b/google/fwtransport/framework_config.go index 96c095e5902..45b61f8205a 100644 --- a/google/fwtransport/framework_config.go +++ b/google/fwtransport/framework_config.go @@ -115,6 +115,7 @@ type FrameworkProviderConfig struct { MemcacheBasePath string MLEngineBasePath string MonitoringBasePath string + NetworkConnectivityBasePath string NetworkManagementBasePath string NetworkSecurityBasePath string NetworkServicesBasePath string @@ -251,6 +252,7 @@ func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context, p.MemcacheBasePath = data.MemcacheCustomEndpoint.ValueString() p.MLEngineBasePath = data.MLEngineCustomEndpoint.ValueString() p.MonitoringBasePath = data.MonitoringCustomEndpoint.ValueString() + p.NetworkConnectivityBasePath = data.NetworkConnectivityCustomEndpoint.ValueString() p.NetworkManagementBasePath = data.NetworkManagementCustomEndpoint.ValueString() p.NetworkSecurityBasePath = data.NetworkSecurityCustomEndpoint.ValueString() p.NetworkServicesBasePath = data.NetworkServicesCustomEndpoint.ValueString() @@ -935,6 +937,14 @@ func (p *FrameworkProviderConfig) HandleDefaults(ctx context.Context, data *fwmo data.MonitoringCustomEndpoint = types.StringValue(customEndpoint.(string)) } } + if data.NetworkConnectivityCustomEndpoint.IsNull() { + customEndpoint := transport_tpg.MultiEnvDefault([]string{ + "GOOGLE_NETWORK_CONNECTIVITY_CUSTOM_ENDPOINT", + }, transport_tpg.DefaultBasePaths[transport_tpg.NetworkConnectivityBasePathKey]) + if customEndpoint != nil { + data.NetworkConnectivityCustomEndpoint = types.StringValue(customEndpoint.(string)) + } + } if data.NetworkManagementCustomEndpoint.IsNull() { customEndpoint := transport_tpg.MultiEnvDefault([]string{ "GOOGLE_NETWORK_MANAGEMENT_CUSTOM_ENDPOINT", diff --git a/google/gcp_sweeper_test.go b/google/gcp_sweeper_test.go index ebddcb939ca..086e21f5541 100644 --- a/google/gcp_sweeper_test.go +++ b/google/gcp_sweeper_test.go @@ -74,6 +74,7 @@ import ( _ "github.com/hashicorp/terraform-provider-google/google/services/memcache" _ "github.com/hashicorp/terraform-provider-google/google/services/mlengine" _ "github.com/hashicorp/terraform-provider-google/google/services/monitoring" + _ "github.com/hashicorp/terraform-provider-google/google/services/networkconnectivity" _ "github.com/hashicorp/terraform-provider-google/google/services/networkmanagement" _ "github.com/hashicorp/terraform-provider-google/google/services/networksecurity" _ "github.com/hashicorp/terraform-provider-google/google/services/networkservices" diff --git a/google/provider/provider.go b/google/provider/provider.go index d16e9f82077..07bb5b4a75b 100644 --- a/google/provider/provider.go +++ b/google/provider/provider.go @@ -79,6 +79,7 @@ import ( "github.com/hashicorp/terraform-provider-google/google/services/memcache" "github.com/hashicorp/terraform-provider-google/google/services/mlengine" "github.com/hashicorp/terraform-provider-google/google/services/monitoring" + "github.com/hashicorp/terraform-provider-google/google/services/networkconnectivity" "github.com/hashicorp/terraform-provider-google/google/services/networkmanagement" "github.com/hashicorp/terraform-provider-google/google/services/networksecurity" "github.com/hashicorp/terraform-provider-google/google/services/networkservices" @@ -554,6 +555,11 @@ func Provider() *schema.Provider { Optional: true, ValidateFunc: transport_tpg.ValidateCustomEndpoint, }, + "network_connectivity_custom_endpoint": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: transport_tpg.ValidateCustomEndpoint, + }, "network_management_custom_endpoint": { Type: schema.TypeString, Optional: true, @@ -953,9 +959,9 @@ func DatasourceMapWithErrors() (map[string]*schema.Resource, error) { }) } -// Generated resources: 305 +// Generated resources: 306 // Generated IAM resources: 204 -// Total generated resources: 509 +// Total generated resources: 510 func ResourceMap() map[string]*schema.Resource { resourceMap, _ := ResourceMapWithErrors() return resourceMap @@ -1363,6 +1369,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { "google_monitoring_custom_service": monitoring.ResourceMonitoringService(), "google_monitoring_slo": monitoring.ResourceMonitoringSlo(), "google_monitoring_uptime_check_config": monitoring.ResourceMonitoringUptimeCheckConfig(), + "google_network_connectivity_service_connection_policy": networkconnectivity.ResourceNetworkConnectivityServiceConnectionPolicy(), "google_network_management_connectivity_test": networkmanagement.ResourceNetworkManagementConnectivityTest(), "google_network_security_address_group": networksecurity.ResourceNetworkSecurityAddressGroup(), "google_network_security_gateway_security_policy": networksecurity.ResourceNetworkSecurityGatewaySecurityPolicy(), @@ -1764,6 +1771,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, p *schema.Pr config.MemcacheBasePath = d.Get("memcache_custom_endpoint").(string) config.MLEngineBasePath = d.Get("ml_engine_custom_endpoint").(string) config.MonitoringBasePath = d.Get("monitoring_custom_endpoint").(string) + config.NetworkConnectivityBasePath = d.Get("network_connectivity_custom_endpoint").(string) config.NetworkManagementBasePath = d.Get("network_management_custom_endpoint").(string) config.NetworkSecurityBasePath = d.Get("network_security_custom_endpoint").(string) config.NetworkServicesBasePath = d.Get("network_services_custom_endpoint").(string) diff --git a/google/resource_network_connectivity_service_connection_policies_test.go b/google/resource_network_connectivity_service_connection_policies_test.go new file mode 100644 index 00000000000..608d8cb0026 --- /dev/null +++ b/google/resource_network_connectivity_service_connection_policies_test.go @@ -0,0 +1,111 @@ +// 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-provider-google/google/acctest" +) + +func TestAccNetworkConnectivityServiceConnectionPolicy_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "networkProducerName": fmt.Sprintf("tf-test-network-%s", RandString(t, 10)), + "subnetworkProducerName1": fmt.Sprintf("tf-test-subnet-producer-%s", RandString(t, 10)), + "subnetworkProducerName2": fmt.Sprintf("tf-test-subnet-producer-%s", RandString(t, 10)), + "serviceConnectionPolicyName": fmt.Sprintf("tf-test-service-connection-policy-%s", RandString(t, 10)), + } + + VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckNetworkConnectivityServiceConnectionPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkConnectivityServiceConnectionPolicy_basic(context), + }, + { + ResourceName: "google_network_connectivity_service_connection_policy.default", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccNetworkConnectivityServiceConnectionPolicy_update(context), + }, + { + ResourceName: "google_network_connectivity_service_connection_policy.default", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccNetworkConnectivityServiceConnectionPolicy_basic(context), + }, + { + ResourceName: "google_network_connectivity_service_connection_policy.default", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccNetworkConnectivityServiceConnectionPolicy_basic(context map[string]interface{}) string { + return acctest.Nprintf(` + resource "google_compute_network" "producer_net" { + name = "%{networkProducerName}" + auto_create_subnetworks = false + } + + resource "google_compute_subnetwork" "producer_subnet" { + name = "%{subnetworkProducerName1}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = google_compute_network.producer_net.id + } + + resource "google_network_connectivity_service_connection_policy" "default" { + name = "%{serviceConnectionPolicyName}" + location = "us-central1" + service_class = "gcp-memorystore-redis" + network = google_compute_network.producer_net.id + psc_config { + subnetworks = [google_compute_subnetwork.producer_subnet.id] + limit = 2 + } + } +`, context) +} + +func testAccNetworkConnectivityServiceConnectionPolicy_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "producer_net" { + name = "%{networkProducerName}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "producer_subnet1" { + name = "%{subnetworkProducerName2}" + ip_cidr_range = "10.1.0.0/16" + region = "us-central1" + network = google_compute_network.producer_net.id +} + +resource "google_network_connectivity_service_connection_policy" "default" { + name = "%{serviceConnectionPolicyName}" + location = "us-central1" + service_class = "gcp-memorystore-redis" + network = google_compute_network.producer_net.id + psc_config { + subnetworks = [google_compute_subnetwork.producer_subnet1.id] + limit = 4 + } + labels = { + foo = "bar" + } +} +`, context) +} diff --git a/google/resource_network_connectivity_service_connection_policy_generated_test.go b/google/resource_network_connectivity_service_connection_policy_generated_test.go new file mode 100644 index 00000000000..4cb92adc14b --- /dev/null +++ b/google/resource_network_connectivity_service_connection_policy_generated_test.go @@ -0,0 +1,124 @@ +// 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 google + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func TestAccNetworkConnectivityServiceConnectionPolicy_networkConnectivityPolicyBasicExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "service_class_name": "gcp-memorystore-redis", + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckNetworkConnectivityServiceConnectionPolicyDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetworkConnectivityServiceConnectionPolicy_networkConnectivityPolicyBasicExample(context), + }, + { + ResourceName: "google_network_connectivity_service_connection_policy.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location"}, + }, + }, + }) +} + +func testAccNetworkConnectivityServiceConnectionPolicy_networkConnectivityPolicyBasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_compute_network" "producer_net" { + name = "tf-test-producer-net%{random_suffix}" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "producer_subnet" { + name = "tf-test-producer-subnet%{random_suffix}" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = google_compute_network.producer_net.id +} + +resource "google_network_connectivity_service_connection_policy" "default" { + name = "tf-test-my-network-connectivity-policy%{random_suffix}" + location = "us-central1" + service_class = "%{service_class_name}" + description = "my basic service connection policy" + network = google_compute_network.producer_net.id + psc_config { + subnetworks = [google_compute_subnetwork.producer_subnet.id] + limit = 2 + } +} +`, context) +} + +func testAccCheckNetworkConnectivityServiceConnectionPolicyDestroyProducer(t *testing.T) func(s *terraform.State) error { + return func(s *terraform.State) error { + for name, rs := range s.RootModule().Resources { + if rs.Type != "google_network_connectivity_service_connection_policy" { + continue + } + if strings.HasPrefix(name, "data.") { + continue + } + + config := acctest.GoogleProviderConfig(t) + + url, err := tpgresource.ReplaceVarsForTest(config, rs, "{{NetworkConnectivityBasePath}}projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + if config.BillingProject != "" { + billingProject = config.BillingProject + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + if err == nil { + return fmt.Errorf("NetworkConnectivityServiceConnectionPolicy still exists at %s", url) + } + } + + return nil + } +} diff --git a/google/services/networkconnectivity/network_connectivity_operation.go b/google/services/networkconnectivity/network_connectivity_operation.go new file mode 100644 index 00000000000..12120a6fa57 --- /dev/null +++ b/google/services/networkconnectivity/network_connectivity_operation.go @@ -0,0 +1,74 @@ +// 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 networkconnectivity + +import ( + "fmt" + "time" + + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +type NetworkConnectivityOperationWaiter struct { + Config *transport_tpg.Config + UserAgent string + Project string + tpgresource.CommonOperationWaiter +} + +func (w *NetworkConnectivityOperationWaiter) QueryOp() (interface{}, error) { + if w == nil { + return nil, fmt.Errorf("Cannot query operation, it's unset or nil.") + } + // Returns the proper get. + url := fmt.Sprintf("%s%s", w.Config.NetworkConnectivityBasePath, w.CommonOperationWaiter.Op.Name) + + return transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: w.Config, + Method: "GET", + Project: w.Project, + RawURL: url, + UserAgent: w.UserAgent, + }) +} + +func createNetworkConnectivityWaiter(config *transport_tpg.Config, op map[string]interface{}, project, activity, userAgent string) (*NetworkConnectivityOperationWaiter, error) { + w := &NetworkConnectivityOperationWaiter{ + Config: config, + UserAgent: userAgent, + Project: project, + } + if err := w.CommonOperationWaiter.SetOp(op); err != nil { + return nil, err + } + return w, nil +} + +func NetworkConnectivityOperationWaitTime(config *transport_tpg.Config, op map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error { + if val, ok := op["name"]; !ok || val == "" { + // This was a synchronous call - there is no operation to wait for. + return nil + } + w, err := createNetworkConnectivityWaiter(config, op, project, activity, userAgent) + if err != nil { + // If w is nil, the op was synchronous. + return err + } + return tpgresource.OperationWait(w, activity, timeout, config.PollInterval) +} diff --git a/google/services/networkconnectivity/resource_network_connectivity_service_connection_policy.go b/google/services/networkconnectivity/resource_network_connectivity_service_connection_policy.go new file mode 100644 index 00000000000..7c131401b3d --- /dev/null +++ b/google/services/networkconnectivity/resource_network_connectivity_service_connection_policy.go @@ -0,0 +1,626 @@ +// 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 networkconnectivity + +import ( + "fmt" + "log" + "reflect" + "strings" + "time" + + "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" +) + +func ResourceNetworkConnectivityServiceConnectionPolicy() *schema.Resource { + return &schema.Resource{ + Create: resourceNetworkConnectivityServiceConnectionPolicyCreate, + Read: resourceNetworkConnectivityServiceConnectionPolicyRead, + Update: resourceNetworkConnectivityServiceConnectionPolicyUpdate, + Delete: resourceNetworkConnectivityServiceConnectionPolicyDelete, + + Importer: &schema.ResourceImporter{ + State: resourceNetworkConnectivityServiceConnectionPolicyImport, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "location": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The location of the ServiceConnectionPolicy.`, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The name of a ServiceConnectionPolicy. Format: projects/{project}/locations/{location}/serviceConnectionPolicies/{service_connection_policy} See: https://google.aip.dev/122#fields-representing-resource-names`, + }, + "network": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The resource path of the consumer network. Example: - projects/{projectNumOrId}/global/networks/{resourceId}.`, + }, + "service_class": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The service class identifier for which this ServiceConnectionPolicy is for. The service class identifier is a unique, symbolic representation of a ServiceClass. +It is provided by the Service Producer. Google services have a prefix of gcp. For example, gcp-cloud-sql. 3rd party services do not. For example, test-service-a3dfcx.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `Free-text description of the resource.`, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `User-defined labels.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "psc_config": { + Type: schema.TypeList, + Optional: true, + Description: `Configuration used for Private Service Connect connections. Used when Infrastructure is PSC.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subnetworks": { + Type: schema.TypeList, + Required: true, + Description: `IDs of the subnetworks or fully qualified identifiers for the subnetworks`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "limit": { + Type: schema.TypeString, + Optional: true, + Description: `Max number of PSC connections for this policy.`, + }, + }, + }, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `The timestamp when the resource was created.`, + }, + "etag": { + Type: schema.TypeString, + Computed: true, + Description: `The etag is computed by the server, and may be sent on update and delete requests to ensure the client has an up-to-date value before proceeding.`, + }, + "infrastructure": { + Type: schema.TypeString, + Computed: true, + Description: `The type of underlying resources used to create the connection.`, + }, + "psc_connections": { + Type: schema.TypeList, + Computed: true, + Description: `Information about each Private Service Connect connection.`, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + Description: `The timestamp when the resource was updated.`, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + UseJSONNumber: true, + } +} + +func resourceNetworkConnectivityServiceConnectionPolicyCreate(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{}) + serviceClassProp, err := expandNetworkConnectivityServiceConnectionPolicyServiceClass(d.Get("service_class"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("service_class"); !tpgresource.IsEmptyValue(reflect.ValueOf(serviceClassProp)) && (ok || !reflect.DeepEqual(v, serviceClassProp)) { + obj["serviceClass"] = serviceClassProp + } + descriptionProp, err := expandNetworkConnectivityServiceConnectionPolicyDescription(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 + } + networkProp, err := expandNetworkConnectivityServiceConnectionPolicyNetwork(d.Get("network"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("network"); !tpgresource.IsEmptyValue(reflect.ValueOf(networkProp)) && (ok || !reflect.DeepEqual(v, networkProp)) { + obj["network"] = networkProp + } + pscConfigProp, err := expandNetworkConnectivityServiceConnectionPolicyPscConfig(d.Get("psc_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("psc_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(pscConfigProp)) && (ok || !reflect.DeepEqual(v, pscConfigProp)) { + obj["pscConfig"] = pscConfigProp + } + etagProp, err := expandNetworkConnectivityServiceConnectionPolicyEtag(d.Get("etag"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("etag"); !tpgresource.IsEmptyValue(reflect.ValueOf(etagProp)) && (ok || !reflect.DeepEqual(v, etagProp)) { + obj["etag"] = etagProp + } + labelsProp, err := expandNetworkConnectivityServiceConnectionPolicyLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(labelsProp)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + url, err := tpgresource.ReplaceVars(d, config, "{{NetworkConnectivityBasePath}}projects/{{project}}/locations/{{location}}/serviceConnectionPolicies?serviceConnectionPolicyId={{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Creating new ServiceConnectionPolicy: %#v", obj) + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for ServiceConnectionPolicy: %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 ServiceConnectionPolicy: %s", err) + } + + // Store the ID now + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}") + if err != nil { + return fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + err = NetworkConnectivityOperationWaitTime( + config, res, project, "Creating ServiceConnectionPolicy", userAgent, + d.Timeout(schema.TimeoutCreate)) + + if err != nil { + // The resource didn't actually create + d.SetId("") + return fmt.Errorf("Error waiting to create ServiceConnectionPolicy: %s", err) + } + + log.Printf("[DEBUG] Finished creating ServiceConnectionPolicy %q: %#v", d.Id(), res) + + return resourceNetworkConnectivityServiceConnectionPolicyRead(d, meta) +} + +func resourceNetworkConnectivityServiceConnectionPolicyRead(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, "{{NetworkConnectivityBasePath}}projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for ServiceConnectionPolicy: %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("NetworkConnectivityServiceConnectionPolicy %q", d.Id())) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + + if err := d.Set("create_time", flattenNetworkConnectivityServiceConnectionPolicyCreateTime(res["createTime"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("update_time", flattenNetworkConnectivityServiceConnectionPolicyUpdateTime(res["updateTime"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("service_class", flattenNetworkConnectivityServiceConnectionPolicyServiceClass(res["serviceClass"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("description", flattenNetworkConnectivityServiceConnectionPolicyDescription(res["description"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("network", flattenNetworkConnectivityServiceConnectionPolicyNetwork(res["network"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("psc_config", flattenNetworkConnectivityServiceConnectionPolicyPscConfig(res["pscConfig"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("etag", flattenNetworkConnectivityServiceConnectionPolicyEtag(res["etag"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("psc_connections", flattenNetworkConnectivityServiceConnectionPolicyPscConnections(res["pscConnections"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("infrastructure", flattenNetworkConnectivityServiceConnectionPolicyInfrastructure(res["infrastructure"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + if err := d.Set("labels", flattenNetworkConnectivityServiceConnectionPolicyLabels(res["labels"], d, config)); err != nil { + return fmt.Errorf("Error reading ServiceConnectionPolicy: %s", err) + } + + return nil +} + +func resourceNetworkConnectivityServiceConnectionPolicyUpdate(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 ServiceConnectionPolicy: %s", err) + } + billingProject = project + + obj := make(map[string]interface{}) + descriptionProp, err := expandNetworkConnectivityServiceConnectionPolicyDescription(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 + } + pscConfigProp, err := expandNetworkConnectivityServiceConnectionPolicyPscConfig(d.Get("psc_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("psc_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, pscConfigProp)) { + obj["pscConfig"] = pscConfigProp + } + etagProp, err := expandNetworkConnectivityServiceConnectionPolicyEtag(d.Get("etag"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("etag"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, etagProp)) { + obj["etag"] = etagProp + } + labelsProp, err := expandNetworkConnectivityServiceConnectionPolicyLabels(d.Get("labels"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("labels"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, labelsProp)) { + obj["labels"] = labelsProp + } + + obj, err = resourceNetworkConnectivityServiceConnectionPolicyUpdateEncoder(d, meta, obj) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{NetworkConnectivityBasePath}}projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}") + if err != nil { + return err + } + + log.Printf("[DEBUG] Updating ServiceConnectionPolicy %q: %#v", d.Id(), obj) + updateMask := []string{} + + if d.HasChange("description") { + updateMask = append(updateMask, "description") + } + + if d.HasChange("psc_config") { + updateMask = append(updateMask, "pscConfig") + } + + if d.HasChange("etag") { + updateMask = append(updateMask, "etag") + } + + if d.HasChange("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 + } + + 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 ServiceConnectionPolicy %q: %s", d.Id(), err) + } else { + log.Printf("[DEBUG] Finished updating ServiceConnectionPolicy %q: %#v", d.Id(), res) + } + + err = NetworkConnectivityOperationWaitTime( + config, res, project, "Updating ServiceConnectionPolicy", userAgent, + d.Timeout(schema.TimeoutUpdate)) + + if err != nil { + return err + } + + return resourceNetworkConnectivityServiceConnectionPolicyRead(d, meta) +} + +func resourceNetworkConnectivityServiceConnectionPolicyDelete(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 ServiceConnectionPolicy: %s", err) + } + billingProject = project + + url, err := tpgresource.ReplaceVars(d, config, "{{NetworkConnectivityBasePath}}projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}") + if err != nil { + return err + } + + var obj map[string]interface{} + log.Printf("[DEBUG] Deleting ServiceConnectionPolicy %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, "ServiceConnectionPolicy") + } + + err = NetworkConnectivityOperationWaitTime( + config, res, project, "Deleting ServiceConnectionPolicy", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting ServiceConnectionPolicy %q: %#v", d.Id(), res) + return nil +} + +func resourceNetworkConnectivityServiceConnectionPolicyImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + config := meta.(*transport_tpg.Config) + if err := tpgresource.ParseImportId([]string{ + "projects/(?P[^/]+)/locations/(?P[^/]+)/serviceConnectionPolicies/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)/(?P[^/]+)", + "(?P[^/]+)/(?P[^/]+)", + }, d, config); err != nil { + return nil, err + } + + // Replace import id for the resource id + id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}") + if err != nil { + return nil, fmt.Errorf("Error constructing id: %s", err) + } + d.SetId(id) + + return []*schema.ResourceData{d}, nil +} + +func flattenNetworkConnectivityServiceConnectionPolicyCreateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyUpdateTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyServiceClass(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyNetwork(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyPscConfig(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["subnetworks"] = + flattenNetworkConnectivityServiceConnectionPolicyPscConfigSubnetworks(original["subnetworks"], d, config) + transformed["limit"] = + flattenNetworkConnectivityServiceConnectionPolicyPscConfigLimit(original["limit"], d, config) + return []interface{}{transformed} +} +func flattenNetworkConnectivityServiceConnectionPolicyPscConfigSubnetworks(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyPscConfigLimit(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyEtag(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyPscConnections(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyInfrastructure(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenNetworkConnectivityServiceConnectionPolicyLabels(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func expandNetworkConnectivityServiceConnectionPolicyServiceClass(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetworkConnectivityServiceConnectionPolicyDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetworkConnectivityServiceConnectionPolicyNetwork(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetworkConnectivityServiceConnectionPolicyPscConfig(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedSubnetworks, err := expandNetworkConnectivityServiceConnectionPolicyPscConfigSubnetworks(original["subnetworks"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedSubnetworks); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["subnetworks"] = transformedSubnetworks + } + + transformedLimit, err := expandNetworkConnectivityServiceConnectionPolicyPscConfigLimit(original["limit"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLimit); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["limit"] = transformedLimit + } + + return transformed, nil +} + +func expandNetworkConnectivityServiceConnectionPolicyPscConfigSubnetworks(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetworkConnectivityServiceConnectionPolicyPscConfigLimit(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetworkConnectivityServiceConnectionPolicyEtag(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandNetworkConnectivityServiceConnectionPolicyLabels(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 resourceNetworkConnectivityServiceConnectionPolicyUpdateEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) { + obj["network"] = d.Get("network").(string) + return obj, nil +} diff --git a/google/services/networkconnectivity/resource_network_connectivity_service_connection_policy_sweeper.go b/google/services/networkconnectivity/resource_network_connectivity_service_connection_policy_sweeper.go new file mode 100644 index 00000000000..e4ba4f6649e --- /dev/null +++ b/google/services/networkconnectivity/resource_network_connectivity_service_connection_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 networkconnectivity + +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("NetworkConnectivityServiceConnectionPolicy", testSweepNetworkConnectivityServiceConnectionPolicy) +} + +// At the time of writing, the CI only passes us-central1 as the region +func testSweepNetworkConnectivityServiceConnectionPolicy(region string) error { + resourceName := "NetworkConnectivityServiceConnectionPolicy" + 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://networkconnectivity.googleapis.com/v1/projects/{{project}}/locations/{{location}}/serviceConnectionPolicies", "?")[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["serviceConnectionPolicies"] + 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://networkconnectivity.googleapis.com/v1/projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}" + deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) + return nil + } + deleteUrl = deleteUrl + name + + // Don't wait on operations as we may have a lot to delete + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: config.Project, + RawURL: deleteUrl, + UserAgent: config.UserAgent, + }) + if err != nil { + log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) + } else { + log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) + } + } + + if nonPrefixCount > 0 { + log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) + } + + return nil +} diff --git a/google/transport/config.go b/google/transport/config.go index 6efa055ec64..df668a3654f 100644 --- a/google/transport/config.go +++ b/google/transport/config.go @@ -249,6 +249,7 @@ type Config struct { MemcacheBasePath string MLEngineBasePath string MonitoringBasePath string + NetworkConnectivityBasePath string NetworkManagementBasePath string NetworkSecurityBasePath string NetworkServicesBasePath string @@ -363,6 +364,7 @@ const LookerBasePathKey = "Looker" const MemcacheBasePathKey = "Memcache" const MLEngineBasePathKey = "MLEngine" const MonitoringBasePathKey = "Monitoring" +const NetworkConnectivityBasePathKey = "NetworkConnectivity" const NetworkManagementBasePathKey = "NetworkManagement" const NetworkSecurityBasePathKey = "NetworkSecurity" const NetworkServicesBasePathKey = "NetworkServices" @@ -471,6 +473,7 @@ var DefaultBasePaths = map[string]string{ MemcacheBasePathKey: "https://memcache.googleapis.com/v1/", MLEngineBasePathKey: "https://ml.googleapis.com/v1/", MonitoringBasePathKey: "https://monitoring.googleapis.com/", + NetworkConnectivityBasePathKey: "https://networkconnectivity.googleapis.com/v1/", NetworkManagementBasePathKey: "https://networkmanagement.googleapis.com/v1/", NetworkSecurityBasePathKey: "https://networksecurity.googleapis.com/v1/", NetworkServicesBasePathKey: "https://networkservices.googleapis.com/v1/", @@ -910,6 +913,11 @@ func HandleSDKDefaults(d *schema.ResourceData) error { "GOOGLE_MONITORING_CUSTOM_ENDPOINT", }, DefaultBasePaths[MonitoringBasePathKey])) } + if d.Get("network_connectivity_custom_endpoint") == "" { + d.Set("network_connectivity_custom_endpoint", MultiEnvDefault([]string{ + "GOOGLE_NETWORK_CONNECTIVITY_CUSTOM_ENDPOINT", + }, DefaultBasePaths[NetworkConnectivityBasePathKey])) + } if d.Get("network_management_custom_endpoint") == "" { d.Set("network_management_custom_endpoint", MultiEnvDefault([]string{ "GOOGLE_NETWORK_MANAGEMENT_CUSTOM_ENDPOINT", @@ -1947,6 +1955,7 @@ func ConfigureBasePaths(c *Config) { c.MemcacheBasePath = DefaultBasePaths[MemcacheBasePathKey] c.MLEngineBasePath = DefaultBasePaths[MLEngineBasePathKey] c.MonitoringBasePath = DefaultBasePaths[MonitoringBasePathKey] + c.NetworkConnectivityBasePath = DefaultBasePaths[NetworkConnectivityBasePathKey] c.NetworkManagementBasePath = DefaultBasePaths[NetworkManagementBasePathKey] c.NetworkSecurityBasePath = DefaultBasePaths[NetworkSecurityBasePathKey] c.NetworkServicesBasePath = DefaultBasePaths[NetworkServicesBasePathKey] diff --git a/google/transport/provider_dcl_endpoints.go b/google/transport/provider_dcl_endpoints.go index 19785b85c32..a52b95541fe 100644 --- a/google/transport/provider_dcl_endpoints.go +++ b/google/transport/provider_dcl_endpoints.go @@ -69,12 +69,6 @@ var FirebaserulesEndpointEntry = &schema.Schema{ Optional: true, } -var NetworkConnectivityEndpointEntryKey = "network_connectivity_custom_endpoint" -var NetworkConnectivityEndpointEntry = &schema.Schema{ - Type: schema.TypeString, - Optional: true, -} - var OrgPolicyEndpointEntryKey = "org_policy_custom_endpoint" var OrgPolicyEndpointEntry = &schema.Schema{ Type: schema.TypeString, @@ -95,7 +89,6 @@ type DCLConfig struct { CloudResourceManagerBasePath string EventarcBasePath string FirebaserulesBasePath string - NetworkConnectivityBasePath string OrgPolicyBasePath string RecaptchaEnterpriseBasePath string } @@ -108,7 +101,6 @@ func ConfigureDCLProvider(provider *schema.Provider) { provider.Schema[CloudResourceManagerEndpointEntryKey] = CloudResourceManagerEndpointEntry provider.Schema[EventarcEndpointEntryKey] = EventarcEndpointEntry provider.Schema[FirebaserulesEndpointEntryKey] = FirebaserulesEndpointEntry - provider.Schema[NetworkConnectivityEndpointEntryKey] = NetworkConnectivityEndpointEntry provider.Schema[OrgPolicyEndpointEntryKey] = OrgPolicyEndpointEntry provider.Schema[RecaptchaEnterpriseEndpointEntryKey] = RecaptchaEnterpriseEndpointEntry } @@ -149,11 +141,6 @@ func HandleDCLCustomEndpointDefaults(d *schema.ResourceData) { "GOOGLE_FIREBASERULES_CUSTOM_ENDPOINT", }, "")) } - if d.Get(NetworkConnectivityEndpointEntryKey) == "" { - d.Set(NetworkConnectivityEndpointEntryKey, MultiEnvDefault([]string{ - "GOOGLE_NETWORK_CONNECTIVITY_CUSTOM_ENDPOINT", - }, "")) - } if d.Get(OrgPolicyEndpointEntryKey) == "" { d.Set(OrgPolicyEndpointEntryKey, MultiEnvDefault([]string{ "GOOGLE_ORG_POLICY_CUSTOM_ENDPOINT", @@ -210,12 +197,6 @@ func ConfigureDCLCustomEndpointAttributesFramework(frameworkSchema *framework_sc CustomEndpointValidator(), }, } - frameworkSchema.Attributes["network_connectivity_custom_endpoint"] = framework_schema.StringAttribute{ - Optional: true, - Validators: []validator.String{ - CustomEndpointValidator(), - }, - } frameworkSchema.Attributes["org_policy_custom_endpoint"] = framework_schema.StringAttribute{ Optional: true, Validators: []validator.String{ @@ -238,7 +219,6 @@ func ProviderDCLConfigure(d *schema.ResourceData, config *Config) interface{} { config.CloudResourceManagerBasePath = d.Get(CloudResourceManagerEndpointEntryKey).(string) config.EventarcBasePath = d.Get(EventarcEndpointEntryKey).(string) config.FirebaserulesBasePath = d.Get(FirebaserulesEndpointEntryKey).(string) - config.NetworkConnectivityBasePath = d.Get(NetworkConnectivityEndpointEntryKey).(string) config.OrgPolicyBasePath = d.Get(OrgPolicyEndpointEntryKey).(string) config.RecaptchaEnterpriseBasePath = d.Get(RecaptchaEnterpriseEndpointEntryKey).(string) config.CloudBuildWorkerPoolBasePath = d.Get(CloudBuildWorkerPoolEndpointEntryKey).(string) diff --git a/website/docs/r/network_connectivity_service_connection_policy.html.markdown b/website/docs/r/network_connectivity_service_connection_policy.html.markdown new file mode 100644 index 00000000000..ccb957ee7fa --- /dev/null +++ b/website/docs/r/network_connectivity_service_connection_policy.html.markdown @@ -0,0 +1,162 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This file is automatically generated by Magic Modules and manual +# changes will be clobbered when the file is regenerated. +# +# Please read more about how to change this file in +# .github/CONTRIBUTING.md. +# +# ---------------------------------------------------------------------------- +subcategory: "Network Connectivity" +description: |- + Manage Service Connection Policies. +--- + +# google\_network\_connectivity\_service\_connection\_policy + +Manage Service Connection Policies. + + +To get more information about ServiceConnectionPolicy, see: + +* [API documentation](https://cloud.google.com/secure-web-proxy/docs/reference/networkconnectivity/rest/v1/projects.locations.networkConnectionPolicies) +* How-to Guides + * [About Service Connection Policies](https://cloud.google.com/vpc/docs/about-service-connection-policies#service-policies) + + +## Example Usage - Network Connectivity Policy Basic + + +```hcl +resource "google_compute_network" "producer_net" { + name = "producer-net" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "producer_subnet" { + name = "producer-subnet" + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" + network = google_compute_network.producer_net.id +} + +resource "google_network_connectivity_service_connection_policy" "default" { + name = "my-network-connectivity-policy" + location = "us-central1" + service_class = "my-basic-service-class" + description = "my basic service connection policy" + network = google_compute_network.producer_net.id + psc_config { + subnetworks = [google_compute_subnetwork.producer_subnet.id] + limit = 2 + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `service_class` - + (Required) + The service class identifier for which this ServiceConnectionPolicy is for. The service class identifier is a unique, symbolic representation of a ServiceClass. + It is provided by the Service Producer. Google services have a prefix of gcp. For example, gcp-cloud-sql. 3rd party services do not. For example, test-service-a3dfcx. + +* `network` - + (Required) + The resource path of the consumer network. Example: - projects/{projectNumOrId}/global/networks/{resourceId}. + +* `name` - + (Required) + The name of a ServiceConnectionPolicy. Format: projects/{project}/locations/{location}/serviceConnectionPolicies/{service_connection_policy} See: https://google.aip.dev/122#fields-representing-resource-names + +* `location` - + (Required) + The location of the ServiceConnectionPolicy. + + +- - - + + +* `description` - + (Optional) + Free-text description of the resource. + +* `psc_config` - + (Optional) + Configuration used for Private Service Connect connections. Used when Infrastructure is PSC. + Structure is [documented below](#nested_psc_config). + +* `labels` - + (Optional) + User-defined labels. + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the provider project is used. + + +The `psc_config` block supports: + +* `subnetworks` - + (Required) + IDs of the subnetworks or fully qualified identifiers for the subnetworks + +* `limit` - + (Optional) + Max number of PSC connections for this policy. + +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are exported: + +* `id` - an identifier for the resource with format `projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}}` + +* `create_time` - + The timestamp when the resource was created. + +* `update_time` - + The timestamp when the resource was updated. + +* `etag` - + The etag is computed by the server, and may be sent on update and delete requests to ensure the client has an up-to-date value before proceeding. + +* `psc_connections` - + Information about each Private Service Connect connection. + +* `infrastructure` - + The type of underlying resources used to create the connection. + + +## Timeouts + +This resource provides the following +[Timeouts](https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/retries-and-customizable-timeouts) configuration options: + +- `create` - Default is 30 minutes. +- `update` - Default is 30 minutes. +- `delete` - Default is 30 minutes. + +## Import + + +ServiceConnectionPolicy can be imported using any of these accepted formats: + +``` +$ terraform import google_network_connectivity_service_connection_policy.default projects/{{project}}/locations/{{location}}/serviceConnectionPolicies/{{name}} +$ terraform import google_network_connectivity_service_connection_policy.default {{project}}/{{location}}/{{name}} +$ terraform import google_network_connectivity_service_connection_policy.default {{location}}/{{name}} +``` + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).