From 9a168c1acd63bb0e8ee7d34c20c30efa1b677188 Mon Sep 17 00:00:00 2001 From: Dosty Date: Fri, 2 Dec 2022 09:29:59 -0600 Subject: [PATCH 1/3] Made timeouts configurable for cluster & advanced_cluster, default is 3 hours --- .../resource_mongodbatlas_advanced_cluster.go | 28 ++++++++++------ mongodbatlas/resource_mongodbatlas_cluster.go | 32 ++++++++++++------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/mongodbatlas/resource_mongodbatlas_advanced_cluster.go b/mongodbatlas/resource_mongodbatlas_advanced_cluster.go index a9f5545963..6ed41a9c97 100644 --- a/mongodbatlas/resource_mongodbatlas_advanced_cluster.go +++ b/mongodbatlas/resource_mongodbatlas_advanced_cluster.go @@ -265,6 +265,11 @@ func resourceMongoDBAtlasAdvancedCluster() *schema.Resource { }, "advanced_configuration": clusterAdvancedConfigurationSchema(), }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(3 * time.Hour), + Update: schema.DefaultTimeout(3 * time.Hour), + Delete: schema.DefaultTimeout(3 * time.Hour), + }, } } @@ -359,11 +364,12 @@ func resourceMongoDBAtlasAdvancedClusterCreate(ctx context.Context, d *schema.Re return diag.FromErr(fmt.Errorf(errorClusterAdvancedCreate, err)) } + timeout := d.Timeout(schema.TimeoutCreate) stateConf := &resource.StateChangeConf{ Pending: []string{"CREATING", "UPDATING", "REPAIRING", "REPEATING", "PENDING"}, Target: []string{"IDLE"}, Refresh: resourceClusterAdvancedRefreshFunc(ctx, d.Get("name").(string), projectID, conn), - Timeout: 3 * time.Hour, + Timeout: timeout, MinTimeout: 1 * time.Minute, Delay: 3 * time.Minute, } @@ -396,7 +402,7 @@ func resourceMongoDBAtlasAdvancedClusterCreate(ctx context.Context, d *schema.Re Paused: pointy.Bool(v), } - _, _, err = updateAdvancedCluster(ctx, conn, request, projectID, d.Get("name").(string)) + _, _, err = updateAdvancedCluster(ctx, conn, request, projectID, d.Get("name").(string), timeout) if err != nil { return diag.FromErr(fmt.Errorf(errorClusterAdvancedUpdate, d.Get("name").(string), err)) } @@ -547,7 +553,7 @@ func resourceMongoDBAtlasAdvancedClusterUpgrade(ctx context.Context, d *schema.R return diag.FromErr(fmt.Errorf("upgrade called without %s in ctx", string(upgradeRequestCtxKey))) } - upgradeResponse, _, err := upgradeCluster(ctx, conn, upgradeRequest, projectID, clusterName) + upgradeResponse, _, err := upgradeCluster(ctx, conn, upgradeRequest, projectID, clusterName, d.Timeout(schema.TimeoutUpdate)) if err != nil { return diag.FromErr(fmt.Errorf(errorClusterAdvancedUpdate, clusterName, err)) @@ -623,17 +629,19 @@ func resourceMongoDBAtlasAdvancedClusterUpdate(ctx context.Context, d *schema.Re cluster.VersionReleaseSystem = d.Get("version_release_system").(string) } + timeout := d.Timeout(schema.TimeoutUpdate) + // Has changes if !reflect.DeepEqual(cluster, matlas.Cluster{}) { - err := resource.RetryContext(ctx, 3*time.Hour, func() *resource.RetryError { - _, _, err := updateAdvancedCluster(ctx, conn, cluster, projectID, clusterName) + err := resource.RetryContext(ctx, timeout, func() *resource.RetryError { + _, _, err := updateAdvancedCluster(ctx, conn, cluster, projectID, clusterName, timeout) if err != nil { var target *matlas.ErrorResponse if errors.As(err, &target) && target.ErrorCode == "CANNOT_UPDATE_PAUSED_CLUSTER" { clusterRequest := &matlas.AdvancedCluster{ Paused: pointy.Bool(false), } - _, _, err := updateAdvancedCluster(ctx, conn, clusterRequest, projectID, clusterName) + _, _, err := updateAdvancedCluster(ctx, conn, clusterRequest, projectID, clusterName, timeout) if err != nil { return resource.NonRetryableError(fmt.Errorf(errorClusterAdvancedUpdate, clusterName, err)) } @@ -670,7 +678,7 @@ func resourceMongoDBAtlasAdvancedClusterUpdate(ctx context.Context, d *schema.Re Paused: pointy.Bool(true), } - _, _, err := updateAdvancedCluster(ctx, conn, clusterRequest, projectID, clusterName) + _, _, err := updateAdvancedCluster(ctx, conn, clusterRequest, projectID, clusterName, timeout) if err != nil { return diag.FromErr(fmt.Errorf(errorClusterAdvancedUpdate, clusterName, err)) } @@ -698,7 +706,7 @@ func resourceMongoDBAtlasAdvancedClusterDelete(ctx context.Context, d *schema.Re Pending: []string{"IDLE", "CREATING", "UPDATING", "REPAIRING", "DELETING"}, Target: []string{"DELETED"}, Refresh: resourceClusterAdvancedRefreshFunc(ctx, clusterName, projectID, conn), - Timeout: 3 * time.Hour, + Timeout: d.Timeout(schema.TimeoutDelete), MinTimeout: 30 * time.Second, Delay: 1 * time.Minute, // Wait 30 secs before starting } @@ -1198,7 +1206,7 @@ func getUpgradeRequest(d *schema.ResourceData) *matlas.Cluster { } } -func updateAdvancedCluster(ctx context.Context, conn *matlas.Client, request *matlas.AdvancedCluster, projectID, name string) (*matlas.AdvancedCluster, *matlas.Response, error) { +func updateAdvancedCluster(ctx context.Context, conn *matlas.Client, request *matlas.AdvancedCluster, projectID, name string, timeout time.Duration) (*matlas.AdvancedCluster, *matlas.Response, error) { cluster, resp, err := conn.AdvancedClusters.Update(ctx, projectID, name, request) if err != nil { return nil, nil, err @@ -1208,7 +1216,7 @@ func updateAdvancedCluster(ctx context.Context, conn *matlas.Client, request *ma Pending: []string{"CREATING", "UPDATING", "REPAIRING"}, Target: []string{"IDLE"}, Refresh: resourceClusterAdvancedRefreshFunc(ctx, name, projectID, conn), - Timeout: 3 * time.Hour, + Timeout: timeout, MinTimeout: 30 * time.Second, Delay: 1 * time.Minute, } diff --git a/mongodbatlas/resource_mongodbatlas_cluster.go b/mongodbatlas/resource_mongodbatlas_cluster.go index c3ead4c2f7..82ae417c2d 100644 --- a/mongodbatlas/resource_mongodbatlas_cluster.go +++ b/mongodbatlas/resource_mongodbatlas_cluster.go @@ -359,6 +359,11 @@ func resourceMongoDBAtlasCluster() *schema.Resource { }, }, CustomizeDiff: resourceClusterCustomizeDiff, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(3 * time.Hour), + Update: schema.DefaultTimeout(3 * time.Hour), + Delete: schema.DefaultTimeout(3 * time.Hour), + }, } } @@ -547,11 +552,12 @@ func resourceMongoDBAtlasClusterCreate(ctx context.Context, d *schema.ResourceDa return diag.FromErr(fmt.Errorf(errorClusterCreate, err)) } + timeout := d.Timeout(schema.TimeoutCreate) stateConf := &resource.StateChangeConf{ Pending: []string{"CREATING", "UPDATING", "REPAIRING", "REPEATING", "PENDING"}, Target: []string{"IDLE"}, Refresh: resourceClusterRefreshFunc(ctx, d.Get("name").(string), projectID, conn), - Timeout: 3 * time.Hour, + Timeout: timeout, MinTimeout: 1 * time.Minute, Delay: 3 * time.Minute, } @@ -584,7 +590,7 @@ func resourceMongoDBAtlasClusterCreate(ctx context.Context, d *schema.ResourceDa Paused: pointy.Bool(v), } - _, _, err = updateCluster(ctx, conn, clusterRequest, projectID, d.Get("name").(string)) + _, _, err = updateCluster(ctx, conn, clusterRequest, projectID, d.Get("name").(string), timeout) if err != nil { return diag.FromErr(fmt.Errorf(errorClusterUpdate, d.Get("name").(string), err)) } @@ -918,8 +924,10 @@ func resourceMongoDBAtlasClusterUpdate(ctx context.Context, d *schema.ResourceDa } } + timeout := d.Timeout(schema.TimeoutUpdate) + if isUpgradeRequired(d) { - updatedCluster, _, err := upgradeCluster(ctx, conn, cluster, projectID, clusterName) + updatedCluster, _, err := upgradeCluster(ctx, conn, cluster, projectID, clusterName, timeout) if err != nil { return diag.FromErr(fmt.Errorf(errorClusterUpdate, clusterName, err)) @@ -932,15 +940,15 @@ func resourceMongoDBAtlasClusterUpdate(ctx context.Context, d *schema.ResourceDa "provider_name": updatedCluster.ProviderSettings.ProviderName, })) } else if !reflect.DeepEqual(cluster, matlas.Cluster{}) { - err := resource.RetryContext(ctx, 3*time.Hour, func() *resource.RetryError { - _, _, err := updateCluster(ctx, conn, cluster, projectID, clusterName) + err := resource.RetryContext(ctx, timeout, func() *resource.RetryError { + _, _, err := updateCluster(ctx, conn, cluster, projectID, clusterName, timeout) if didErrOnPausedCluster(err) { clusterRequest := &matlas.Cluster{ Paused: pointy.Bool(false), } - _, _, err = updateCluster(ctx, conn, clusterRequest, projectID, clusterName) + _, _, err = updateCluster(ctx, conn, clusterRequest, projectID, clusterName, timeout) } if err != nil { @@ -976,7 +984,7 @@ func resourceMongoDBAtlasClusterUpdate(ctx context.Context, d *schema.ResourceDa Paused: pointy.Bool(true), } - _, _, err := updateCluster(ctx, conn, clusterRequest, projectID, clusterName) + _, _, err := updateCluster(ctx, conn, clusterRequest, projectID, clusterName, timeout) if err != nil { return diag.FromErr(fmt.Errorf(errorClusterUpdate, clusterName, err)) } @@ -1014,7 +1022,7 @@ func resourceMongoDBAtlasClusterDelete(ctx context.Context, d *schema.ResourceDa Pending: []string{"IDLE", "CREATING", "UPDATING", "REPAIRING", "DELETING"}, Target: []string{"DELETED"}, Refresh: resourceClusterRefreshFunc(ctx, clusterName, projectID, conn), - Timeout: 3 * time.Hour, + Timeout: d.Timeout(schema.TimeoutDelete), MinTimeout: 30 * time.Second, Delay: 1 * time.Minute, // Wait 30 secs before starting } @@ -1716,7 +1724,7 @@ func clusterAdvancedConfigurationSchema() *schema.Schema { } } -func updateCluster(ctx context.Context, conn *matlas.Client, request *matlas.Cluster, projectID, name string) (*matlas.Cluster, *matlas.Response, error) { +func updateCluster(ctx context.Context, conn *matlas.Client, request *matlas.Cluster, projectID, name string, timeout time.Duration) (*matlas.Cluster, *matlas.Response, error) { cluster, resp, err := conn.Clusters.Update(ctx, projectID, name, request) if err != nil { return nil, nil, err @@ -1726,7 +1734,7 @@ func updateCluster(ctx context.Context, conn *matlas.Client, request *matlas.Clu Pending: []string{"CREATING", "UPDATING", "REPAIRING"}, Target: []string{"IDLE"}, Refresh: resourceClusterRefreshFunc(ctx, name, projectID, conn), - Timeout: 3 * time.Hour, + Timeout: timeout, MinTimeout: 30 * time.Second, Delay: 1 * time.Minute, } @@ -1740,7 +1748,7 @@ func updateCluster(ctx context.Context, conn *matlas.Client, request *matlas.Clu return cluster, resp, nil } -func upgradeCluster(ctx context.Context, conn *matlas.Client, request *matlas.Cluster, projectID, name string) (*matlas.Cluster, *matlas.Response, error) { +func upgradeCluster(ctx context.Context, conn *matlas.Client, request *matlas.Cluster, projectID, name string, timeout time.Duration) (*matlas.Cluster, *matlas.Response, error) { request.Name = name cluster, resp, err := conn.Clusters.Upgrade(ctx, projectID, request) @@ -1752,7 +1760,7 @@ func upgradeCluster(ctx context.Context, conn *matlas.Client, request *matlas.Cl Pending: []string{"CREATING", "UPDATING", "REPAIRING"}, Target: []string{"IDLE"}, Refresh: resourceClusterRefreshFunc(ctx, name, projectID, conn), - Timeout: 3 * time.Hour, + Timeout: timeout, MinTimeout: 30 * time.Second, Delay: 1 * time.Minute, } From 89c665cf8c392653cb185333bdf72f04e605a1bf Mon Sep 17 00:00:00 2001 From: Dosty Date: Fri, 2 Dec 2022 09:43:14 -0600 Subject: [PATCH 2/3] Addressed a lint issue --- mongodbatlas/resource_mongodbatlas_advanced_cluster.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mongodbatlas/resource_mongodbatlas_advanced_cluster.go b/mongodbatlas/resource_mongodbatlas_advanced_cluster.go index 6ed41a9c97..cc1480871c 100644 --- a/mongodbatlas/resource_mongodbatlas_advanced_cluster.go +++ b/mongodbatlas/resource_mongodbatlas_advanced_cluster.go @@ -1206,7 +1206,13 @@ func getUpgradeRequest(d *schema.ResourceData) *matlas.Cluster { } } -func updateAdvancedCluster(ctx context.Context, conn *matlas.Client, request *matlas.AdvancedCluster, projectID, name string, timeout time.Duration) (*matlas.AdvancedCluster, *matlas.Response, error) { +func updateAdvancedCluster( + ctx context.Context, + conn *matlas.Client, + request *matlas.AdvancedCluster, + projectID, name string, + timeout time.Duration, +) (*matlas.AdvancedCluster, *matlas.Response, error) { cluster, resp, err := conn.AdvancedClusters.Update(ctx, projectID, name, request) if err != nil { return nil, nil, err From 2ade1e458411214b5dcc6d120f5b5f9fd0b5a437 Mon Sep 17 00:00:00 2001 From: Dosty Date: Mon, 5 Dec 2022 09:20:52 -0600 Subject: [PATCH 3/3] Added documentation on timeouts arguments to cluster --- website/docs/r/advanced_cluster.html.markdown | 2 ++ website/docs/r/cluster.html.markdown | 1 + 2 files changed, 3 insertions(+) diff --git a/website/docs/r/advanced_cluster.html.markdown b/website/docs/r/advanced_cluster.html.markdown index 49941034b3..2335eb9702 100644 --- a/website/docs/r/advanced_cluster.html.markdown +++ b/website/docs/r/advanced_cluster.html.markdown @@ -217,6 +217,7 @@ This parameter defaults to false. `lifecycle { ignore_changes = [paused] }` +* `timeouts`- (Optional) The duration of time to wait for Cluster to be created, updated, or deleted. The timeout value is defined by a signed sequence of decimal numbers with an time unit suffix such as: `1h45m`, `300s`, `10m`, .... The valid time units are: `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. The default timeout for Private Endpoint create & delete is `3h`. Learn more about timeouts [here](https://www.terraform.io/plugin/sdkv2/resources/retries-and-customizable-timeouts). ### bi_connector @@ -411,6 +412,7 @@ In addition to all arguments above, the following attributes are exported: - REPAIRING * `replication_specs` - Set of replication specifications for the cluster. Primary usage is covered under the [replication_specs argument reference](#replication_specs), though there are some computed attributes: - `replication_specs.#.container_id` - A key-value map of the Network Peering Container ID(s) for the configuration specified in `region_configs`. The Container ID is the id of the container created when the first cluster in the region (AWS/Azure) or project (GCP) was created. The syntax is `"providerName:regionName" = "containerId"`. Example `AWS:US_EAST_1" = "61e0797dde08fb498ca11a71`. + ## Import Clusters can be imported using project ID and cluster name, in the format `PROJECTID-CLUSTERNAME`, e.g. diff --git a/website/docs/r/cluster.html.markdown b/website/docs/r/cluster.html.markdown index 6dc50c321b..cf7d948f66 100644 --- a/website/docs/r/cluster.html.markdown +++ b/website/docs/r/cluster.html.markdown @@ -378,6 +378,7 @@ But in order to explicitly change `provider_instance_size_name` comment the `lif * `version_release_system` - (Optional) - Release cadence that Atlas uses for this cluster. This parameter defaults to `LTS`. If you set this field to `CONTINUOUS`, you must omit the `mongo_db_major_version` field. Atlas accepts: - `CONTINUOUS`: Atlas creates your cluster using the most recent MongoDB release. Atlas automatically updates your cluster to the latest major and rapid MongoDB releases as they become available. - `LTS`: Atlas creates your cluster using the latest patch release of the MongoDB version that you specify in the mongoDBMajorVersion field. Atlas automatically updates your cluster to subsequent patch releases of this MongoDB version. Atlas doesn't update your cluster to newer rapid or major MongoDB releases as they become available. +* `timeouts`- (Optional) The duration of time to wait for Cluster to be created, updated, or deleted. The timeout value is defined by a signed sequence of decimal numbers with an time unit suffix such as: `1h45m`, `300s`, `10m`, .... The valid time units are: `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. The default timeout for Private Endpoint create & delete is `3h`. Learn more about timeouts [here](https://www.terraform.io/plugin/sdkv2/resources/retries-and-customizable-timeouts). ### Multi-Region Cluster