Skip to content

Commit 0900ebc

Browse files
lantoliCopilot
andauthored
feat: Convert from blocks to nested attributes in advancedClusterToV2 command (#61)
Co-authored-by: Copilot <[email protected]>
1 parent 6c18dc0 commit 0900ebc

16 files changed

+593
-40
lines changed

internal/cli/clu2adv/clu2adv.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ import (
1010

1111
func Builder() *cobra.Command {
1212
o := &struct {
13-
*cli.BaseOpts
13+
cli.BaseOpts
1414
includeMoved bool
1515
}{
16-
BaseOpts: &cli.BaseOpts{
16+
BaseOpts: cli.BaseOpts{
1717
Fs: afero.NewOsFs(),
1818
},
1919
}
@@ -28,7 +28,7 @@ func Builder() *cobra.Command {
2828
Aliases: []string{"clu2adv"},
2929
RunE: o.RunE,
3030
}
31-
cli.SetupCommonFlags(cmd, o.BaseOpts)
31+
cli.SetupCommonFlags(cmd, &o.BaseOpts)
3232
cmd.Flags().BoolVarP(&o.includeMoved, flag.IncludeMoved, flag.IncludeMovedShort, false,
3333
"include moved blocks in the output file")
3434
return cmd

internal/convert/adv2v2.go

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package convert
22

3-
import "github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/hcl"
3+
import (
4+
"slices"
5+
6+
"github.com/hashicorp/hcl/v2/hclwrite"
7+
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/hcl"
8+
)
49

510
// AdvancedClusterToV2 transforms all mongodbatlas_advanced_cluster resource definitions in a
611
// Terraform configuration file from SDKv2 schema to TPF (Terraform Plugin Framework) schema.
@@ -11,5 +16,91 @@ func AdvancedClusterToV2(config []byte) ([]byte, error) {
1116
if err != nil {
1217
return nil, err
1318
}
19+
parserb := parser.Body()
20+
for _, block := range parserb.Blocks() {
21+
updated, err := updateResource(block)
22+
if err != nil {
23+
return nil, err
24+
}
25+
if updated { // If the resource was converted, add a comment at the end so user knows the resource was updated
26+
blockb := block.Body()
27+
blockb.AppendNewline()
28+
hcl.AppendComment(blockb, commentUpdatedBy)
29+
}
30+
}
1431
return parser.Bytes(), nil
1532
}
33+
34+
func updateResource(resource *hclwrite.Block) (bool, error) {
35+
if resource.Type() != resourceType || getResourceName(resource) != advCluster {
36+
return false, nil
37+
}
38+
resourceb := resource.Body()
39+
if hasExpectedBlocksAsAttributes(resourceb) {
40+
return false, nil
41+
}
42+
if err := convertRepSpecs(resourceb); err != nil {
43+
return false, err
44+
}
45+
if err := fillTagsLabelsOpt(resourceb, nTags); err != nil {
46+
return false, err
47+
}
48+
if err := fillTagsLabelsOpt(resourceb, nLabels); err != nil {
49+
return false, err
50+
}
51+
fillBlockOpt(resourceb, nAdvConf)
52+
fillBlockOpt(resourceb, nBiConnector)
53+
fillBlockOpt(resourceb, nPinnedFCV)
54+
fillBlockOpt(resourceb, nTimeouts)
55+
return true, nil
56+
}
57+
58+
func convertRepSpecs(resourceb *hclwrite.Body) error {
59+
block := resourceb.FirstMatchingBlock(nRepSpecs, nil)
60+
if block == nil {
61+
return nil
62+
}
63+
resourceb.RemoveBlock(block)
64+
if err := convertConfig(block.Body()); err != nil {
65+
return err
66+
}
67+
resourceb.SetAttributeRaw(nRepSpecs, hcl.TokensArraySingle(block.Body()))
68+
return nil
69+
}
70+
71+
func convertConfig(repSpecs *hclwrite.Body) error {
72+
block := repSpecs.FirstMatchingBlock(nConfig, nil)
73+
if block == nil {
74+
return nil
75+
}
76+
repSpecs.RemoveBlock(block)
77+
blockb := block.Body()
78+
fillBlockOpt(blockb, nElectableSpecs)
79+
fillBlockOpt(blockb, nReadOnlySpecs)
80+
fillBlockOpt(blockb, nAnalyticsSpecs)
81+
fillBlockOpt(blockb, nAutoScaling)
82+
fillBlockOpt(blockb, nAnalyticsAutoScaling)
83+
repSpecs.SetAttributeRaw(nConfig, hcl.TokensArraySingle(blockb))
84+
return nil
85+
}
86+
87+
// hasExpectedBlocksAsAttributes checks if any of the expected block names
88+
// exist as attributes in the resource body. In that case conversion is not done
89+
// as advanced cluster is not in a valid SDKv2 configuration.
90+
func hasExpectedBlocksAsAttributes(resourceb *hclwrite.Body) bool {
91+
expectedBlocks := []string{
92+
nRepSpecs,
93+
nTags,
94+
nLabels,
95+
nAdvConf,
96+
nBiConnector,
97+
nPinnedFCV,
98+
nTimeouts,
99+
}
100+
for name := range resourceb.Attributes() {
101+
if slices.Contains(expectedBlocks, name) {
102+
return true
103+
}
104+
}
105+
return false
106+
}

internal/convert/clu2adv.go

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,6 @@ import (
1313
"github.com/zclconf/go-cty/cty"
1414
)
1515

16-
const (
17-
resourceType = "resource"
18-
dataSourceType = "data"
19-
cluster = "mongodbatlas_cluster"
20-
advCluster = "mongodbatlas_advanced_cluster"
21-
clusterPlural = "mongodbatlas_clusters"
22-
advClusterPlural = "mongodbatlas_advanced_clusters"
23-
valClusterType = "REPLICASET"
24-
valMaxPriority = 7
25-
valMinPriority = 0
26-
errFreeCluster = "free cluster (because no " + nRepSpecs + ")"
27-
errRepSpecs = "setting " + nRepSpecs
28-
errConfigs = "setting " + nConfig
29-
errPriority = "setting " + nPriority
30-
errNumShards = "setting " + nNumShards
31-
32-
commentGeneratedBy = "Generated by atlas-cli-plugin-terraform."
33-
commentConfirmReferences = "Please review the changes and confirm that references to this resource are updated."
34-
commentMovedBlock = "Moved blocks"
35-
commentRemovedOld = "Note: Remember to remove or comment out the old cluster definitions."
36-
commentPriorityFor = "Regions must be sorted by priority in descending order."
37-
)
38-
3916
var (
4017
dynamicBlockAllowList = []string{nTags, nLabels, nConfigSrc, nRepSpecs}
4118
)
@@ -188,10 +165,10 @@ func fillCluster(resourceb *hclwrite.Body) error {
188165
if err := fillTagsLabelsOpt(resourceb, nLabels); err != nil {
189166
return err
190167
}
191-
fillBlockOpt(resourceb, nTimeouts)
192168
fillBlockOpt(resourceb, nAdvConf)
193169
fillBlockOpt(resourceb, nBiConnector)
194170
fillBlockOpt(resourceb, nPinnedFCV)
171+
fillBlockOpt(resourceb, nTimeouts)
195172
return nil
196173
}
197174

internal/convert/const_names.go renamed to internal/convert/const.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,27 @@
11
package convert
22

33
const (
4+
resourceType = "resource"
5+
dataSourceType = "data"
6+
cluster = "mongodbatlas_cluster"
7+
advCluster = "mongodbatlas_advanced_cluster"
8+
clusterPlural = "mongodbatlas_clusters"
9+
advClusterPlural = "mongodbatlas_advanced_clusters"
10+
valClusterType = "REPLICASET"
11+
valMaxPriority = 7
12+
valMinPriority = 0
13+
errFreeCluster = "free cluster (because no " + nRepSpecs + ")"
14+
errRepSpecs = "setting " + nRepSpecs
15+
errPriority = "setting " + nPriority
16+
errNumShards = "setting " + nNumShards
17+
18+
commentGeneratedBy = "Generated by atlas-cli-plugin-terraform."
19+
commentConfirmReferences = "Please review the changes and confirm that references to this resource are updated."
20+
commentUpdatedBy = "Updated by atlas-cli-plugin-terraform, please review the changes."
21+
commentMovedBlock = "Moved blocks"
22+
commentRemovedOld = "Note: Remember to remove or comment out the old cluster definitions."
23+
commentPriorityFor = "Regions must be sorted by priority in descending order."
24+
425
nRepSpecs = "replication_specs"
526
nConfig = "region_configs"
627
nConfigSrc = "regions_config"
@@ -12,6 +33,7 @@ const (
1233
nBiConnector = "bi_connector_config"
1334
nElectableSpecs = "electable_specs"
1435
nAutoScaling = "auto_scaling"
36+
nAnalyticsAutoScaling = "analytics_auto_scaling"
1537
nReadOnlySpecs = "read_only_specs"
1638
nAnalyticsSpecs = "analytics_specs"
1739
nRegionNameSrc = "provider_region_name"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
resource "mongodbatlas_advanced_cluster" "this" {
2+
project_id = var.project_id
3+
name = var.cluster_name
4+
cluster_type = "REPLICASET"
5+
replication_specs {
6+
region_configs {
7+
priority = 7
8+
provider_name = "AWS"
9+
region_name = "EU_WEST_1"
10+
electable_specs {
11+
instance_size = "M10"
12+
node_count = 3
13+
}
14+
}
15+
}
16+
17+
advanced_configuration {
18+
# comments in advanced_configuration are kept
19+
javascript_enabled = true
20+
}
21+
22+
bi_connector_config {
23+
# comments in bi_connector_config are kept
24+
enabled = true
25+
read_preference = "secondary"
26+
}
27+
28+
pinned_fcv {
29+
# comments in pinned_fcv are kept
30+
expiration_date = var.fcv_date
31+
}
32+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
resource "mongodbatlas_advanced_cluster" "this" {
2+
project_id = var.project_id
3+
name = var.cluster_name
4+
cluster_type = "REPLICASET"
5+
6+
7+
8+
replication_specs = [
9+
{
10+
region_configs = [
11+
{
12+
priority = 7
13+
provider_name = "AWS"
14+
region_name = "EU_WEST_1"
15+
electable_specs = {
16+
instance_size = "M10"
17+
node_count = 3
18+
}
19+
}
20+
]
21+
}
22+
]
23+
advanced_configuration = {
24+
# comments in advanced_configuration are kept
25+
javascript_enabled = true
26+
}
27+
bi_connector_config = {
28+
# comments in bi_connector_config are kept
29+
enabled = true
30+
read_preference = "secondary"
31+
}
32+
pinned_fcv = {
33+
# comments in pinned_fcv are kept
34+
expiration_date = var.fcv_date
35+
}
36+
37+
# Updated by atlas-cli-plugin-terraform, please review the changes.
38+
}
Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
resource "mongodbatlas_advanced_cluster" "basic" {
2-
name = "basic"
3-
// TODO: missing fields as transformation is not implemented yet
1+
resource "mongodbatlas_advanced_cluster" "clu" {
2+
project_id = var.project_id
3+
name = "clu"
4+
cluster_type = "REPLICASET"
5+
replication_specs {
6+
region_configs {
7+
priority = 7
8+
provider_name = "AWS"
9+
region_name = "EU_WEST_1"
10+
electable_specs {
11+
instance_size = "M10"
12+
node_count = 3
13+
}
14+
}
15+
}
416
}
Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,22 @@
1-
resource "mongodbatlas_advanced_cluster" "basic" {
2-
name = "basic"
3-
// TODO: missing fields as transformation is not implemented yet
1+
resource "mongodbatlas_advanced_cluster" "clu" {
2+
project_id = var.project_id
3+
name = "clu"
4+
cluster_type = "REPLICASET"
5+
replication_specs = [
6+
{
7+
region_configs = [
8+
{
9+
priority = 7
10+
provider_name = "AWS"
11+
region_name = "EU_WEST_1"
12+
electable_specs = {
13+
instance_size = "M10"
14+
node_count = 3
15+
}
16+
}
17+
]
18+
}
19+
]
20+
21+
# Updated by atlas-cli-plugin-terraform, please review the changes.
422
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
resource "mongodbatlas_advanced_cluster" "this" {
2+
# updated, doesn't have nested attributes
3+
}
4+
5+
resource "mongodbatlas_advanced_cluster" "this" {
6+
# not updated, replication_specs is not a block, resource already in TPF format
7+
project_id = var.project_id
8+
name = "this"
9+
cluster_type = "REPLICASET"
10+
replication_specs = [
11+
{
12+
region_configs = [
13+
{
14+
priority = 7
15+
provider_name = "AWS"
16+
region_name = "EU_WEST_1"
17+
electable_specs = {
18+
instance_size = "M10"
19+
node_count = 3
20+
}
21+
}
22+
]
23+
}
24+
]
25+
}
26+
27+
resource "mongodbatlas_advanced_cluster" "this" {
28+
# not updated, has an attribute instead of block (timeouts)
29+
timeouts = {
30+
create = "60m"
31+
}
32+
}
33+
34+
datasource "mongodbatlas_advanced_cluster" "this" {
35+
# not updated, data source
36+
}
37+
38+
resource "another_resource" "this" {
39+
# not updated, not advanced cluster
40+
}

0 commit comments

Comments
 (0)