Skip to content

Commit 0db194f

Browse files
authored
Branch 240408 improve error handling (#150)
* improve error handling * support version constraint in terraform block * fix gosec
1 parent 3a22161 commit 0db194f

File tree

6 files changed

+83
-31
lines changed

6 files changed

+83
-31
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## v2.4.0 (unreleased)
2+
3+
ENHANCEMENTS:
4+
- Support specifying the provider version used in the migration in the `terraform` block.
5+
16
## v2.3.0
27
Target azurerm version: v4.20.0
38

cmd/migrate_command.go

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"path/filepath"
1010
"strings"
1111

12+
"github.com/Azure/aztfmigrate/helper"
1213
"github.com/Azure/aztfmigrate/tf"
1314
"github.com/Azure/aztfmigrate/types"
1415
"github.com/hashicorp/hcl/v2/hclwrite"
@@ -125,7 +126,7 @@ func (c *MigrateCommand) MigrateResources(terraform *tf.Terraform, resources []t
125126
}
126127

127128
log.Printf("[INFO] generating import config...")
128-
config := importConfig(resources)
129+
config := ImportConfig(resources, helper.FindHclBlock(workingDirectory, "terraform", nil))
129130
if err = os.WriteFile(filepath.Join(tempDir, filenameImport), []byte(config), 0600); err != nil {
130131
log.Fatal(err)
131132
}
@@ -190,26 +191,20 @@ func (c *MigrateCommand) MigrateResources(terraform *tf.Terraform, resources []t
190191
}
191192
}
192193

193-
func importConfig(resources []types.AzureResource) string {
194-
const providerConfig = `
195-
terraform {
194+
func ImportConfig(resources []types.AzureResource, terraformBlock *hclwrite.Block) string {
195+
config := `terraform {
196196
required_providers {
197197
azapi = {
198198
source = "Azure/azapi"
199199
}
200200
}
201-
}
202-
203-
provider "azurerm" {
204-
features {}
205-
subscription_id = "%s"
206-
}
207-
208-
provider "azapi" {
209-
}
210-
`
201+
}`
202+
if terraformBlock != nil {
203+
newFile := hclwrite.NewEmptyFile()
204+
newFile.Body().AppendBlock(terraformBlock)
205+
config = string(hclwrite.Format(newFile.Bytes()))
206+
}
211207

212-
config := ""
213208
for _, r := range resources {
214209
config += r.EmptyImportConfig()
215210
}
@@ -232,7 +227,16 @@ provider "azapi" {
232227
break
233228
}
234229
}
235-
config = fmt.Sprintf(providerConfig, subscriptionId) + config
236230

237-
return config
231+
const providerConfig = `
232+
provider "azurerm" {
233+
features {}
234+
subscription_id = "%s"
235+
}
236+
237+
provider "azapi" {
238+
}
239+
`
240+
241+
return fmt.Sprintf(providerConfig, subscriptionId) + config
238242
}

helper/utils.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io/fs"
77
"os"
8+
"path"
89
"strings"
910

1011
"github.com/hashicorp/hcl/v2"
@@ -79,6 +80,48 @@ func ListHclFiles(workingDirectory string) []fs.DirEntry {
7980
return res
8081
}
8182

83+
func ListHclBlocks(workingDirectory string) []*hclwrite.Block {
84+
res := make([]*hclwrite.Block, 0)
85+
files := ListHclFiles(workingDirectory)
86+
for _, file := range files {
87+
filePath := path.Join(workingDirectory, file.Name())
88+
// #nosec G304
89+
f, err := os.ReadFile(filePath)
90+
if err != nil {
91+
continue
92+
}
93+
hclFile, diags := hclwrite.ParseConfig(f, file.Name(), hcl.InitialPos)
94+
if diags.HasErrors() {
95+
continue
96+
}
97+
res = append(res, hclFile.Body().Blocks()...)
98+
}
99+
return res
100+
}
101+
102+
func FindHclBlock(workingDirectory string, blockType string, labels []string) *hclwrite.Block {
103+
blocks := ListHclBlocks(workingDirectory)
104+
for _, block := range blocks {
105+
if block.Type() != blockType {
106+
continue
107+
}
108+
if len(block.Labels()) != len(labels) {
109+
continue
110+
}
111+
isLabelsEqual := true
112+
for i, label := range labels {
113+
if block.Labels()[i] != label {
114+
isLabelsEqual = false
115+
break
116+
}
117+
}
118+
if isLabelsEqual {
119+
return block
120+
}
121+
}
122+
return nil
123+
}
124+
82125
// GetTokensForExpression convert a literal value to hclwrite.Tokens
83126
func GetTokensForExpression(expression string) hclwrite.Tokens {
84127
syntaxTokens, diags := hclsyntax.LexConfig([]byte(expression), "main.tf", hcl.InitialPos)

tf/terraform.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (t *Terraform) ImportAdd(address string, id string) (string, error) {
8888
_ = t.Init()
8989
err := t.exec.Import(context.TODO(), address, id)
9090
if err != nil {
91-
log.Fatal(err)
91+
return "", fmt.Errorf("importing resource %s: %w", address, err)
9292
}
9393
outputs, err := tfadd.StateForTargets(context.TODO(), t.exec, []string{address}, tfadd.Full(true))
9494
if err != nil {

types/azapi_resource.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,18 +248,18 @@ type Instance struct {
248248
func importAndGenerateConfig(terraform *tf.Terraform, address string, id string, resourceType string, skipTune bool) (*hclwrite.Block, error) {
249249
tpl, err := terraform.ImportAdd(address, id)
250250
if err != nil {
251-
return nil, fmt.Errorf("[ERROR] error importing address: %s, id: %s: %+v", address, id, err)
251+
return nil, err
252252
}
253253
f, diag := hclwrite.ParseConfig([]byte(tpl), "", hcl.InitialPos)
254254
if (diag != nil && diag.HasErrors()) || f == nil {
255-
return nil, fmt.Errorf("[ERROR] parsing the HCL generated by \"terraform add\" of %s: %s", address, diag.Error())
255+
return nil, fmt.Errorf("parsing the HCL generated by \"terraform add\" of %s: %s", address, diag.Error())
256256
}
257257

258258
if !skipTune {
259259
rb := f.Body().Blocks()[0].Body()
260260
sch := schema.ProviderSchemaInfo.ResourceSchemas[resourceType]
261261
if err := azurerm.TuneHCLSchemaForResource(rb, sch); err != nil {
262-
return nil, fmt.Errorf("[ERROR] tuning hcl config base on schema: %+v", err)
262+
return nil, fmt.Errorf("tuning hcl config base on schema: %+v", err)
263263
}
264264
}
265265

types/azurerm_resource.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,17 @@ func (r *AzurermResource) GenerateNewConfig(terraform *tf.Terraform) error {
6161
if !r.IsMultipleResources() {
6262
instance := r.Instances[0]
6363
log.Printf("[INFO] importing %s to %s and generating config...", instance.ResourceId, r.NewAddress(nil))
64-
if block, err := importAndGenerateConfig(terraform, r.NewAddress(nil), instance.ResourceId, "", true); err == nil {
65-
r.Block = block
66-
valuePropMap := GetValuePropMap(r.Block, r.NewAddress(nil))
67-
for i, output := range r.Instances[0].Outputs {
68-
r.Instances[0].Outputs[i].NewName = valuePropMap[output.GetStringValue()]
69-
}
70-
r.Migrated = true
71-
log.Printf("[INFO] resource %s has migrated to %s", r.OldAddress(nil), r.NewAddress(nil))
72-
} else {
73-
log.Printf("[ERROR] %+v", err)
64+
block, err := importAndGenerateConfig(terraform, r.NewAddress(nil), instance.ResourceId, "", true)
65+
if err != nil {
66+
return err
67+
}
68+
r.Block = block
69+
valuePropMap := GetValuePropMap(r.Block, r.NewAddress(nil))
70+
for i, output := range r.Instances[0].Outputs {
71+
r.Instances[0].Outputs[i].NewName = valuePropMap[output.GetStringValue()]
7472
}
73+
r.Migrated = true
74+
log.Printf("[INFO] resource %s has migrated to %s", r.OldAddress(nil), r.NewAddress(nil))
7575
r.Block = InjectReference(r.Block, r.References)
7676
} else {
7777
// import and build combined block

0 commit comments

Comments
 (0)