diff --git a/google/resource_compute_network.go b/google/resource_compute_network.go index 91c883ef..c615bc34 100644 --- a/google/resource_compute_network.go +++ b/google/resource_compute_network.go @@ -195,9 +195,12 @@ func resourceComputeNetworkDelete(d *schema.ResourceData, meta interface{}) erro return err } - // Delete the network + return deleteComputeNetwork(project, d.Id(), config) +} + +func deleteComputeNetwork(project, network string, config *Config) error { op, err := config.clientCompute.Networks.Delete( - project, d.Id()).Do() + project, network).Do() if err != nil { return fmt.Errorf("Error deleting network: %s", err) } @@ -206,7 +209,5 @@ func resourceComputeNetworkDelete(d *schema.ResourceData, meta interface{}) erro if err != nil { return err } - - d.SetId("") return nil } diff --git a/google/resource_google_project.go b/google/resource_google_project.go index 506e3d87..ea122f6d 100644 --- a/google/resource_google_project.go +++ b/google/resource_google_project.go @@ -151,15 +151,13 @@ func resourceGoogleProjectCreate(d *schema.ResourceData, meta interface{}) error // people if we don't have to. The GCP Console is doing the same thing - creating // a network and deleting it in the background. if !d.Get("auto_create_network").(bool) { - op, err := config.clientCompute.Networks.Delete( - project.Name, "default").Do() - if err != nil { - return fmt.Errorf("Error deleting network: %s", err) + // The compute API has to be enabled before we can delete a network. + if err = enableService("compute.googleapis.com", project.ProjectId, config); err != nil { + return fmt.Errorf("Error enabling the Compute Engine API required to delete the default network: %s", err) } - err = computeOperationWaitTime(config.clientCompute, op, project.Name, "Deleting Network", 10) - if err != nil { - return err + if err = forceDeleteComputeNetwork(project.ProjectId, "default", config); err != nil { + return fmt.Errorf("Error deleting default network in project %s: %s", project.ProjectId, err) } } return nil @@ -343,3 +341,35 @@ func resourceProjectImportState(d *schema.ResourceData, meta interface{}) ([]*sc d.Set("auto_create_network", true) return []*schema.ResourceData{d}, nil } + +// Delete a compute network along with the firewall rules inside it. +func forceDeleteComputeNetwork(projectId, networkName string, config *Config) error { + networkLink := fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/global/networks/%s", projectId, networkName) + + token := "" + for paginate := true; paginate; { + filter := fmt.Sprintf("network eq %s", networkLink) + resp, err := config.clientCompute.Firewalls.List(projectId).Filter(filter).Do() + if err != nil { + return fmt.Errorf("Error listing firewall rules in proj: %s", err) + } + + log.Printf("[DEBUG] Found %d firewall rules in %q network", len(resp.Items), networkName) + + for _, firewall := range resp.Items { + op, err := config.clientCompute.Firewalls.Delete(projectId, firewall.Name).Do() + if err != nil { + return fmt.Errorf("Error deleting firewall: %s", err) + } + err = computeSharedOperationWait(config.clientCompute, op, projectId, "Deleting Firewall") + if err != nil { + return err + } + } + + token = resp.NextPageToken + paginate = token != "" + } + + return deleteComputeNetwork(projectId, networkName, config) +} diff --git a/google/resource_google_project_test.go b/google/resource_google_project_test.go index 71c57a35..c38eec5d 100644 --- a/google/resource_google_project_test.go +++ b/google/resource_google_project_test.go @@ -153,6 +153,23 @@ func TestAccProject_labels(t *testing.T) { }) } +func TestAccProject_deleteDefaultNetwork(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "terraform-" + acctest.RandString(10) + billingId := getTestBillingAccountFromEnv(t) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccProject_deleteDefaultNetwork(pid, pname, org, billingId), + }, + }, + }) +} + func testAccCheckGoogleProjectExists(r, pid string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[r] @@ -286,6 +303,17 @@ resource "google_project" "acceptance" { return r + l } +func testAccProject_deleteDefaultNetwork(pid, name, org, billing string) string { + return fmt.Sprintf(` +resource "google_project" "acceptance" { + project_id = "%s" + name = "%s" + org_id = "%s" + billing_account = "%s" # requires billing to enable compute API + auto_create_network = false +}`, pid, name, org, billing) +} + func skipIfEnvNotSet(t *testing.T, envs ...string) { for _, k := range envs { if os.Getenv(k) == "" { diff --git a/website/docs/r/google_project.html.markdown b/website/docs/r/google_project.html.markdown index 0e9a77b2..a0193472 100755 --- a/website/docs/r/google_project.html.markdown +++ b/website/docs/r/google_project.html.markdown @@ -100,7 +100,8 @@ The following arguments are supported: * `auto_create_network` - (Optional) Create the 'default' network automatically. Default true. Note: this might be more accurately described as "Delete Default Network", since the network is created automatically then deleted before project creation returns, but we choose this - name to match the GCP Console UI. + name to match the GCP Console UI. Setting this field to false will enable the Compute Engine + API which is required to delete the network. ## Attributes Reference