From 1ceb0d5c83603838d70f13c37652b75f27fa2ec6 Mon Sep 17 00:00:00 2001 From: Chris Stephens Date: Thu, 19 Dec 2019 01:18:33 +0000 Subject: [PATCH] Allow GKE to resume create after interruption Signed-off-by: Modular Magician --- google/bootstrap_utils_test.go | 5 +- google/config.go | 78 +++++++++---------- google/config_test.go | 16 ++-- google/container_operation.go | 12 +++ google/provider.go | 6 +- google/resource_composer_environment_test.go | 3 +- .../resource_compute_instance_migrate_test.go | 3 +- google/resource_container_cluster.go | 30 +++++++ google/resource_container_cluster_test.go | 3 +- google/resource_monitoring_group_test.go | 3 +- google/resource_sql_database_instance_test.go | 3 +- 11 files changed, 105 insertions(+), 57 deletions(-) diff --git a/google/bootstrap_utils_test.go b/google/bootstrap_utils_test.go index 28c5319e98e..fcab7f2e1f5 100644 --- a/google/bootstrap_utils_test.go +++ b/google/bootstrap_utils_test.go @@ -1,6 +1,7 @@ package google import ( + "context" "fmt" "log" "os" @@ -73,7 +74,7 @@ func BootstrapKMSKeyWithPurposeInLocation(t *testing.T, purpose, locationID stri ConfigureBasePaths(config) - if err := config.LoadAndValidate(); err != nil { + if err := config.LoadAndValidate(context.Background()); err != nil { t.Errorf("Unable to bootstrap KMS key: %s", err) } @@ -213,7 +214,7 @@ func BootstrapServiceAccount(t *testing.T, project, testRunner string) string { ConfigureBasePaths(config) - if err := config.LoadAndValidate(); err != nil { + if err := config.LoadAndValidate(context.Background()); err != nil { t.Fatalf("Bootstrapping failed. Unable to load test config: %s", err) } diff --git a/google/config.go b/google/config.go index dcd689dee83..eb6261d3e82 100644 --- a/google/config.go +++ b/google/config.go @@ -66,6 +66,7 @@ type Config struct { RequestTimeout time.Duration client *http.Client + context context.Context terraformVersion string userAgent string @@ -243,7 +244,7 @@ var defaultClientScopes = []string{ "https://www.googleapis.com/auth/userinfo.email", } -func (c *Config) LoadAndValidate() error { +func (c *Config) LoadAndValidate(ctx context.Context) error { if len(c.Scopes) == 0 { c.Scopes = defaultClientScopes } @@ -264,10 +265,9 @@ func (c *Config) LoadAndValidate() error { userAgent := fmt.Sprintf("%s %s", tfUserAgent, providerVersion) c.client = client + c.context = ctx c.userAgent = userAgent - context := context.Background() - // This base path and some others below need the version and possibly more of the path // set on them. The client libraries are inconsistent about which values they need; // while most only want the host URL, some older ones also want the version and some @@ -275,7 +275,7 @@ func (c *Config) LoadAndValidate() error { // the basePath value in the client library file. computeClientBasePath := c.ComputeBasePath + "projects/" log.Printf("[INFO] Instantiating GCE client for path %s", computeClientBasePath) - c.clientCompute, err = compute.NewService(context, option.WithHTTPClient(client)) + c.clientCompute, err = compute.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -284,7 +284,7 @@ func (c *Config) LoadAndValidate() error { computeBetaClientBasePath := c.ComputeBetaBasePath + "projects/" log.Printf("[INFO] Instantiating GCE Beta client for path %s", computeBetaClientBasePath) - c.clientComputeBeta, err = computeBeta.NewService(context, option.WithHTTPClient(client)) + c.clientComputeBeta, err = computeBeta.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -293,7 +293,7 @@ func (c *Config) LoadAndValidate() error { containerClientBasePath := removeBasePathVersion(c.ContainerBasePath) log.Printf("[INFO] Instantiating GKE client for path %s", containerClientBasePath) - c.clientContainer, err = container.NewService(context, option.WithHTTPClient(client)) + c.clientContainer, err = container.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -302,7 +302,7 @@ func (c *Config) LoadAndValidate() error { containerBetaClientBasePath := removeBasePathVersion(c.ContainerBetaBasePath) log.Printf("[INFO] Instantiating GKE Beta client for path %s", containerBetaClientBasePath) - c.clientContainerBeta, err = containerBeta.NewService(context, option.WithHTTPClient(client)) + c.clientContainerBeta, err = containerBeta.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -311,7 +311,7 @@ func (c *Config) LoadAndValidate() error { dnsClientBasePath := c.DNSBasePath + "projects/" log.Printf("[INFO] Instantiating Google Cloud DNS client for path %s", dnsClientBasePath) - c.clientDns, err = dns.NewService(context, option.WithHTTPClient(client)) + c.clientDns, err = dns.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -320,7 +320,7 @@ func (c *Config) LoadAndValidate() error { dnsBetaClientBasePath := c.DnsBetaBasePath + "projects/" log.Printf("[INFO] Instantiating Google Cloud DNS Beta client for path %s", dnsBetaClientBasePath) - c.clientDnsBeta, err = dnsBeta.NewService(context, option.WithHTTPClient(client)) + c.clientDnsBeta, err = dnsBeta.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -329,7 +329,7 @@ func (c *Config) LoadAndValidate() error { kmsClientBasePath := removeBasePathVersion(c.KMSBasePath) log.Printf("[INFO] Instantiating Google Cloud KMS client for path %s", kmsClientBasePath) - c.clientKms, err = cloudkms.NewService(context, option.WithHTTPClient(client)) + c.clientKms, err = cloudkms.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -338,7 +338,7 @@ func (c *Config) LoadAndValidate() error { loggingClientBasePath := removeBasePathVersion(c.LoggingBasePath) log.Printf("[INFO] Instantiating Google Stackdriver Logging client for path %s", loggingClientBasePath) - c.clientLogging, err = cloudlogging.NewService(context, option.WithHTTPClient(client)) + c.clientLogging, err = cloudlogging.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -347,7 +347,7 @@ func (c *Config) LoadAndValidate() error { storageClientBasePath := c.StorageBasePath log.Printf("[INFO] Instantiating Google Storage client for path %s", storageClientBasePath) - c.clientStorage, err = storage.NewService(context, option.WithHTTPClient(client)) + c.clientStorage, err = storage.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -356,7 +356,7 @@ func (c *Config) LoadAndValidate() error { sqlClientBasePath := c.SQLBasePath log.Printf("[INFO] Instantiating Google SqlAdmin client for path %s", sqlClientBasePath) - c.clientSqlAdmin, err = sqladmin.NewService(context, option.WithHTTPClient(client)) + c.clientSqlAdmin, err = sqladmin.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -365,7 +365,7 @@ func (c *Config) LoadAndValidate() error { pubsubClientBasePath := removeBasePathVersion(c.PubsubBasePath) log.Printf("[INFO] Instantiating Google Pubsub client for path %s", pubsubClientBasePath) - c.clientPubsub, err = pubsub.NewService(context, option.WithHTTPClient(client)) + c.clientPubsub, err = pubsub.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -374,7 +374,7 @@ func (c *Config) LoadAndValidate() error { dataflowClientBasePath := removeBasePathVersion(c.DataflowBasePath) log.Printf("[INFO] Instantiating Google Dataflow client for path %s", dataflowClientBasePath) - c.clientDataflow, err = dataflow.NewService(context, option.WithHTTPClient(client)) + c.clientDataflow, err = dataflow.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -383,7 +383,7 @@ func (c *Config) LoadAndValidate() error { resourceManagerBasePath := removeBasePathVersion(c.ResourceManagerBasePath) log.Printf("[INFO] Instantiating Google Cloud ResourceManager client for path %s", resourceManagerBasePath) - c.clientResourceManager, err = cloudresourcemanager.NewService(context, option.WithHTTPClient(client)) + c.clientResourceManager, err = cloudresourcemanager.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -392,7 +392,7 @@ func (c *Config) LoadAndValidate() error { resourceManagerV2Beta1BasePath := removeBasePathVersion(c.ResourceManagerV2Beta1BasePath) log.Printf("[INFO] Instantiating Google Cloud ResourceManager V client for path %s", resourceManagerV2Beta1BasePath) - c.clientResourceManagerV2Beta1, err = resourceManagerV2Beta1.NewService(context, option.WithHTTPClient(client)) + c.clientResourceManagerV2Beta1, err = resourceManagerV2Beta1.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -401,7 +401,7 @@ func (c *Config) LoadAndValidate() error { runtimeConfigClientBasePath := removeBasePathVersion(c.RuntimeConfigBasePath) log.Printf("[INFO] Instantiating Google Cloud Runtimeconfig client for path %s", runtimeConfigClientBasePath) - c.clientRuntimeconfig, err = runtimeconfig.NewService(context, option.WithHTTPClient(client)) + c.clientRuntimeconfig, err = runtimeconfig.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -410,7 +410,7 @@ func (c *Config) LoadAndValidate() error { iamClientBasePath := removeBasePathVersion(c.IAMBasePath) log.Printf("[INFO] Instantiating Google Cloud IAM client for path %s", iamClientBasePath) - c.clientIAM, err = iam.NewService(context, option.WithHTTPClient(client)) + c.clientIAM, err = iam.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -419,7 +419,7 @@ func (c *Config) LoadAndValidate() error { iamCredentialsClientBasePath := removeBasePathVersion(c.IamCredentialsBasePath) log.Printf("[INFO] Instantiating Google Cloud IAMCredentials client for path %s", iamCredentialsClientBasePath) - c.clientIamCredentials, err = iamcredentials.NewService(context, option.WithHTTPClient(client)) + c.clientIamCredentials, err = iamcredentials.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -428,7 +428,7 @@ func (c *Config) LoadAndValidate() error { serviceManagementClientBasePath := removeBasePathVersion(c.ServiceManagementBasePath) log.Printf("[INFO] Instantiating Google Cloud Service Management client for path %s", serviceManagementClientBasePath) - c.clientServiceMan, err = servicemanagement.NewService(context, option.WithHTTPClient(client)) + c.clientServiceMan, err = servicemanagement.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -437,7 +437,7 @@ func (c *Config) LoadAndValidate() error { serviceUsageClientBasePath := removeBasePathVersion(c.ServiceUsageBasePath) log.Printf("[INFO] Instantiating Google Cloud Service Usage client for path %s", serviceUsageClientBasePath) - c.clientServiceUsage, err = serviceusage.NewService(context, option.WithHTTPClient(client)) + c.clientServiceUsage, err = serviceusage.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -446,7 +446,7 @@ func (c *Config) LoadAndValidate() error { cloudBillingClientBasePath := removeBasePathVersion(c.CloudBillingBasePath) log.Printf("[INFO] Instantiating Google Cloud Billing client for path %s", cloudBillingClientBasePath) - c.clientBilling, err = cloudbilling.NewService(context, option.WithHTTPClient(client)) + c.clientBilling, err = cloudbilling.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -455,7 +455,7 @@ func (c *Config) LoadAndValidate() error { cloudBuildClientBasePath := removeBasePathVersion(c.CloudBuildBasePath) log.Printf("[INFO] Instantiating Google Cloud Build client for path %s", cloudBuildClientBasePath) - c.clientBuild, err = cloudbuild.NewService(context, option.WithHTTPClient(client)) + c.clientBuild, err = cloudbuild.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -464,7 +464,7 @@ func (c *Config) LoadAndValidate() error { bigQueryClientBasePath := c.BigQueryBasePath log.Printf("[INFO] Instantiating Google Cloud BigQuery client for path %s", bigQueryClientBasePath) - c.clientBigQuery, err = bigquery.NewService(context, option.WithHTTPClient(client)) + c.clientBigQuery, err = bigquery.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -473,7 +473,7 @@ func (c *Config) LoadAndValidate() error { cloudFunctionsClientBasePath := removeBasePathVersion(c.CloudFunctionsBasePath) log.Printf("[INFO] Instantiating Google Cloud CloudFunctions Client for path %s", cloudFunctionsClientBasePath) - c.clientCloudFunctions, err = cloudfunctions.NewService(context, option.WithHTTPClient(client)) + c.clientCloudFunctions, err = cloudfunctions.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -488,7 +488,7 @@ func (c *Config) LoadAndValidate() error { bigtableAdminBasePath := removeBasePathVersion(c.BigtableAdminBasePath) log.Printf("[INFO] Instantiating Google Cloud BigtableAdmin for path %s", bigtableAdminBasePath) - clientBigtable, err := bigtableadmin.NewService(context, option.WithHTTPClient(client)) + clientBigtable, err := bigtableadmin.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -498,7 +498,7 @@ func (c *Config) LoadAndValidate() error { sourceRepoClientBasePath := removeBasePathVersion(c.SourceRepoBasePath) log.Printf("[INFO] Instantiating Google Cloud Source Repo client for path %s", sourceRepoClientBasePath) - c.clientSourceRepo, err = sourcerepo.NewService(context, option.WithHTTPClient(client)) + c.clientSourceRepo, err = sourcerepo.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -507,7 +507,7 @@ func (c *Config) LoadAndValidate() error { spannerClientBasePath := removeBasePathVersion(c.SpannerBasePath) log.Printf("[INFO] Instantiating Google Cloud Spanner client for path %s", spannerClientBasePath) - c.clientSpanner, err = spanner.NewService(context, option.WithHTTPClient(client)) + c.clientSpanner, err = spanner.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -516,7 +516,7 @@ func (c *Config) LoadAndValidate() error { dataprocClientBasePath := removeBasePathVersion(c.DataprocBasePath) log.Printf("[INFO] Instantiating Google Cloud Dataproc client for path %s", dataprocClientBasePath) - c.clientDataproc, err = dataproc.NewService(context, option.WithHTTPClient(client)) + c.clientDataproc, err = dataproc.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -525,7 +525,7 @@ func (c *Config) LoadAndValidate() error { dataprocBetaClientBasePath := removeBasePathVersion(c.DataprocBetaBasePath) log.Printf("[INFO] Instantiating Google Cloud Dataproc Beta client for path %s", dataprocBetaClientBasePath) - c.clientDataprocBeta, err = dataprocBeta.NewService(context, option.WithHTTPClient(client)) + c.clientDataprocBeta, err = dataprocBeta.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -534,7 +534,7 @@ func (c *Config) LoadAndValidate() error { filestoreClientBasePath := removeBasePathVersion(c.FilestoreBasePath) log.Printf("[INFO] Instantiating Filestore client for path %s", filestoreClientBasePath) - c.clientFilestore, err = file.NewService(context, option.WithHTTPClient(client)) + c.clientFilestore, err = file.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -543,7 +543,7 @@ func (c *Config) LoadAndValidate() error { cloudIoTClientBasePath := removeBasePathVersion(c.CloudIoTBasePath) log.Printf("[INFO] Instantiating Google Cloud IoT Core client for path %s", cloudIoTClientBasePath) - c.clientCloudIoT, err = cloudiot.NewService(context, option.WithHTTPClient(client)) + c.clientCloudIoT, err = cloudiot.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -552,7 +552,7 @@ func (c *Config) LoadAndValidate() error { appEngineClientBasePath := removeBasePathVersion(c.AppEngineBasePath) log.Printf("[INFO] Instantiating App Engine client for path %s", appEngineClientBasePath) - c.clientAppEngine, err = appengine.NewService(context, option.WithHTTPClient(client)) + c.clientAppEngine, err = appengine.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -561,7 +561,7 @@ func (c *Config) LoadAndValidate() error { composerClientBasePath := removeBasePathVersion(c.ComposerBasePath) log.Printf("[INFO] Instantiating Cloud Composer client for path %s", composerClientBasePath) - c.clientComposer, err = composer.NewService(context, option.WithHTTPClient(client)) + c.clientComposer, err = composer.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -570,7 +570,7 @@ func (c *Config) LoadAndValidate() error { serviceNetworkingClientBasePath := removeBasePathVersion(c.ServiceNetworkingBasePath) log.Printf("[INFO] Instantiating Service Networking client for path %s", serviceNetworkingClientBasePath) - c.clientServiceNetworking, err = servicenetworking.NewService(context, option.WithHTTPClient(client)) + c.clientServiceNetworking, err = servicenetworking.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -579,7 +579,7 @@ func (c *Config) LoadAndValidate() error { storageTransferClientBasePath := removeBasePathVersion(c.StorageTransferBasePath) log.Printf("[INFO] Instantiating Google Cloud Storage Transfer client for path %s", storageTransferClientBasePath) - c.clientStorageTransfer, err = storagetransfer.NewService(context, option.WithHTTPClient(client)) + c.clientStorageTransfer, err = storagetransfer.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return err } @@ -588,8 +588,8 @@ func (c *Config) LoadAndValidate() error { c.Region = GetRegionFromRegionSelfLink(c.Region) - c.requestBatcherServiceUsage = NewRequestBatcher("Service Usage", context, c.BatchingConfig) - c.requestBatcherIam = NewRequestBatcher("IAM", context, c.BatchingConfig) + c.requestBatcherServiceUsage = NewRequestBatcher("Service Usage", ctx, c.BatchingConfig) + c.requestBatcherIam = NewRequestBatcher("IAM", ctx, c.BatchingConfig) return nil } diff --git a/google/config_test.go b/google/config_test.go index ae47412e9b1..44dbe40922d 100644 --- a/google/config_test.go +++ b/google/config_test.go @@ -24,7 +24,7 @@ func TestConfigLoadAndValidate_accountFilePath(t *testing.T) { ConfigureBasePaths(config) - err := config.LoadAndValidate() + err := config.LoadAndValidate(context.Background()) if err != nil { t.Fatalf("error: %v", err) } @@ -43,7 +43,7 @@ func TestConfigLoadAndValidate_accountFileJSON(t *testing.T) { ConfigureBasePaths(config) - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { t.Fatalf("error: %v", err) } @@ -58,7 +58,7 @@ func TestConfigLoadAndValidate_accountFileJSONInvalid(t *testing.T) { ConfigureBasePaths(config) - if config.LoadAndValidate() == nil { + if config.LoadAndValidate(context.Background()) == nil { t.Fatalf("expected error, but got nil") } } @@ -80,7 +80,7 @@ func TestAccConfigLoadValidate_credentials(t *testing.T) { ConfigureBasePaths(config) - err := config.LoadAndValidate() + err := config.LoadAndValidate(context.Background()) if err != nil { t.Fatalf("error: %v", err) } @@ -118,7 +118,7 @@ func TestAccConfigLoadValidate_accessToken(t *testing.T) { ConfigureBasePaths(config) - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { t.Fatalf("error: %v", err) } @@ -139,7 +139,7 @@ func TestConfigLoadAndValidate_customScopes(t *testing.T) { ConfigureBasePaths(config) - err := config.LoadAndValidate() + err := config.LoadAndValidate(context.Background()) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -165,7 +165,7 @@ func TestConfigLoadAndValidate_defaultBatchingConfig(t *testing.T) { BatchingConfig: batchCfg, } - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { t.Fatalf("unexpected error: %v", err) } @@ -202,7 +202,7 @@ func TestConfigLoadAndValidate_customBatchingConfig(t *testing.T) { BatchingConfig: batchCfg, } - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/google/container_operation.go b/google/container_operation.go index 99984f0f536..0cffb0d33bf 100644 --- a/google/container_operation.go +++ b/google/container_operation.go @@ -1,13 +1,17 @@ package google import ( + "context" + "errors" "fmt" + "log" container "google.golang.org/api/container/v1beta1" ) type ContainerOperationWaiter struct { Service *container.Service + Context context.Context Op *container.Operation Project string Location string @@ -62,6 +66,13 @@ func (w *ContainerOperationWaiter) QueryOp() (interface{}, error) { w.Project, w.Location, w.Op.Name) var op *container.Operation + select { + case <-w.Context.Done(): + log.Println("[WARN] request has been cancelled early") + return op, errors.New("unable to finish polling, context has been cancelled") + default: + // default must be here to keep the previous case from blocking + } err := retryTimeDuration(func() (opErr error) { op, opErr = w.Service.Projects.Locations.Operations.Get(name).Do() return opErr @@ -88,6 +99,7 @@ func (w *ContainerOperationWaiter) TargetStates() []string { func containerOperationWait(config *Config, op *container.Operation, project, location, activity string, timeoutMinutes int) error { w := &ContainerOperationWaiter{ Service: config.clientContainerBeta, + Context: config.context, Op: op, Project: project, Location: location, diff --git a/google/provider.go b/google/provider.go index 69df00416ae..3768700fc7f 100644 --- a/google/provider.go +++ b/google/provider.go @@ -462,7 +462,7 @@ func Provider() terraform.ResourceProvider { // We can therefore assume that if it's missing it's 0.10 or 0.11 terraformVersion = "0.11+compatible" } - return providerConfigure(d, terraformVersion) + return providerConfigure(d, provider, terraformVersion) } return provider @@ -721,7 +721,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) { ) } -func providerConfigure(d *schema.ResourceData, terraformVersion string) (interface{}, error) { +func providerConfigure(d *schema.ResourceData, p *schema.Provider, terraformVersion string) (interface{}, error) { config := Config{ Project: d.Get("project").(string), Region: d.Get("region").(string), @@ -814,7 +814,7 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa config.StorageTransferBasePath = d.Get(StorageTransferCustomEndpointEntryKey).(string) config.BigtableAdminBasePath = d.Get(BigtableAdminCustomEndpointEntryKey).(string) - if err := config.LoadAndValidate(); err != nil { + if err := config.LoadAndValidate(p.StopContext()); err != nil { return nil, err } diff --git a/google/resource_composer_environment_test.go b/google/resource_composer_environment_test.go index 2d8ff87412c..7e40f0fda73 100644 --- a/google/resource_composer_environment_test.go +++ b/google/resource_composer_environment_test.go @@ -1,6 +1,7 @@ package google import ( + "context" "fmt" "testing" @@ -551,7 +552,7 @@ func testSweepComposerResources(region string) error { return fmt.Errorf("error getting shared config for region: %s", err) } - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { log.Fatalf("error loading: %s", err) } diff --git a/google/resource_compute_instance_migrate_test.go b/google/resource_compute_instance_migrate_test.go index 36aebf40f46..3f04f42d5a1 100644 --- a/google/resource_compute_instance_migrate_test.go +++ b/google/resource_compute_instance_migrate_test.go @@ -1,6 +1,7 @@ package google import ( + "context" "fmt" "log" "os" @@ -941,7 +942,7 @@ func getInitializedConfig(t *testing.T) *Config { ConfigureBasePaths(config) - err := config.LoadAndValidate() + err := config.LoadAndValidate(context.Background()) if err != nil { t.Fatal(err) } diff --git a/google/resource_container_cluster.go b/google/resource_container_cluster.go index d38094140e5..2e36258d9ab 100644 --- a/google/resource_container_cluster.go +++ b/google/resource_container_cluster.go @@ -109,6 +109,11 @@ func resourceContainerCluster() *schema.Resource { }, }, + "operation": { + Type: schema.TypeString, + Computed: true, + }, + "location": { Type: schema.TypeString, Optional: true, @@ -916,6 +921,18 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er timeoutInMinutes := int(d.Timeout(schema.TimeoutCreate).Minutes()) waitErr := containerOperationWait(config, op, project, location, "creating GKE cluster", timeoutInMinutes) if waitErr != nil { + // Check if the create operation failed because Terraform was prematurely terminated. If it was we can persist the + // operation id to state so that a subsequent refresh of this resource will wait until the operation has terminated + // before attempting to Read the state of the cluster. This allows a graceful resumption of a Create that was killed + // by the upstream Terraform process exiting early such as a sigterm. + select { + case <-config.context.Done(): + log.Printf("[DEBUG] Persisting %s so this operation can be resumed \n", op.Name) + d.Set("operation", op.Name) + return nil + default: + // leaving default case to ensure this is non blocking + } // Try a GET on the cluster so we can see the state in debug logs. This will help classify error states. _, getErr := config.clientContainerBeta.Projects.Locations.Clusters.Get(containerClusterFullName(project, location, clusterName)).Do() if getErr != nil { @@ -974,6 +991,19 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro return err } + operation := d.Get("operation").(string) + if operation != "" { + log.Printf("[DEBUG] in progress operation detected at %v, attempting to resume", operation) + op := &containerBeta.Operation{ + Name: operation, + } + d.Set("operation", "") + waitErr := containerOperationWait(config, op, project, location, "resuming GKE cluster", int(d.Timeout(schema.TimeoutCreate).Minutes())) + if waitErr != nil { + return waitErr + } + } + clusterName := d.Get("name").(string) name := containerClusterFullName(project, location, clusterName) cluster, err := config.clientContainerBeta.Projects.Locations.Clusters.Get(name).Do() diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index e881bedbccf..d47580637b9 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -2,6 +2,7 @@ package google import ( "bytes" + "context" "fmt" "log" "regexp" @@ -27,7 +28,7 @@ func testSweepContainerClusters(region string) error { log.Fatalf("error getting shared config for region: %s", err) } - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { log.Fatalf("error loading: %s", err) } diff --git a/google/resource_monitoring_group_test.go b/google/resource_monitoring_group_test.go index bd0ff75e5bb..25284379fe3 100644 --- a/google/resource_monitoring_group_test.go +++ b/google/resource_monitoring_group_test.go @@ -1,6 +1,7 @@ package google import ( + "context" "fmt" "log" "strings" @@ -23,7 +24,7 @@ func testSweepMonitoringGroups(region string) error { log.Fatalf("error getting shared config for region: %s", err) } - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { log.Fatalf("error loading: %s", err) } diff --git a/google/resource_sql_database_instance_test.go b/google/resource_sql_database_instance_test.go index 4c96a3d03b9..11c939db0d2 100644 --- a/google/resource_sql_database_instance_test.go +++ b/google/resource_sql_database_instance_test.go @@ -1,6 +1,7 @@ package google import ( + "context" "fmt" "log" "strings" @@ -40,7 +41,7 @@ func testSweepDatabases(region string) error { return fmt.Errorf("error getting shared config for region: %s", err) } - err = config.LoadAndValidate() + err = config.LoadAndValidate(context.Background()) if err != nil { log.Fatalf("error loading: %s", err) }