Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/convert/const_names.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ const (
nZoneName = "zone_name"
nKey = "key"
nValue = "value"
nUseRepSpecsPerShard = "use_replication_spec_per_shard"
)
111 changes: 78 additions & 33 deletions internal/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ import (
)

const (
resourceType = "resource"
cluster = "mongodbatlas_cluster"
advCluster = "mongodbatlas_advanced_cluster"
valClusterType = "REPLICASET"
valMaxPriority = 7
valMinPriority = 1
errFreeCluster = "free cluster (because no " + nRepSpecs + ")"
errRepSpecs = "setting " + nRepSpecs
errConfigs = "setting " + nConfig
errPriority = "setting " + nPriority
errNumShards = "setting " + nNumShards
resourceType = "resource"
dataSourceType = "data"
cluster = "mongodbatlas_cluster"
advCluster = "mongodbatlas_advanced_cluster"
clusterPlural = "mongodbatlas_clusters"
advClusterPlural = "mongodbatlas_advanced_clusters"
valClusterType = "REPLICASET"
valMaxPriority = 7
valMinPriority = 1
errFreeCluster = "free cluster (because no " + nRepSpecs + ")"
errRepSpecs = "setting " + nRepSpecs
errConfigs = "setting " + nConfig
errPriority = "setting " + nPriority
errNumShards = "setting " + nNumShards
)

type attrVals struct {
Expand All @@ -42,35 +45,60 @@ func ClusterToAdvancedCluster(config []byte) ([]byte, error) {
if err != nil {
return nil, err
}
for _, resource := range parser.Body().Blocks() {
labels := resource.Labels()
resourceName := labels[0]
if resource.Type() != resourceType || resourceName != cluster {
continue
}
resourceb := resource.Body()
if errDyn := checkDynamicBlock(resourceb); errDyn != nil {
return nil, errDyn
}
labels[0] = advCluster
resource.SetLabels(labels)

if resourceb.FirstMatchingBlock(nRepSpecs, nil) != nil {
err = fillCluster(resourceb)
} else {
err = fillFreeTierCluster(resourceb)
}
for _, block := range parser.Body().Blocks() {
converted, err := convertResource(block)
if err != nil {
return nil, err
}

resourceb.AppendNewline()
hcl.AppendComment(resourceb, "Generated by atlas-cli-plugin-terraform.")
hcl.AppendComment(resourceb, "Please confirm that all references to this resource are updated.")
converted = converted || convertDataSource(block)
if converted {
blockb := block.Body()
blockb.AppendNewline()
hcl.AppendComment(blockb, "Generated by atlas-cli-plugin-terraform.")
hcl.AppendComment(blockb, "Please confirm that all references to this resource are updated.")
}
}
return parser.Bytes(), nil
}

func convertResource(block *hclwrite.Block) (bool, error) {
if block.Type() != resourceType || getResourceName(block) != cluster {
return false, nil
}
setResourceName(block, advCluster)
blockb := block.Body()
if errDyn := checkDynamicBlock(blockb); errDyn != nil {
return false, errDyn
}

var err error
if blockb.FirstMatchingBlock(nRepSpecs, nil) != nil {
err = fillCluster(blockb)
} else {
err = fillFreeTierCluster(blockb)
}
if err != nil {
return false, err
}
return true, nil
}

func convertDataSource(block *hclwrite.Block) bool {
if block.Type() != dataSourceType {
return false
}
convertMap := map[string]string{
cluster: advCluster,
clusterPlural: advClusterPlural,
}
if newName, found := convertMap[getResourceName(block)]; found {
setResourceName(block, newName)
block.Body().SetAttributeValue(nUseRepSpecsPerShard, cty.True)
return true
}
return false
}

// fillFreeTierCluster is the entry point to convert clusters in free tier
func fillFreeTierCluster(resourceb *hclwrite.Body) error {
resourceb.SetAttributeValue(nClusterType, cty.StringVal(valClusterType))
Expand Down Expand Up @@ -301,6 +329,23 @@ func getAutoScalingOpt(opt map[string]hclwrite.Tokens) hclwrite.Tokens {
return hcl.TokensObject(fileb)
}

func setResourceName(resource *hclwrite.Block, name string) {
labels := resource.Labels()
if len(labels) == 0 {
return
}
labels[0] = name
resource.SetLabels(labels)
}

func getResourceName(resource *hclwrite.Block) string {
labels := resource.Labels()
if len(labels) == 0 {
return ""
}
return labels[0]
}

func checkDynamicBlock(body *hclwrite.Body) error {
for _, block := range body.Blocks() {
if block.Type() == "dynamic" {
Expand Down
50 changes: 50 additions & 0 deletions internal/convert/testdata/clu2adv/data_sources.in.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
data "mongodbatlas_cluster" "singular" {
# data source content is kept - singular
project_id = mongodbatlas_advanced_cluster.example.project_id
name = mongodbatlas_advanced_cluster.example.name
depends_on = [mongodbatlas_privatelink_endpoint_service.example_endpoint]
}

data "mongodbatlas_clusters" "plural" {
# data source content is kept - plural
project_id = mongodbatlas_advanced_cluster.example.project_id
}

data "mongodbatlas_advanced_cluster" "adv_singular" {
# adv_cluster is not changed - adv_singular
project_id = mongodbatlas_advanced_cluster.example.project_id
name = mongodbatlas_advanced_cluster.example.name
}

data "mongodbatlas_advanced_cluster" "adv_plural" {
# adv_cluster is not changed - adv_plural
project_id = mongodbatlas_advanced_cluster.example.project_id
}

resource "random_resource" "random1" {
# other resources are left unchanged - random1
hi1 = "there1"
}

data "random_datasource" "random2" {
# other resources are left unchanged - random2
hi2 = "there2"
}

# comments out of resources are kept

unknown_block "hello" {
# unkown block types are kept
}

unknown_block {
# plugin doesn't panic with unlabeled blocks - unknown_block
}

resource {
# plugin doesn't panic with unlabeled blocks - resource
}

data {
# plugin doesn't panic with unlabeled blocks - data
}
58 changes: 58 additions & 0 deletions internal/convert/testdata/clu2adv/data_sources.out.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
data "mongodbatlas_advanced_cluster" "singular" {
# data source content is kept - singular
project_id = mongodbatlas_advanced_cluster.example.project_id
name = mongodbatlas_advanced_cluster.example.name
depends_on = [mongodbatlas_privatelink_endpoint_service.example_endpoint]
use_replication_spec_per_shard = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to use the new format 👍


# Generated by atlas-cli-plugin-terraform.
# Please confirm that all references to this resource are updated.
}

data "mongodbatlas_advanced_clusters" "plural" {
# data source content is kept - plural
project_id = mongodbatlas_advanced_cluster.example.project_id
use_replication_spec_per_shard = true

# Generated by atlas-cli-plugin-terraform.
# Please confirm that all references to this resource are updated.
}

data "mongodbatlas_advanced_cluster" "adv_singular" {
# adv_cluster is not changed - adv_singular
project_id = mongodbatlas_advanced_cluster.example.project_id
name = mongodbatlas_advanced_cluster.example.name
}

data "mongodbatlas_advanced_cluster" "adv_plural" {
# adv_cluster is not changed - adv_plural
project_id = mongodbatlas_advanced_cluster.example.project_id
}

resource "random_resource" "random1" {
# other resources are left unchanged - random1
hi1 = "there1"
}

data "random_datasource" "random2" {
# other resources are left unchanged - random2
hi2 = "there2"
}

# comments out of resources are kept

unknown_block "hello" {
# unkown block types are kept
}

unknown_block {
# plugin doesn't panic with unlabeled blocks - unknown_block
}

resource {
# plugin doesn't panic with unlabeled blocks - resource
}

data {
# plugin doesn't panic with unlabeled blocks - data
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ resource "resource1" "res1" {

resource "mongodbatlas_cluster" "free_cluster" { # comment in the resource
# comment in own line in the beginning
count = local.use_free_cluster ? 1 : 0
project_id = var.project_id # inline comment kept
name = var.cluster_name
count = local.use_free_cluster ? 1 : 0
project_id = var.project_id # inline comment kept
name = var.cluster_name
# comment in own line in the middle is deleted
provider_name = "TENANT" # inline comment for attribute moved is not kept
backing_provider_name = "AWS"
provider_region_name = var.region
provider_instance_size_name = "M0"
# comment in own line at the end happens before replication_specs
}

data "mongodbatlas_cluster" "cluster2" {
name = "name4"
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,3 @@ resource "mongodbatlas_advanced_cluster" "free_cluster" { # comment in the resou
# Generated by atlas-cli-plugin-terraform.
# Please confirm that all references to this resource are updated.
}

data "mongodbatlas_cluster" "cluster2" {
name = "name4"
}