@@ -11,7 +11,6 @@ import (
11
11
// AdvancedClusterToV2 transforms all mongodbatlas_advanced_cluster resource definitions in a
12
12
// Terraform configuration file from SDKv2 schema to TPF (Terraform Plugin Framework) schema.
13
13
// All other resources and data sources are left untouched.
14
- // TODO: Not implemented yet.
15
14
func AdvancedClusterToV2 (config []byte ) ([]byte , error ) {
16
15
parser , err := hcl .GetParser (config )
17
16
if err != nil {
@@ -58,7 +57,6 @@ func updateResource(resource *hclwrite.Block) (bool, error) {
58
57
}
59
58
60
59
func convertRepSpecs (resourceb * hclwrite.Body , diskSizeGB hclwrite.Tokens ) error {
61
- // Handle dynamic blocks for replication_specs
62
60
dSpec , err := getDynamicBlock (resourceb , nRepSpecs )
63
61
if err != nil {
64
62
return err
@@ -67,17 +65,12 @@ func convertRepSpecs(resourceb *hclwrite.Body, diskSizeGB hclwrite.Tokens) error
67
65
return convertDynamicRepSpecs (resourceb , dSpec , diskSizeGB )
68
66
}
69
67
70
- // Collect all replication_specs blocks first
71
68
repSpecBlocks := collectBlocks (resourceb , nRepSpecs )
72
-
73
69
if len (repSpecBlocks ) == 0 {
74
70
return fmt .Errorf ("must have at least one replication_specs" )
75
71
}
76
72
77
- // Check if any replication_specs has a variable num_shards
78
- hasVariableNumShards := HasVariableNumShards (repSpecBlocks )
79
-
80
- if hasVariableNumShards {
73
+ if hasVariableNumShards (repSpecBlocks ) {
81
74
var concatParts []hclwrite.Tokens
82
75
83
76
for _ , block := range repSpecBlocks {
@@ -89,7 +82,7 @@ func convertRepSpecs(resourceb *hclwrite.Body, diskSizeGB hclwrite.Tokens) error
89
82
return err
90
83
}
91
84
92
- tokens , err := ProcessNumShards (numShardsAttr , blockb )
85
+ tokens , err := processNumShards (numShardsAttr , blockb )
93
86
if err != nil {
94
87
return err
95
88
}
@@ -125,10 +118,7 @@ func convertRepSpecs(resourceb *hclwrite.Body, diskSizeGB hclwrite.Tokens) error
125
118
}
126
119
127
120
func convertDynamicRepSpecs (resourceb * hclwrite.Body , dSpec dynamicBlock , diskSizeGB hclwrite.Tokens ) error {
128
- // Transform references from replication_specs.value.* to spec.*
129
121
transformDynamicBlockReferences (dSpec .content .Body (), nRepSpecs , nSpec )
130
-
131
- // Check for dynamic region_configs within this dynamic replication_specs
132
122
dConfig , err := getDynamicBlock (dSpec .content .Body (), nConfig )
133
123
if err != nil {
134
124
return err
@@ -139,150 +129,98 @@ func convertDynamicRepSpecs(resourceb *hclwrite.Body, dSpec dynamicBlock, diskSi
139
129
return err
140
130
}
141
131
}
142
-
143
132
if dConfig .IsPresent () {
144
- // Handle nested dynamic block for region_configs
145
133
return convertDynamicRepSpecsWithDynamicConfig (resourceb , dSpec , dConfig , diskSizeGB )
146
134
}
147
-
148
- // Get num_shards from the dynamic block content
149
135
numShardsAttr := dSpec .content .Body ().GetAttribute (nNumShards )
150
136
if numShardsAttr != nil {
151
137
numShardsExpr := replaceDynamicBlockReferences (hcl .GetAttrExpr (numShardsAttr ), nRepSpecs , nSpec )
152
138
dSpec .content .Body ().RemoveAttribute (nNumShards )
153
-
154
- // Convert region_configs inside the dynamic block
155
139
if err := convertConfig (dSpec .content .Body (), diskSizeGB ); err != nil {
156
140
return err
157
141
}
158
-
159
- // Create the for expression for the flattened replication_specs
160
142
outerFor := buildForExpr (nSpec , hcl .GetAttrExpr (dSpec .forEach ))
161
143
innerFor := buildForExpr ("i" , fmt .Sprintf ("range(%s)" , numShardsExpr ))
162
144
forExpr := fmt .Sprintf ("%s [\n %s " , outerFor , innerFor )
163
145
tokens := hcl .TokensFromExpr (forExpr )
164
146
tokens = append (tokens , hcl .TokensObject (dSpec .content .Body ())... )
165
147
tokens = append (tokens , hcl .TokensFromExpr ("\n ]\n ]" )... )
166
-
167
148
resourceb .RemoveBlock (dSpec .block )
168
149
resourceb .SetAttributeRaw (nRepSpecs , hcl .TokensFuncFlatten (tokens ))
169
150
return nil
170
151
}
171
- // No num_shards, default to 1
172
152
dSpec .content .Body ().RemoveAttribute (nNumShards )
173
-
174
- // Convert region_configs inside the dynamic block
175
153
if err := convertConfig (dSpec .content .Body (), diskSizeGB ); err != nil {
176
154
return err
177
155
}
178
-
179
- // Create the for expression without num_shards
180
156
forExpr := buildForExpr (nSpec , hcl .GetAttrExpr (dSpec .forEach ))
181
157
tokens := hcl .TokensFromExpr (forExpr )
182
158
tokens = append (tokens , hcl .TokensObject (dSpec .content .Body ())... )
183
159
tokens = hcl .EncloseBracketsNewLines (tokens )
184
-
185
160
resourceb .RemoveBlock (dSpec .block )
186
161
resourceb .SetAttributeRaw (nRepSpecs , tokens )
187
162
return nil
188
163
}
189
164
190
- // Helper function to process blocks for region configs
191
165
func processRegionConfigBlocks (targetBody * hclwrite.Body , blocks []* hclwrite.Block , diskSizeGB hclwrite.Tokens ) {
192
166
for _ , block := range blocks {
193
167
blockType := block .Type ()
194
168
blockFile := hclwrite .NewEmptyFile ()
195
169
blockBody := blockFile .Body ()
196
-
197
- // Copy all attributes in deterministic order
198
170
copyAttributesSorted (blockBody , block .Body ().Attributes ())
199
-
200
- // Add disk_size_gb to specs blocks if needed
201
171
if diskSizeGB != nil && (blockType == nElectableSpecs ||
202
172
blockType == nReadOnlySpecs || blockType == nAnalyticsSpecs ) {
203
173
blockBody .SetAttributeRaw (nDiskSizeGB , diskSizeGB )
204
174
}
205
-
206
175
targetBody .SetAttributeRaw (blockType , hcl .TokensObject (blockBody ))
207
176
}
208
177
}
209
178
210
179
func convertDynamicRepSpecsWithDynamicConfig (resourceb * hclwrite.Body , dSpec , dConfig dynamicBlock ,
211
180
diskSizeGB hclwrite.Tokens ) error {
212
- // Get the block name from the dynamic block
213
181
configBlockName := getResourceName (dConfig .block )
214
-
215
- // Get num_shards expression
216
182
numShardsAttr := dSpec .content .Body ().GetAttribute (nNumShards )
217
183
if numShardsAttr != nil {
218
184
numShardsExpr := replaceDynamicBlockReferences (hcl .GetAttrExpr (numShardsAttr ), nRepSpecs , nSpec )
219
-
220
- // Transform references in place for the dynamic config content
221
185
transformDynamicBlockReferencesRecursive (dConfig .content .Body (), configBlockName , nRegion )
222
- // Also transform outer references (with deterministic ordering)
223
186
transform := func (expr string ) string {
224
187
return replaceDynamicBlockReferences (expr , nRepSpecs , nSpec )
225
188
}
226
189
transformAttributesSorted (dConfig .content .Body (), dConfig .content .Body ().Attributes (), transform )
227
190
for _ , block := range dConfig .content .Body ().Blocks () {
228
191
transformAttributesSorted (block .Body (), block .Body ().Attributes (), transform )
229
192
}
230
-
231
- // Build the expression using HCL functions
232
- // Use standardized property name (region_configs) instead of the actual for_each collection
233
193
configForEach := fmt .Sprintf ("%s.%s" , nSpec , nConfig )
234
-
235
- // Create the inner region_configs body
236
194
regionConfigFile := hclwrite .NewEmptyFile ()
237
195
regionConfigBody := regionConfigFile .Body ()
238
-
239
- // Copy all attributes in deterministic order
240
196
copyAttributesSorted (regionConfigBody , dConfig .content .Body ().Attributes ())
241
-
242
- // Add all blocks generically as objects
243
197
processRegionConfigBlocks (regionConfigBody , dConfig .content .Body ().Blocks (), diskSizeGB )
244
-
245
- // Build the region_configs for expression
246
198
regionForExpr := buildForExpr (nRegion , configForEach )
247
199
regionTokens := hcl .TokensFromExpr (regionForExpr )
248
200
regionTokens = append (regionTokens , hcl .TokensObject (regionConfigBody )... )
249
-
250
- // Create the replication spec body
251
201
repSpecFile := hclwrite .NewEmptyFile ()
252
202
repSpecBody := repSpecFile .Body ()
253
-
254
203
if zoneNameAttr := dSpec .content .Body ().GetAttribute (nZoneName ); zoneNameAttr != nil {
255
204
zoneNameExpr := replaceDynamicBlockReferences (hcl .GetAttrExpr (zoneNameAttr ), nRepSpecs , nSpec )
256
205
repSpecBody .SetAttributeRaw (nZoneName , hcl .TokensFromExpr (zoneNameExpr ))
257
206
}
258
-
259
207
repSpecBody .SetAttributeRaw (nConfig , hcl .EncloseBracketsNewLines (regionTokens ))
260
-
261
- // Build the inner for expression with range
262
208
innerForExpr := buildForExpr ("i" , fmt .Sprintf ("range(%s)" , numShardsExpr ))
263
209
innerTokens := hcl .TokensFromExpr (innerForExpr )
264
210
innerTokens = append (innerTokens , hcl .TokensObject (repSpecBody )... )
265
-
266
- // Build the outer for expression
267
211
outerForExpr := buildForExpr (nSpec , hcl .GetAttrExpr (dSpec .forEach ))
268
212
outerTokens := hcl .TokensFromExpr (fmt .Sprintf ("%s " , outerForExpr ))
269
213
outerTokens = append (outerTokens , hcl .EncloseBracketsNewLines (innerTokens )... )
270
-
271
- // Apply flatten to the entire expression
272
214
tokens := hcl .TokensFuncFlatten (outerTokens )
273
-
274
215
resourceb .RemoveBlock (dSpec .block )
275
216
resourceb .SetAttributeRaw (nRepSpecs , tokens )
276
217
return nil
277
218
}
278
- // No num_shards, handle like without nested shards
279
219
return convertDynamicRepSpecsWithoutNumShards (resourceb , dSpec , dConfig , diskSizeGB , configBlockName )
280
220
}
281
221
282
- // Helper function to add attributes with transformation
283
222
func addAttributesWithTransform (targetBody * hclwrite.Body , sourceAttrs map [string ]* hclwrite.Attribute ,
284
223
configBlockName string ) {
285
- // Apply transformations in order
286
224
transform1 := func (expr string ) string {
287
225
return replaceDynamicBlockReferences (expr , configBlockName , nRegion )
288
226
}
@@ -294,59 +232,36 @@ func addAttributesWithTransform(targetBody *hclwrite.Body, sourceAttrs map[strin
294
232
295
233
func convertDynamicRepSpecsWithoutNumShards (resourceb * hclwrite.Body , dSpec , dConfig dynamicBlock ,
296
234
diskSizeGB hclwrite.Tokens , configBlockName string ) error {
297
- // Get zone_name if present
298
235
repSpecFile := hclwrite .NewEmptyFile ()
299
236
repSpecb := repSpecFile .Body ()
300
-
301
237
if zoneNameAttr := dSpec .content .Body ().GetAttribute (nZoneName ); zoneNameAttr != nil {
302
238
zoneNameExpr := replaceDynamicBlockReferences (hcl .GetAttrExpr (zoneNameAttr ), nRepSpecs , nSpec )
303
239
repSpecb .SetAttributeRaw (nZoneName , hcl .TokensFromExpr (zoneNameExpr ))
304
240
}
305
-
306
- // Create config content with transformed references
307
241
configFile := hclwrite .NewEmptyFile ()
308
242
configb := configFile .Body ()
309
-
310
- // Copy and transform attributes
311
243
addAttributesWithTransform (configb , dConfig .content .Body ().Attributes (), configBlockName )
312
-
313
- // Process blocks and transform their references
314
244
for _ , block := range dConfig .content .Body ().Blocks () {
315
245
newBlock := configb .AppendNewBlock (block .Type (), block .Labels ())
316
246
newBlockb := newBlock .Body ()
317
247
addAttributesWithTransform (newBlockb , block .Body ().Attributes (), configBlockName )
318
248
}
319
-
320
- // Process specs
321
249
processAllSpecs (configb , diskSizeGB )
322
-
323
- // Build the nested for expression for region_configs
324
- // Use standardized property name (region_configs) instead of the actual for_each collection
325
250
configForEach := fmt .Sprintf ("%s.%s" , nSpec , nConfig )
326
-
327
- // Build the region_configs for expression
328
251
regionForExpr := buildForExpr (nRegion , configForEach )
329
252
regionTokens := hcl .TokensFromExpr (regionForExpr )
330
253
regionTokens = append (regionTokens , hcl .TokensObject (configb )... )
331
-
332
254
repSpecb .SetAttributeRaw (nConfig , hcl .EncloseBracketsNewLines (regionTokens ))
333
-
334
- // Build the for expression as an array wrapped in flatten
335
- // Format: flatten([for spec in ... : [ { ... } ] ])
336
255
forExpr := buildForExpr (nSpec , hcl .GetAttrExpr (dSpec .forEach ))
337
256
innerTokens := hcl .TokensFromExpr (fmt .Sprintf ("%s " , forExpr ))
338
257
innerTokens = append (innerTokens , hcl .TokensArraySingle (repSpecb )... )
339
-
340
- // Apply flatten to the entire expression
341
258
tokens := hcl .TokensFuncFlatten (innerTokens )
342
-
343
259
resourceb .RemoveBlock (dSpec .block )
344
260
resourceb .SetAttributeRaw (nRepSpecs , tokens )
345
261
return nil
346
262
}
347
263
348
264
func convertConfig (repSpecs * hclwrite.Body , diskSizeGB hclwrite.Tokens ) error {
349
- // Check for dynamic region_configs block (can be either "region_configs" or "regions_config")
350
265
dConfig , err := getDynamicBlock (repSpecs , nConfig )
351
266
if err != nil {
352
267
return err
@@ -357,12 +272,9 @@ func convertConfig(repSpecs *hclwrite.Body, diskSizeGB hclwrite.Tokens) error {
357
272
return err
358
273
}
359
274
}
360
-
361
275
if dConfig .IsPresent () {
362
- // Handle dynamic region_configs
363
276
return convertDynamicConfig (repSpecs , dConfig , diskSizeGB )
364
277
}
365
-
366
278
var configs []* hclwrite.Body
367
279
for _ , block := range collectBlocks (repSpecs , nConfig ) {
368
280
blockb := block .Body ()
@@ -377,21 +289,13 @@ func convertConfig(repSpecs *hclwrite.Body, diskSizeGB hclwrite.Tokens) error {
377
289
}
378
290
379
291
func convertDynamicConfig (repSpecs * hclwrite.Body , dConfig dynamicBlock , diskSizeGB hclwrite.Tokens ) error {
380
- // Get the block name from the dynamic block itself
381
292
blockName := getResourceName (dConfig .block )
382
-
383
- // Transform the references in attributes and blocks
384
293
transformDynamicBlockReferencesRecursive (dConfig .content .Body (), blockName , nRegion )
385
-
386
- // Process specs
387
294
processAllSpecs (dConfig .content .Body (), diskSizeGB )
388
-
389
- // Build the for expression
390
295
forExpr := buildForExpr (nRegion , hcl .GetAttrExpr (dConfig .forEach ))
391
296
tokens := hcl .TokensFromExpr (forExpr )
392
297
tokens = append (tokens , hcl .TokensObject (dConfig .content .Body ())... )
393
298
tokens = hcl .EncloseBracketsNewLines (tokens )
394
-
395
299
repSpecs .RemoveBlock (dConfig .block )
396
300
repSpecs .SetAttributeRaw (nConfig , tokens )
397
301
return nil
@@ -401,15 +305,7 @@ func convertDynamicConfig(repSpecs *hclwrite.Body, dConfig dynamicBlock, diskSiz
401
305
// exist as attributes in the resource body. In that case conversion is not done
402
306
// as advanced cluster is not in a valid SDKv2 configuration.
403
307
func hasExpectedBlocksAsAttributes (resourceb * hclwrite.Body ) bool {
404
- expectedBlocks := []string {
405
- nRepSpecs ,
406
- nTags ,
407
- nLabels ,
408
- nAdvConfig ,
409
- nBiConnector ,
410
- nPinnedFCV ,
411
- nTimeouts ,
412
- }
308
+ expectedBlocks := []string {nRepSpecs , nTags , nLabels , nAdvConfig , nBiConnector , nPinnedFCV , nTimeouts }
413
309
for name := range resourceb .Attributes () {
414
310
if slices .Contains (expectedBlocks , name ) {
415
311
return true
0 commit comments