From 5ef128134c15614caae9a50011c093f09e15bd75 Mon Sep 17 00:00:00 2001 From: Dana Hoffman Date: Sat, 9 Nov 2019 00:35:30 +0000 Subject: [PATCH] batch serviceusage reads Signed-off-by: Modular Magician --- google/batcher.go | 5 ++- google/resource_google_project_service.go | 41 ++++------------------- google/serviceusage_batching.go | 23 +++++++++++++ 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/google/batcher.go b/google/batcher.go index 12a3ac88608..85aa0005cc3 100644 --- a/google/batcher.go +++ b/google/batcher.go @@ -6,6 +6,8 @@ import ( "log" "sync" "time" + + "github.com/hashicorp/errwrap" ) const defaultBatchSendIntervalSec = 10 @@ -154,7 +156,8 @@ func (b *RequestBatcher) SendRequestWithTimeout(batchKey string, request *BatchR select { case resp := <-respCh: if resp.err != nil { - return nil, fmt.Errorf("Batch %q for request %q returned error: %v", batchKey, request.DebugId, resp.err) + // use wrapf so we can potentially extract the original error type + return nil, errwrap.Wrapf(fmt.Sprintf("Batch %q for request %q returned error: {{err}}", batchKey, request.DebugId), resp.err) } return resp.body, nil case <-ctx.Done(): diff --git a/google/resource_google_project_service.go b/google/resource_google_project_service.go index 7e026db554f..86c06e6f07f 100644 --- a/google/resource_google_project_service.go +++ b/google/resource_google_project_service.go @@ -2,13 +2,12 @@ package google import ( "fmt" - "github.com/hashicorp/errwrap" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "google.golang.org/api/googleapi" - "google.golang.org/api/serviceusage/v1" "log" "strings" "time" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "google.golang.org/api/serviceusage/v1" ) var ignoredProjectServices = []string{"dataproc-control.googleapis.com", "source.googleapis.com", "stackdriverprovisioning.googleapis.com"} @@ -138,11 +137,13 @@ func resourceGoogleProjectServiceRead(d *schema.ResourceData, meta interface{}) } srv := d.Get("service").(string) - enabled, err := isServiceEnabled(project, srv, config) + servicesRaw, err := BatchRequestReadServices(project, d, config) if err != nil { return handleNotFoundError(err, d, fmt.Sprintf("Project Service %s", d.Id())) } - if enabled { + servicesList := servicesRaw.(map[string]struct{}) + + if _, ok := servicesList[srv]; ok { d.Set("project", project) d.Set("service", srv) return nil @@ -184,34 +185,6 @@ func resourceGoogleProjectServiceUpdate(d *schema.ResourceData, meta interface{} return nil } -// Retrieve enablement state for a given project's service -func isServiceEnabled(project, serviceName string, config *Config) (bool, error) { - // Verify project for services still exists - p, err := config.clientResourceManager.Projects.Get(project).Do() - if err != nil { - return false, err - } - if p.LifecycleState == "DELETE_REQUESTED" { - // Construct a 404 error for handleNotFoundError - return false, &googleapi.Error{ - Code: 404, - Message: "Project deletion was requested", - } - } - - resourceName := fmt.Sprintf("projects/%s/services/%s", project, serviceName) - var srv *serviceusage.GoogleApiServiceusageV1Service - err = retryTime(func() error { - var currErr error - srv, currErr = config.clientServiceUsage.Services.Get(resourceName).Do() - return currErr - }, 10) - if err != nil { - return false, errwrap.Wrapf(fmt.Sprintf("Failed to list enabled services for project %s: {{err}}", project), err) - } - return srv.State == "ENABLED", nil -} - // Disables a project service. func disableServiceUsageProjectService(service, project string, d *schema.ResourceData, config *Config, disableDependentServices bool) error { err := retryTimeDuration(func() error { diff --git a/google/serviceusage_batching.go b/google/serviceusage_batching.go index f0921c5be6b..8ec706db0a5 100644 --- a/google/serviceusage_batching.go +++ b/google/serviceusage_batching.go @@ -10,6 +10,7 @@ import ( const ( batchKeyTmplServiceUsageEnableServices = "project/%s/services:batchEnable" + batchKeyTmplServiceUsageListServices = "project/%s/services" ) // BatchRequestEnableServices can be used to batch requests to enable services @@ -53,6 +54,22 @@ func BatchRequestEnableServices(services map[string]struct{}, project string, d return err } +func BatchRequestReadServices(project string, d *schema.ResourceData, config *Config) (interface{}, error) { + req := &BatchRequest{ + ResourceName: project, + Body: nil, + // Use empty CombineF since the request is exactly the same no matter how many services we read. + CombineF: func(body interface{}, toAdd interface{}) (interface{}, error) { return nil, nil }, + SendF: sendListServices(config, d.Timeout(schema.TimeoutRead)), + DebugId: fmt.Sprintf("List Project Services %s", project), + } + + return config.requestBatcherServiceUsage.SendRequestWithTimeout( + fmt.Sprintf(batchKeyTmplServiceUsageListServices, project), + req, + d.Timeout(schema.TimeoutRead)) +} + func combineServiceUsageServicesBatches(srvsRaw interface{}, toAddRaw interface{}) (interface{}, error) { srvs, ok := srvsRaw.([]string) if !ok { @@ -75,3 +92,9 @@ func sendBatchFuncEnableServices(config *Config, timeout time.Duration) batcherS return nil, enableServiceUsageProjectServices(toEnable, project, config, timeout) } } + +func sendListServices(config *Config, timeout time.Duration) batcherSendFunc { + return func(project string, _ interface{}) (interface{}, error) { + return listCurrentlyEnabledServices(project, config, timeout) + } +}