Skip to content

Commit

Permalink
Add disable_dependent_services to google_project_service resource.
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <[email protected]>
  • Loading branch information
rileykarson authored and modular-magician committed Jan 25, 2019
1 parent d1f1222 commit 178260b
Show file tree
Hide file tree
Showing 9 changed files with 593 additions and 295 deletions.
4 changes: 2 additions & 2 deletions google/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import (
redis "google.golang.org/api/redis/v1beta1"
runtimeconfig "google.golang.org/api/runtimeconfig/v1beta1"
"google.golang.org/api/servicemanagement/v1"
serviceusage "google.golang.org/api/serviceusage/v1beta1"
"google.golang.org/api/serviceusage/v1"
"google.golang.org/api/sourcerepo/v1"
"google.golang.org/api/spanner/v1"
sqladmin "google.golang.org/api/sqladmin/v1beta4"
Expand Down Expand Up @@ -86,7 +86,7 @@ type Config struct {
clientSqlAdmin *sqladmin.Service
clientIAM *iam.Service
clientServiceMan *servicemanagement.APIService
clientServiceUsage *serviceusage.APIService
clientServiceUsage *serviceusage.Service
clientBigQuery *bigquery.Service
clientCloudFunctions *cloudfunctions.Service
clientCloudIoT *cloudiot.Service
Expand Down
8 changes: 7 additions & 1 deletion google/resource_google_project_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ func resourceGoogleProjectService() *schema.Resource {
Computed: true,
ForceNew: true,
},

"disable_dependent_services": {
Type: schema.TypeBool,
Optional: true,
},

"disable_on_destroy": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -120,7 +126,7 @@ func resourceGoogleProjectServiceDelete(d *schema.ResourceData, meta interface{}
return nil
}

if err = disableService(id.service, id.project, config); err != nil {
if err = disableService(id.service, id.project, config, d.Get("disable_dependent_services").(bool)); err != nil {
return fmt.Errorf("Error disabling service: %s", err)
}

Expand Down
77 changes: 77 additions & 0 deletions google/resource_google_project_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package google

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
Expand Down Expand Up @@ -63,6 +64,46 @@ func TestAccProjectService_basic(t *testing.T) {
})
}

func TestAccProjectService_disableDependentServices(t *testing.T) {
t.Parallel()

org := getTestOrgFromEnv(t)
pid := "terraform-" + acctest.RandString(10)
services := []string{"cloudbuild.googleapis.com", "containerregistry.googleapis.com"}
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccProjectService_disableDependentServices(services, pid, pname, org, "false"),
},
{
ResourceName: "google_project_service.test",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"disable_on_destroy"},
},
{
Config: testAccProjectService_dependencyRemoved(services, pid, pname, org),
ExpectError: regexp.MustCompile("Please use disable_dependent_services flag if you want to proceed"),
},
{
Config: testAccProjectService_disableDependentServices(services, pid, pname, org, "true"),
},
{
ResourceName: "google_project_service.test",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"disable_on_destroy"},
},
{
Config: testAccProjectService_dependencyRemoved(services, pid, pname, org),
ExpectNonEmptyPlan: true,
},
},
})
}

func TestAccProjectService_handleNotFound(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -136,6 +177,42 @@ resource "google_project_service" "test2" {
`, pid, name, org, services[0], services[1])
}

func testAccProjectService_disableDependentServices(services []string, pid, name, org, disableDependentServices string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
}
resource "google_project_service" "test" {
project = "${google_project.acceptance.project_id}"
service = "%s"
}
resource "google_project_service" "test2" {
project = "${google_project.acceptance.project_id}"
service = "%s"
disable_dependent_services = %s
}
`, pid, name, org, services[0], services[1], disableDependentServices)
}

func testAccProjectService_dependencyRemoved(services []string, pid, name, org string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
}
resource "google_project_service" "test" {
project = "${google_project.acceptance.project_id}"
service = "%s"
}
`, pid, name, org, services[0])
}

func testAccProjectService_noDisable(services []string, pid, name, org string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
Expand Down
25 changes: 16 additions & 9 deletions google/resource_google_project_services.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import (
"context"
"fmt"
"log"
"sort"
"strings"

"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
"google.golang.org/api/googleapi"
"google.golang.org/api/serviceusage/v1beta1"
"google.golang.org/api/serviceusage/v1"
)

func resourceGoogleProjectServices() *schema.Resource {
Expand Down Expand Up @@ -129,7 +130,7 @@ func resourceGoogleProjectServicesDelete(d *schema.ResourceData, meta interface{
config := meta.(*Config)
services := resourceServices(d)
for _, s := range services {
disableService(s, d.Id(), config)
disableService(s, d.Id(), config, true)
}
d.SetId("")
return nil
Expand All @@ -148,19 +149,21 @@ func reconcileServices(cfgServices, apiServices []string, config *Config, pid st
return sm
}

sort.Strings(cfgServices)
cfgMap := m(cfgServices)
log.Printf("[DEBUG]: Saw the following services in config: %v", cfgServices)
apiMap := m(apiServices)
log.Printf("[DEBUG]: Saw the following services enabled: %v", apiServices)

for k := range apiMap {
if _, ok := cfgMap[k]; !ok {
// The service in the API is not in the config; disable it.
err := disableService(k, pid, config)
log.Printf("[DEBUG]: Disabling %s as it's enabled upstream but not in config", k)
err := disableService(k, pid, config, true)
if err != nil {
return err
}
} else {
// The service exists in the config and the API, so we don't need
// to re-enable it
log.Printf("[DEBUG]: Skipping %s as it's enabled in both config and upstream", k)
delete(cfgMap, k)
}
}
Expand All @@ -169,6 +172,8 @@ func reconcileServices(cfgServices, apiServices []string, config *Config, pid st
for k := range cfgMap {
keys = append(keys, k)
}
sort.Strings(keys)
log.Printf("[DEBUG]: Enabling the following services: %v", keys)
err := enableServices(keys, pid, config)
if err != nil {
return err
Expand Down Expand Up @@ -233,7 +238,7 @@ func enableServices(s []string, pid string, config *Config) error {
// It's not permitted to enable more than 20 services in one API call (even
// for batch).
//
// https://godoc.org/google.golang.org/api/serviceusage/v1beta1#BatchEnableServicesRequest
// https://godoc.org/google.golang.org/api/serviceusage/v1#BatchEnableServicesRequest
batchSize := 20

for i := 0; i < len(s); i += batchSize {
Expand Down Expand Up @@ -334,10 +339,12 @@ func diffStringSlice(wanted, actual []string) []string {
return missing
}

func disableService(s, pid string, config *Config) error {
func disableService(s, pid string, config *Config, disableDependentServices bool) error {
err := retryTime(func() error {
name := fmt.Sprintf("projects/%s/services/%s", pid, s)
sop, err := config.clientServiceUsage.Services.Disable(name, &serviceusage.DisableServiceRequest{}).Do()
sop, err := config.clientServiceUsage.Services.Disable(name, &serviceusage.DisableServiceRequest{
DisableDependentServices: disableDependentServices,
}).Do()
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions google/serviceusage_operation.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package google

import (
"google.golang.org/api/serviceusage/v1beta1"
"google.golang.org/api/serviceusage/v1"
)

type ServiceUsageOperationWaiter struct {
Service *serviceusage.APIService
Service *serviceusage.Service
CommonOperationWaiter
}

Expand Down
Loading

0 comments on commit 178260b

Please sign in to comment.