From 791c5087557c7384c90ffdd56693731dcae9385b Mon Sep 17 00:00:00 2001 From: Paddy Carver Date: Thu, 20 Sep 2018 12:54:21 -0700 Subject: [PATCH] Check for project deletion when refreshing/deleting project_service. When reading or deleting the google_project_service resource, first retrieve the project. If it's not found, or if it's pending deletion, remove the service, as it's functionally disabled. Also, add a test to confirm the behaviour. This should resolve #1292. --- google/resource_google_project_service.go | 20 +++++++ .../resource_google_project_service_test.go | 55 +++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/google/resource_google_project_service.go b/google/resource_google_project_service.go index c0600160..d87db7cd 100644 --- a/google/resource_google_project_service.go +++ b/google/resource_google_project_service.go @@ -67,6 +67,16 @@ func resourceGoogleProjectServiceRead(d *schema.ResourceData, meta interface{}) return err } + project, err := config.clientResourceManager.Projects.Get(id.project).Do() + if err != nil { + return handleNotFoundError(err, d, id.project) + } + if project.LifecycleState == "DELETE_REQUESTED" { + log.Printf("[WARN] Removing %s from state, its project is deleted", id.terraformId()) + d.SetId("") + return nil + } + services, err := getApiServices(id.project, config, map[string]struct{}{}) if err != nil { return err @@ -100,6 +110,16 @@ func resourceGoogleProjectServiceDelete(d *schema.ResourceData, meta interface{} return err } + project, err := config.clientResourceManager.Projects.Get(id.project).Do() + if err != nil { + return handleNotFoundError(err, d, id.project) + } + if project.LifecycleState == "DELETE_REQUESTED" { + log.Printf("[WARN] Removing %s from state, its project is deleted", id.terraformId()) + d.SetId("") + return nil + } + if err = disableService(id.service, id.project, config); err != nil { return fmt.Errorf("Error disabling service: %s", err) } diff --git a/google/resource_google_project_service_test.go b/google/resource_google_project_service_test.go index 76e5a43c..8f4b0e08 100644 --- a/google/resource_google_project_service_test.go +++ b/google/resource_google_project_service_test.go @@ -63,6 +63,31 @@ func TestAccProjectService_basic(t *testing.T) { }) } +func TestAccProjectService_handleNotFound(t *testing.T) { + t.Parallel() + + org := getTestOrgFromEnv(t) + pid := "terraform-" + acctest.RandString(10) + service := "iam.googleapis.com" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccProjectService_handleNotFound(service, pid, pname, org), + Check: resource.ComposeTestCheckFunc( + testAccCheckProjectService([]string{service}, pid, true), + ), + }, + // Delete the project, implicitly deletes service, expect the plan to want to create the service again + resource.TestStep{ + Config: testAccProjectService_handleNotFoundNoProject(service, pid), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckProjectService(services []string, pid string, expectEnabled bool) resource.TestCheckFunc { return func(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -132,3 +157,33 @@ resource "google_project_service" "test2" { } `, pid, name, org, services[0], services[1]) } + +func testAccProjectService_handleNotFound(service, pid, name, org string) string { + return fmt.Sprintf(` +resource "google_project" "acceptance" { + project_id = "%s" + name = "%s" + org_id = "%s" +} + +// by passing through locals, we break the dependency chain +// see terraform-provider-google#1292 +locals { + project_id = "${google_project.acceptance.project_id}" +} + +resource "google_project_service" "test" { + project = "${local.project_id}" + service = "%s" +} +`, pid, name, org, service) +} + +func testAccProjectService_handleNotFoundNoProject(service, pid string) string { + return fmt.Sprintf(` +resource "google_project_service" "test" { + project = "%s" + service = "%s" +} +`, pid, service) +}