From e9d01d6c775cdf179c930d308fd65b81ea70b8b0 Mon Sep 17 00:00:00 2001 From: The Magician Date: Wed, 7 Aug 2024 14:35:44 -0700 Subject: [PATCH] Add a flag to use patch when creating a service networking connection fails (#11364) (#7915) [upstream:6af157ec0f4671062b20902414b20d30b0390f63] Signed-off-by: Modular Magician --- .changelog/11364.txt | 3 + .../resource_service_networking_connection.go | 21 ++++- ...urce_service_networking_connection_test.go | 88 +++++++++++++++++++ ...ervice_networking_connection.html.markdown | 2 + 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 .changelog/11364.txt diff --git a/.changelog/11364.txt b/.changelog/11364.txt new file mode 100644 index 0000000000..3a28cb6a0b --- /dev/null +++ b/.changelog/11364.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +servicenetworking: added `update_on_creation_fail` field to `google_service_networking_connection` resource. When it is set to true, enforce an update of the reserved peering ranges on the existing service networking connection in case of a new connection creation failure. +``` \ No newline at end of file diff --git a/google-beta/services/servicenetworking/resource_service_networking_connection.go b/google-beta/services/servicenetworking/resource_service_networking_connection.go index cb66bf7c50..075462ec59 100644 --- a/google-beta/services/servicenetworking/resource_service_networking_connection.go +++ b/google-beta/services/servicenetworking/resource_service_networking_connection.go @@ -71,6 +71,11 @@ func ResourceServiceNetworkingConnection() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "update_on_creation_fail": { + Type: schema.TypeBool, + Optional: true, + Description: `When set to true, enforce an update of the reserved peering ranges on the existing service networking connection in case of a new connection creation failure.`, + }, }, UseJSONNumber: true, } @@ -120,7 +125,21 @@ func resourceServiceNetworkingConnectionCreate(d *schema.ResourceData, meta inte } if err := ServiceNetworkingOperationWaitTimeHW(config, op, "Create Service Networking Connection", userAgent, project, d.Timeout(schema.TimeoutCreate)); err != nil { - return err + if strings.Contains(err.Error(), "Cannot modify allocated ranges in CreateConnection.") && d.Get("update_on_creation_fail").(bool) { + patchCall := config.NewServiceNetworkingClient(userAgent).Services.Connections.Patch(parentService+"/connections/-", connection).UpdateMask("reservedPeeringRanges").Force(true) + if config.UserProjectOverride { + patchCall.Header().Add("X-Goog-User-Project", project) + } + op, err := patchCall.Do() + if err != nil { + return err + } + if err := ServiceNetworkingOperationWaitTimeHW(config, op, "Update Service Networking Connection", userAgent, project, d.Timeout(schema.TimeoutUpdate)); err != nil { + return err + } + } else { + return err + } } connectionId := &connectionId{ diff --git a/google-beta/services/servicenetworking/resource_service_networking_connection_test.go b/google-beta/services/servicenetworking/resource_service_networking_connection_test.go index e9bae696a0..97cb0b8e5a 100644 --- a/google-beta/services/servicenetworking/resource_service_networking_connection_test.go +++ b/google-beta/services/servicenetworking/resource_service_networking_connection_test.go @@ -4,6 +4,7 @@ package servicenetworking_test import ( "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -64,6 +65,38 @@ func TestAccServiceNetworkingConnection_abandon(t *testing.T) { }) } +func TestAccServiceNetworkingConnection_updateOnCreationFail(t *testing.T) { + t.Parallel() + + network := fmt.Sprintf("tf-test-service-networking-connection-update-%s", acctest.RandString(t, 10)) + addr1 := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + addr2 := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + service := "servicenetworking.googleapis.com" + org_id := envvar.GetTestOrgFromEnv(t) + billing_account := envvar.GetTestBillingAccountFromEnv(t) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testServiceNetworkingConnectionDestroy(t, service, network), + Steps: []resource.TestStep{ + { + Config: testAccServiceNetworkingConnections(network, addr1, addr2, "servicenetworking.googleapis.com", org_id, billing_account, false), + ExpectError: regexp.MustCompile("Cannot modify allocated ranges in CreateConnection. Please use UpdateConnection"), + }, + { + Config: testAccServiceNetworkingConnections(network, addr1, addr2, "servicenetworking.googleapis.com", org_id, billing_account, true), + // google_service_networking_connection.foobar and google_service_networking_connection.foobar1 are the same service networking connection + // as they have the same network and service. When update_on_creation_fail is set to true, the service networking connection is updated + // with peering range google_compute_global_address.foobar1 successfully through google_service_networking_connection.foobar1. + // After refresh, google_service_networking_connection.foobar will also have the updated peering range google_compute_global_address.foobar1, so the plan is not empty. + ExpectNonEmptyPlan: true, + }, + }, + }) + +} + func TestAccServiceNetworkingConnection_update(t *testing.T) { t.Parallel() @@ -185,6 +218,61 @@ resource "google_service_networking_connection" "foobar" { `, addressRangeName, addressRangeName, org_id, billing_account, networkName, addressRangeName, serviceName) } +func testAccServiceNetworkingConnections(networkName, addressRangeName, addressRangeName1, serviceName, org_id, billing_account string, update_on_creation_fail bool) string { + return fmt.Sprintf(` +resource "google_project" "project" { + project_id = "%s" + name = "%s" + org_id = "%s" + billing_account = "%s" +} + +resource "google_project_service" "servicenetworking" { + project = google_project.project.project_id + service = "servicenetworking.googleapis.com" +} + +resource "google_compute_network" "servicenet" { + name = "%s" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_global_address" "foobar" { + name = "%s" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.servicenet.self_link + depends_on = [google_project_service.servicenetworking] +} + +resource "google_compute_global_address" "foobar1" { + name = "%s" + purpose = "VPC_PEERING" + address_type = "INTERNAL" + prefix_length = 16 + network = google_compute_network.servicenet.self_link + depends_on = [google_project_service.servicenetworking] +} + +resource "google_service_networking_connection" "foobar" { + network = google_compute_network.servicenet.self_link + service = "%s" + reserved_peering_ranges = [google_compute_global_address.foobar.name] + deletion_policy = "ABANDON" + depends_on = [google_project_service.servicenetworking] +} + +resource "google_service_networking_connection" "foobar1" { + network = google_compute_network.servicenet.self_link + service = "%s" + reserved_peering_ranges = [google_compute_global_address.foobar1.name] + update_on_creation_fail = "%t" + depends_on = [google_service_networking_connection.foobar] +} +`, addressRangeName, addressRangeName, org_id, billing_account, networkName, addressRangeName, addressRangeName1, serviceName, serviceName, update_on_creation_fail) +} + func testAccServiceNetworkingConnectionToBeAbandoned(networkName, addressRangeName, serviceName, org_id, billing_account string) string { return fmt.Sprintf(` resource "google_project" "project" { diff --git a/website/docs/r/service_networking_connection.html.markdown b/website/docs/r/service_networking_connection.html.markdown index 04ad2d747d..78af668080 100644 --- a/website/docs/r/service_networking_connection.html.markdown +++ b/website/docs/r/service_networking_connection.html.markdown @@ -61,6 +61,8 @@ The following arguments are supported: * `deletion_policy` - (Optional) The deletion policy for the service networking connection. Setting to ABANDON allows the resource to be abandoned rather than deleted. This will enable a successful terraform destroy when destroying CloudSQL instances. Use with care as it can lead to dangling resources. +* `update_on_creation_fail` - (Optional) When set to true, enforce an update of the reserved peering ranges on the existing service networking connection in case of a new connection creation failure. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: