Skip to content

Commit 26fe17d

Browse files
committed
checkDynamicBlock
1 parent 383396a commit 26fe17d

File tree

8 files changed

+83
-51
lines changed

8 files changed

+83
-51
lines changed

internal/convert/adv2v2.go

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ func updateResource(resource *hclwrite.Block) (bool, error) {
3636
return false, nil
3737
}
3838
resourceb := resource.Body()
39+
if errDyn := checkDynamicBlock(resourceb); errDyn != nil {
40+
return false, errDyn
41+
}
3942
if hasExpectedBlocksAsAttributes(resourceb) {
4043
return false, nil
4144
}
@@ -194,10 +197,24 @@ func buildDynamicRepSpecsWithNumShards(dSpec, dConfig dynamicBlock, diskSizeGB h
194197
transformAttributesSorted(block.Body(), block.Body().Attributes(), transform)
195198
}
196199
regionConfigBody := buildRegionConfigBody(dConfig, diskSizeGB)
197-
regionTokens := buildRegionForExpr(nSpec, regionConfigBody)
200+
201+
configForEach := fmt.Sprintf("%s.%s", nSpec, nConfig)
202+
regionForExpr := buildForExpr(nRegion, configForEach, false)
203+
regionTokens := hcl.TokensFromExpr(regionForExpr)
204+
regionTokens = append(regionTokens, hcl.TokensObject(regionConfigBody)...)
205+
198206
repSpecBody := buildRepSpecBody(dSpec, regionTokens)
199-
innerTokens := buildInnerForExpr(numShardsExpr, repSpecBody)
200-
outerTokens := buildOuterForExpr(dSpec, innerTokens)
207+
208+
// Inline buildInnerForExpr
209+
innerForExpr := buildForExpr("i", fmt.Sprintf("range(%s)", numShardsExpr), false)
210+
innerTokens := hcl.TokensFromExpr(innerForExpr)
211+
innerTokens = append(innerTokens, hcl.TokensObject(repSpecBody)...)
212+
213+
// Inline buildOuterForExpr
214+
outerForExpr := buildForExpr(nSpec, hcl.GetAttrExpr(dSpec.forEach), true)
215+
outerTokens := hcl.TokensFromExpr(outerForExpr)
216+
outerTokens = append(outerTokens, hcl.EncloseBracketsNewLines(innerTokens)...)
217+
201218
return hcl.TokensFuncFlatten(outerTokens), nil
202219
}
203220

@@ -209,13 +226,6 @@ func buildRegionConfigBody(dConfig dynamicBlock, diskSizeGB hclwrite.Tokens) *hc
209226
return regionConfigBody
210227
}
211228

212-
func buildRegionForExpr(spec string, regionConfigBody *hclwrite.Body) hclwrite.Tokens {
213-
configForEach := fmt.Sprintf("%s.%s", spec, nConfig)
214-
regionForExpr := buildForExpr(nRegion, configForEach, false)
215-
regionTokens := hcl.TokensFromExpr(regionForExpr)
216-
return append(regionTokens, hcl.TokensObject(regionConfigBody)...)
217-
}
218-
219229
func buildRepSpecBody(dSpec dynamicBlock, regionTokens hclwrite.Tokens) *hclwrite.Body {
220230
repSpecFile := hclwrite.NewEmptyFile()
221231
repSpecBody := repSpecFile.Body()
@@ -227,18 +237,6 @@ func buildRepSpecBody(dSpec dynamicBlock, regionTokens hclwrite.Tokens) *hclwrit
227237
return repSpecBody
228238
}
229239

230-
func buildInnerForExpr(numShardsExpr string, repSpecBody *hclwrite.Body) hclwrite.Tokens {
231-
innerForExpr := buildForExpr("i", fmt.Sprintf("range(%s)", numShardsExpr), false)
232-
innerTokens := hcl.TokensFromExpr(innerForExpr)
233-
return append(innerTokens, hcl.TokensObject(repSpecBody)...)
234-
}
235-
236-
func buildOuterForExpr(dSpec dynamicBlock, innerTokens hclwrite.Tokens) hclwrite.Tokens {
237-
outerForExpr := buildForExpr(nSpec, hcl.GetAttrExpr(dSpec.forEach), true)
238-
outerTokens := hcl.TokensFromExpr(outerForExpr)
239-
return append(outerTokens, hcl.EncloseBracketsNewLines(innerTokens)...)
240-
}
241-
242240
func processRegionConfigBlocks(targetBody *hclwrite.Body, blocks []*hclwrite.Block, diskSizeGB hclwrite.Tokens) {
243241
for _, block := range blocks {
244242
blockType := block.Type()

internal/convert/clu2adv.go

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package convert
22

33
import (
44
"fmt"
5-
"slices"
65
"sort"
76
"strconv"
87
"strings"
@@ -13,10 +12,6 @@ import (
1312
"github.com/zclconf/go-cty/cty"
1413
)
1514

16-
var (
17-
dynamicBlockAllowList = []string{nTags, nLabels, nConfigSrc, nRepSpecs}
18-
)
19-
2015
type attrVals struct {
2116
req map[string]hclwrite.Tokens
2217
opt map[string]hclwrite.Tokens
@@ -236,7 +231,7 @@ func extractTagsLabelsDynamicBlock(resourceb *hclwrite.Body, name string) (hclwr
236231
valueExpr := replaceDynamicBlockExpr(value, name, nValue)
237232
collectionExpr := hcl.GetAttrExpr(d.forEach)
238233
forExpr := fmt.Sprintf("for key, value in %s : %s => %s", collectionExpr, keyExpr, valueExpr)
239-
tokens := hcl.TokensObjectFromExpr(forExpr)
234+
tokens := hcl.EncloseBraces(hcl.EncloseNewLines(hcl.TokensFromExpr(forExpr)), false)
240235
if keyExpr == nKey && valueExpr == nValue { // expression can be simplified and use for_each expression
241236
tokens = hcl.TokensFromExpr(collectionExpr)
242237
}
@@ -445,17 +440,6 @@ func getResourceLabel(resource *hclwrite.Block) string {
445440
return labels[1]
446441
}
447442

448-
func checkDynamicBlock(body *hclwrite.Body) error {
449-
for _, block := range body.Blocks() {
450-
name := getResourceName(block)
451-
if block.Type() != nDynamic || slices.Contains(dynamicBlockAllowList, name) {
452-
continue
453-
}
454-
return fmt.Errorf("dynamic blocks are not supported for %s", name)
455-
}
456-
return nil
457-
}
458-
459443
func replaceDynamicBlockExpr(attr *hclwrite.Attribute, blockName, attrName string) string {
460444
expr := hcl.GetAttrExpr(attr)
461445
return strings.ReplaceAll(expr, fmt.Sprintf("%s.%s", blockName, attrName), attrName)
@@ -570,7 +554,7 @@ func sortConfigsByPriority(configs []*hclwrite.Body) []*hclwrite.Body {
570554
}
571555

572556
func setKeyValue(body *hclwrite.Body, key, value *hclwrite.Attribute) {
573-
keyStr, err := hcl.GetAttrString(key, "")
557+
keyStr, err := hcl.GetAttrString(key)
574558
if err == nil {
575559
if !hclsyntax.ValidIdentifier(keyStr) {
576560
// wrap in quotes so invalid identifiers (e.g. with blanks) can be used as attribute names

internal/convert/shared.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ func getDynamicBlock(body *hclwrite.Body, name string) (dynamicBlock, error) {
7171
return dynamicBlock{}, nil
7272
}
7373

74+
func checkDynamicBlock(body *hclwrite.Body) error {
75+
dynamicBlockAllowList := []string{nTags, nLabels, nRepSpecs}
76+
for _, block := range body.Blocks() {
77+
name := getResourceName(block)
78+
if block.Type() != nDynamic || slices.Contains(dynamicBlockAllowList, name) {
79+
continue
80+
}
81+
return fmt.Errorf("dynamic blocks are not supported for %s", name)
82+
}
83+
return nil
84+
}
85+
7486
// getResourceName returns the first label of a block, if it exists.
7587
// e.g. in resource "mongodbatlas_cluster" "mycluster", the first label is "mongodbatlas_cluster".
7688
func getResourceName(resource *hclwrite.Block) string {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
resource "mongodbatlas_advanced_cluster" "this" {
2+
project_id = var.project_id
3+
name = "cluster"
4+
cluster_type = "REPLICASET"
5+
6+
# dynamic blocks are only supported for tags, labels, replication_specs and region_configs
7+
dynamic "advanced_configuration" {
8+
for_each = var.advanced_configuration
9+
content {
10+
javascript_enabled = advanced_configuration.value.javascript_enabled
11+
}
12+
}
13+
14+
replication_specs {
15+
region_configs {
16+
priority = 7
17+
provider_name = "AWS"
18+
region_name = "EU_WEST_1"
19+
electable_specs {
20+
instance_size = "M10"
21+
node_count = 3
22+
}
23+
}
24+
}
25+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"configuration_file_error": "failed to parse Terraform config file",
33
"replication_specs_missing_region_configs": "replication_specs must have at least one region_configs",
4-
"missing_replication_specs": "must have at least one replication_specs"
4+
"missing_replication_specs": "must have at least one replication_specs",
5+
"dynamic_unsupported_tag": "dynamic blocks are not supported for advanced_configuration"
56
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
resource "mongodbatlas_cluster" "this" {
2+
project_id = var.project_id
3+
name = var.cluster_name
4+
cluster_type = var.cluster_type
5+
mongo_db_major_version = var.mongo_db_major_version
6+
provider_instance_size_name = var.instance_size
7+
provider_name = var.provider_name
8+
9+
# dynamic blocks are only supported for tags, labels, replication_specs and regions_config
10+
dynamic "advanced_configuration" {
11+
for_each = var.advanced_configuration
12+
content {
13+
javascript_enabled = advanced_configuration.value.javascript_enabled
14+
}
15+
}
16+
}

internal/convert/testdata/clu2adv/errors.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
"free_cluster_missing_attribute": "free cluster (because no replication_specs): attribute backing_provider_name not found",
55
"regions_config_missing_priority": "setting replication_specs: attribute priority not found",
66
"replication_specs_missing_num_shards": "num_shards not found",
7-
"replication_specs_missing_regions_config": "setting replication_specs: regions_config not found"
7+
"replication_specs_missing_regions_config": "setting replication_specs: regions_config not found",
8+
"dynamic_unsupported_tag": "dynamic blocks are not supported for advanced_configuration"
89
}

internal/hcl/hcl.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,17 +65,17 @@ func GetAttrInt(attr *hclwrite.Attribute, errPrefix string) (int, error) {
6565
}
6666

6767
// GetAttrString tries to get an attribute value as a string.
68-
func GetAttrString(attr *hclwrite.Attribute, errPrefix string) (string, error) {
68+
func GetAttrString(attr *hclwrite.Attribute) (string, error) {
6969
expr, diags := hclsyntax.ParseExpression(attr.Expr().BuildTokens(nil).Bytes(), "", hcl.InitialPos)
7070
if diags.HasErrors() {
71-
return "", fmt.Errorf("%s: failed to parse string: %s", errPrefix, diags.Error())
71+
return "", fmt.Errorf("failed to parse string: %s", diags.Error())
7272
}
7373
val, diags := expr.Value(nil)
7474
if diags.HasErrors() {
75-
return "", fmt.Errorf("%s: failed to evaluate string: %s", errPrefix, diags.Error())
75+
return "", fmt.Errorf("failed to evaluate string: %s", diags.Error())
7676
}
7777
if !val.Type().Equals(cty.String) {
78-
return "", fmt.Errorf("%s: attribute is not a string", errPrefix)
78+
return "", fmt.Errorf("attribute is not a string")
7979
}
8080
return val.AsString(), nil
8181
}
@@ -106,11 +106,6 @@ func TokensFromExpr(expr string) hclwrite.Tokens {
106106
return hclwrite.Tokens{{Type: hclsyntax.TokenIdent, Bytes: []byte(expr)}}
107107
}
108108

109-
// TokensObjectFromExpr creates an object with an expression.
110-
func TokensObjectFromExpr(expr string) hclwrite.Tokens {
111-
return EncloseBraces(EncloseNewLines(TokensFromExpr(expr)), false)
112-
}
113-
114109
// TokensFuncMerge creates the tokens for the HCL merge function.
115110
func TokensFuncMerge(tokens ...hclwrite.Tokens) hclwrite.Tokens {
116111
params := EncloseNewLines(joinTokens(tokens...))

0 commit comments

Comments
 (0)