Skip to content

Commit f333547

Browse files
authored
INTMDB-271: Fixing a bug and improving for custom zone mappings in global cluster config (#597)
* refactor: improved the funcionality of updating custom zone mapping, fixes error about duplicated * test: added testacc * refactor suggested by tony * refactor
1 parent b6cf3a6 commit f333547

File tree

2 files changed

+278
-28
lines changed

2 files changed

+278
-28
lines changed

mongodbatlas/resource_mongodbatlas_global_cluster_config.go

Lines changed: 90 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import (
44
"context"
55
"errors"
66
"fmt"
7-
"log"
87
"net/http"
98
"strings"
9+
"time"
1010

1111
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1213
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1314
"github.com/mwielbut/pointy"
1415
matlas "go.mongodb.org/atlas/mongodbatlas"
@@ -75,7 +76,6 @@ func resourceMongoDBAtlasGlobalCluster() *schema.Resource {
7576
"custom_zone_mappings": {
7677
Type: schema.TypeSet,
7778
Optional: true,
78-
ForceNew: true,
7979
Elem: &schema.Resource{
8080
Schema: map[string]*schema.Schema{
8181
"location": {
@@ -109,8 +109,6 @@ func resourceMongoDBAtlasGlobalClusterCreate(ctx context.Context, d *schema.Reso
109109
for _, m := range v.(*schema.Set).List() {
110110
mn := m.(map[string]interface{})
111111

112-
log.Printf("[DEBUG] managed namespaces %+v", mn)
113-
114112
addManagedNamespace := &matlas.ManagedNamespace{
115113
Collection: mn["collection"].(string),
116114
Db: mn["db"].(string),
@@ -125,38 +123,39 @@ func resourceMongoDBAtlasGlobalClusterCreate(ctx context.Context, d *schema.Reso
125123
addManagedNamespace.IsShardKeyUnique = pointy.Bool(isShardKeyUnique.(bool))
126124
}
127125

128-
_, _, err := conn.GlobalClusters.AddManagedNamespace(ctx, projectID, clusterName, addManagedNamespace)
129-
126+
err := resource.RetryContext(ctx, 2*time.Minute, func() *resource.RetryError {
127+
_, _, err := conn.GlobalClusters.AddManagedNamespace(ctx, projectID, clusterName, addManagedNamespace)
128+
if err != nil {
129+
var target *matlas.ErrorResponse
130+
if errors.As(err, &target) && target.ErrorCode == "DUPLICATE_MANAGED_NAMESPACE" {
131+
if err := removeManagedNamespaces(ctx, conn, v.(*schema.Set).List(), projectID, clusterName); err != nil {
132+
return resource.NonRetryableError(fmt.Errorf(errorGlobalClusterCreate, err))
133+
}
134+
return resource.RetryableError(err)
135+
}
136+
return resource.NonRetryableError(fmt.Errorf(errorGlobalClusterCreate, err))
137+
}
138+
139+
return nil
140+
})
130141
if err != nil {
131142
return diag.FromErr(fmt.Errorf(errorGlobalClusterCreate, err))
132143
}
133144
}
134145
}
135146

136147
if v, ok := d.GetOk("custom_zone_mappings"); ok {
137-
var customZoneMappings []matlas.CustomZoneMapping
138-
139-
for _, czms := range v.(*schema.Set).List() {
140-
cz := czms.(map[string]interface{})
141-
142-
log.Printf("[DEBUG] custom zone mappings %+v", cz)
143-
144-
customZoneMapping := matlas.CustomZoneMapping{
145-
Location: cz["location"].(string),
146-
Zone: cz["zone"].(string),
147-
}
148-
149-
customZoneMappings = append(customZoneMappings, customZoneMapping)
150-
}
151-
152-
if len(customZoneMappings) > 0 {
153-
_, _, err := conn.GlobalClusters.AddCustomZoneMappings(ctx, projectID, clusterName, &matlas.CustomZoneMappingsRequest{
154-
CustomZoneMappings: customZoneMappings,
155-
})
148+
_, _, err := conn.GlobalClusters.AddCustomZoneMappings(ctx, projectID, clusterName, &matlas.CustomZoneMappingsRequest{
149+
CustomZoneMappings: newCustomZoneMappings(v.(*schema.Set).List()),
150+
})
156151

157-
if err != nil {
158-
return diag.FromErr(fmt.Errorf(errorGlobalClusterCreate, err))
152+
if err != nil {
153+
if v2, ok2 := d.GetOk("managed_namespaces"); ok2 {
154+
if err := removeManagedNamespaces(ctx, conn, v2.(*schema.Set).List(), projectID, clusterName); err != nil {
155+
return diag.FromErr(fmt.Errorf(errorGlobalClusterCreate, err))
156+
}
159157
}
158+
return diag.FromErr(fmt.Errorf(errorGlobalClusterCreate, err))
160159
}
161160
}
162161

@@ -224,6 +223,36 @@ func resourceMongoDBAtlasGlobalClusterUpdate(ctx context.Context, d *schema.Reso
224223
}
225224
}
226225

226+
if d.HasChange("custom_zone_mappings") {
227+
old, newMN := d.GetChange("custom_zone_mappings")
228+
oldSet := old.(*schema.Set)
229+
newSet := newMN.(*schema.Set)
230+
231+
remove := oldSet.Difference(newSet).List()
232+
add := newSet.Difference(oldSet).List()
233+
234+
if len(remove) > 0 {
235+
if _, _, err := conn.GlobalClusters.DeleteCustomZoneMappings(ctx, projectID, clusterName); err != nil {
236+
return diag.FromErr(fmt.Errorf(errorGlobalClusterUpdate, clusterName, err))
237+
}
238+
if v, ok := d.GetOk("custom_zone_mappings"); ok {
239+
if _, _, err := conn.GlobalClusters.AddCustomZoneMappings(ctx, projectID, clusterName, &matlas.CustomZoneMappingsRequest{
240+
CustomZoneMappings: newCustomZoneMappings(v.(*schema.Set).List()),
241+
}); err != nil {
242+
return diag.FromErr(fmt.Errorf(errorGlobalClusterUpdate, clusterName, err))
243+
}
244+
}
245+
}
246+
247+
if len(add) > 0 {
248+
if _, _, err := conn.GlobalClusters.AddCustomZoneMappings(ctx, projectID, clusterName, &matlas.CustomZoneMappingsRequest{
249+
CustomZoneMappings: newCustomZoneMappings(add),
250+
}); err != nil {
251+
return diag.FromErr(fmt.Errorf(errorGlobalClusterUpdate, clusterName, err))
252+
}
253+
}
254+
}
255+
227256
return resourceMongoDBAtlasGlobalClusterRead(ctx, d, meta)
228257
}
229258

@@ -348,3 +377,37 @@ func addManagedNamespaces(ctx context.Context, conn *matlas.Client, add []interf
348377

349378
return nil
350379
}
380+
381+
func newCustomZoneMapping(tfMap map[string]interface{}) *matlas.CustomZoneMapping {
382+
if tfMap == nil {
383+
return nil
384+
}
385+
386+
apiObject := &matlas.CustomZoneMapping{
387+
Location: tfMap["location"].(string),
388+
Zone: tfMap["zone"].(string),
389+
}
390+
391+
return apiObject
392+
}
393+
394+
func newCustomZoneMappings(tfList []interface{}) []matlas.CustomZoneMapping {
395+
if len(tfList) == 0 {
396+
return nil
397+
}
398+
399+
apiObjects := make([]matlas.CustomZoneMapping, len(tfList))
400+
if len(tfList) > 0 {
401+
for i, tfMapRaw := range tfList {
402+
if tfMap, ok := tfMapRaw.(map[string]interface{}); ok {
403+
apiObject := newCustomZoneMapping(tfMap)
404+
if apiObject == nil {
405+
continue
406+
}
407+
apiObjects[i] = *apiObject
408+
}
409+
}
410+
}
411+
412+
return apiObjects
413+
}

mongodbatlas/resource_mongodbatlas_global_cluster_config_test.go

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func TestAccResourceMongoDBAtlasGlobalCluster_importBasic(t *testing.T) {
103103
resource.Test(t, resource.TestCase{
104104
PreCheck: func() { testAccPreCheck(t) },
105105
ProviderFactories: testAccProviderFactories,
106-
CheckDestroy: testAccCheckMongoDBAtlasProjectIPAccessListDestroy,
106+
CheckDestroy: testAccCheckMongoDBAtlasGlobalClusterDestroy,
107107
Steps: []resource.TestStep{
108108
{
109109
Config: testAccMongoDBAtlasGlobalClusterConfig(projectID, name, "false", "false", "false"),
@@ -119,6 +119,92 @@ func TestAccResourceMongoDBAtlasGlobalCluster_importBasic(t *testing.T) {
119119
})
120120
}
121121

122+
func TestAccResourceMongoDBAtlasGlobalCluster_database(t *testing.T) {
123+
var (
124+
globalConfig matlas.GlobalCluster
125+
resourceName = "mongodbatlas_global_cluster_config.test"
126+
projectID = os.Getenv("MONGODB_ATLAS_PROJECT_ID")
127+
name = acctest.RandomWithPrefix("test-acc-global")
128+
)
129+
130+
customZone := `
131+
custom_zone_mappings {
132+
location = "US"
133+
zone = "US"
134+
}
135+
custom_zone_mappings {
136+
location = "IE"
137+
zone = "EU"
138+
}
139+
custom_zone_mappings {
140+
location = "DE"
141+
zone = "DE"
142+
}`
143+
customZoneUpdated := `
144+
custom_zone_mappings {
145+
location = "US"
146+
zone = "US"
147+
}
148+
custom_zone_mappings {
149+
location = "IE"
150+
zone = "EU"
151+
}
152+
custom_zone_mappings {
153+
location = "DE"
154+
zone = "DE"
155+
}
156+
custom_zone_mappings {
157+
location = "JP"
158+
zone = "JP"
159+
}`
160+
161+
resource.Test(t, resource.TestCase{
162+
PreCheck: func() { testAccPreCheck(t) },
163+
ProviderFactories: testAccProviderFactories,
164+
CheckDestroy: testAccCheckMongoDBAtlasGlobalClusterDestroy,
165+
Steps: []resource.TestStep{
166+
{
167+
Config: testAccMongoDBAtlasGlobalClusterWithDBConfig(projectID, name, "false", customZone),
168+
Check: resource.ComposeTestCheckFunc(
169+
testAccCheckMongoDBAtlasGlobalClusterExists(resourceName, &globalConfig),
170+
resource.TestCheckResourceAttrSet(resourceName, "managed_namespaces.#"),
171+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mappings.#"),
172+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.%"),
173+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.US"),
174+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.IE"),
175+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.DE"),
176+
resource.TestCheckResourceAttr(resourceName, "cluster_name", name),
177+
resource.TestCheckResourceAttr(resourceName, "project_id", projectID),
178+
testAccCheckMongoDBAtlasGlobalClusterAttributes(&globalConfig, 5),
179+
),
180+
},
181+
{
182+
Config: testAccMongoDBAtlasGlobalClusterWithDBConfig(projectID, name, "false", customZoneUpdated),
183+
Check: resource.ComposeTestCheckFunc(
184+
testAccCheckMongoDBAtlasGlobalClusterExists(resourceName, &globalConfig),
185+
resource.TestCheckResourceAttrSet(resourceName, "managed_namespaces.#"),
186+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mappings.#"),
187+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.%"),
188+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.US"),
189+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.IE"),
190+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.DE"),
191+
resource.TestCheckResourceAttrSet(resourceName, "custom_zone_mapping.JP"),
192+
resource.TestCheckResourceAttr(resourceName, "cluster_name", name),
193+
resource.TestCheckResourceAttr(resourceName, "project_id", projectID),
194+
testAccCheckMongoDBAtlasGlobalClusterAttributes(&globalConfig, 5),
195+
),
196+
},
197+
{
198+
ResourceName: resourceName,
199+
ImportStateIdFunc: testAccCheckMongoDBAtlasGlobalClusterImportStateIDFunc(resourceName),
200+
ImportState: true,
201+
ImportStateVerify: true,
202+
ImportStateVerifyIgnore: []string{"custom_zone_mappings"},
203+
},
204+
},
205+
})
206+
}
207+
122208
func testAccCheckMongoDBAtlasGlobalClusterExists(resourceName string, globalConfig *matlas.GlobalCluster) resource.TestCheckFunc {
123209
return func(s *terraform.State) error {
124210
conn := testAccProvider.Meta().(*MongoDBClient).Atlas
@@ -295,3 +381,104 @@ func testAccMongoDBAtlasGlobalClusterWithAWSClusterConfig(projectID, name, backu
295381
}
296382
`, projectID, name, backupEnabled)
297383
}
384+
385+
func testAccMongoDBAtlasGlobalClusterWithDBConfig(projectID, name, backupEnabled, zones string) string {
386+
return fmt.Sprintf(`
387+
resource "mongodbatlas_database_user" "test" {
388+
username = "horizonv2-sg"
389+
password = "password testing something"
390+
project_id = %[1]q
391+
auth_database_name = "admin"
392+
393+
roles {
394+
role_name = "readWrite"
395+
database_name = "horizonv2-sg"
396+
}
397+
}
398+
399+
resource "mongodbatlas_cluster" "test" {
400+
project_id = %[1]q
401+
name = %[2]q
402+
disk_size_gb = 80
403+
cloud_backup = %[3]s
404+
cluster_type = "GEOSHARDED"
405+
406+
// Provider Settings "block"
407+
provider_name = "AWS"
408+
provider_instance_size_name = "M30"
409+
410+
replication_specs {
411+
zone_name = "US"
412+
num_shards = 1
413+
regions_config {
414+
region_name = "US_EAST_1"
415+
electable_nodes = 3
416+
priority = 7
417+
read_only_nodes = 0
418+
}
419+
}
420+
replication_specs {
421+
zone_name = "EU"
422+
num_shards = 1
423+
regions_config {
424+
region_name = "EU_WEST_1"
425+
electable_nodes = 3
426+
priority = 7
427+
read_only_nodes = 0
428+
}
429+
}
430+
replication_specs {
431+
zone_name = "DE"
432+
num_shards = 1
433+
regions_config {
434+
region_name = "EU_NORTH_1"
435+
electable_nodes = 3
436+
priority = 7
437+
read_only_nodes = 0
438+
}
439+
}
440+
replication_specs {
441+
zone_name = "JP"
442+
num_shards = 1
443+
regions_config {
444+
region_name = "AP_NORTHEAST_1"
445+
electable_nodes = 3
446+
priority = 7
447+
read_only_nodes = 0
448+
}
449+
}
450+
}
451+
452+
resource "mongodbatlas_global_cluster_config" "test" {
453+
project_id = mongodbatlas_cluster.test.project_id
454+
cluster_name = mongodbatlas_cluster.test.name
455+
456+
managed_namespaces {
457+
db = "horizonv2-sg"
458+
collection = "entitlements.entitlement"
459+
custom_shard_key = "orgId"
460+
}
461+
managed_namespaces {
462+
db = "horizonv2-sg"
463+
collection = "entitlements.homesitemapping"
464+
custom_shard_key = "orgId"
465+
}
466+
managed_namespaces {
467+
db = "horizonv2-sg"
468+
collection = "entitlements.site"
469+
custom_shard_key = "orgId"
470+
}
471+
managed_namespaces {
472+
db = "horizonv2-sg"
473+
collection = "entitlements.userDesktopMapping"
474+
custom_shard_key = "orgId"
475+
}
476+
managed_namespaces {
477+
db = "horizonv2-sg"
478+
collection = "session"
479+
custom_shard_key = "orgId"
480+
}
481+
%s
482+
}
483+
`, projectID, name, backupEnabled, zones)
484+
}

0 commit comments

Comments
 (0)