-
Notifications
You must be signed in to change notification settings - Fork 7
/
terraformer_cli.go
168 lines (138 loc) · 5.56 KB
/
terraformer_cli.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package terraformercli
import (
"bytes"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
log "github.com/sirupsen/logrus"
terraformValueObjects "github.com/dragondrop-cloud/cloud-concierge/main/internal/implementations/terraform_value_objects"
)
// TerraformImportMigrationGeneratorParams is the struct that wraps the params to run terraform import statement
type TerraformImportMigrationGeneratorParams struct {
Provider string
Resources []string
AdditionalArgs []string
Regions []string
IsCompact bool
}
// TerraformerCLI interface is an abstraction on the methods needed within the
// terraformer package.
type TerraformerCLI interface {
// Import runs the `terraformer import` command to import all resources for the specified provider, division,
// and specified credentials.
Import(params TerraformImportMigrationGeneratorParams) error
// UpdateState runs the `terraform state replace-provider` command to upgrade the state file generated
// to version 4.
UpdateState(provider string) error
}
// Config is the struct that contains parameters considered to import the resources
type Config struct {
// ResourcesWhiteList represents the list of resource names that will be exclusively considered for inclusion in the import statement.
ResourcesWhiteList terraformValueObjects.ResourceNameList
// ResourcesBlackList represents the list of resource names that will be excluded from consideration for inclusion in the import statement.
ResourcesBlackList terraformValueObjects.ResourceNameList
}
// terraformerCLI implements the TerraformerCLI interface.
type terraformerCLI struct {
// config is the struct that contains parameters considered to import the resources such the black and white resources list
config Config
}
// newTerraformerCLI creates a new instance of the terraformerCLI struct.
func newTerraformerCLI(config Config) TerraformerCLI {
return &terraformerCLI{config: config}
}
// Import runs the `terraformer import` command.
func (tfrCLI *terraformerCLI) Import(params TerraformImportMigrationGeneratorParams) error {
log.Debugf("Running terraformer import with params: %+v", params)
importProvider := getActualImportProvider(params.Provider)
mainArgs := []string{
"import", importProvider,
fmt.Sprintf("--compact=%s", strconv.FormatBool(params.IsCompact)),
"--path-output=./",
"--path-pattern={output}",
}
if len(params.Regions) > 0 {
regions := strings.Join(params.Regions, ",")
mainArgs = append(mainArgs, fmt.Sprintf("--regions=%s", regions))
}
if len(tfrCLI.config.ResourcesBlackList) > 0 {
resourceGroups := tfrCLI.getGroupListByResourceNames(tfrCLI.config.ResourcesBlackList)
if len(resourceGroups) > 0 {
excludes := strings.Join(resourceGroups, ",")
mainArgs = append(mainArgs, fmt.Sprintf("--excludes=%s", excludes))
mainArgs = append(mainArgs, "--resources=*")
}
} else if len(tfrCLI.config.ResourcesWhiteList) > 0 {
resourceGroups := tfrCLI.getGroupListByResourceNames(tfrCLI.config.ResourcesWhiteList)
if len(resourceGroups) > 0 {
resources := strings.Join(tfrCLI.getGroupListByResourceNames(tfrCLI.config.ResourcesWhiteList), ",")
mainArgs = append(mainArgs, fmt.Sprintf("--resources=%s", resources))
}
} else {
mainArgs = append(mainArgs, "--resources=*")
}
args := append(mainArgs, params.AdditionalArgs...)
log.Infof("Terraformer ARGS: %s", args)
err := executeCommand("terraformer", args...)
if err != nil {
return fmt.Errorf("[Import] Error in running 'terraformer import': %v", err)
}
return nil
}
func getActualImportProvider(provider string) string {
if provider == "azurerm" {
return "azure"
}
return provider
}
func (tfrCLI *terraformerCLI) UpdateState(provider string) error {
log.Debugf("Running terraform state replace-provider with provider: %s", provider)
// Remove the provider.tf file that was generated by terraformer.
// Duplicate specified provider in the provider.tf file otherwise causes an error when running
// the terraform state replace-provider command.
err := os.Remove("./provider.tf")
if err != nil {
return fmt.Errorf("[os.Remove]Error in removing 'provider.tf' file: %v", err)
}
// Specify the location of the state file, as well as the from and to provider plug in values.
stateFlag := "-state=./terraform.tfstate"
fromProvider := fmt.Sprintf("registry.terraform.io/-/%s", provider)
toProvider := fmt.Sprintf("hashicorp/%s", provider)
args := []string{"state", "replace-provider", "-auto-approve", stateFlag, fromProvider, toProvider}
err = executeCommand("terraform", args...)
if err != nil {
return fmt.Errorf("[UpdateState] Error in running 'terraform state replace-provider': %v", err)
}
return nil
}
func (tfrCLI *terraformerCLI) getGroupListByResourceNames(list terraformValueObjects.ResourceNameList) []string {
resourceGroups := make([]string, 0)
for _, resourceName := range list {
resourceGroup := googleResourceGroups[resourceName]
if resourceGroup == "" {
resourceGroup = awsResourceGroups[resourceName]
}
if resourceGroup == "" {
resourceGroup = azureResourceGroups[resourceName]
}
resourceGroups = append(resourceGroups, resourceGroup)
}
return resourceGroups
}
// executeCommand wraps os.exec.Command with capturing of std output and errors.
func executeCommand(command string, args ...string) error {
cmd := exec.Command(command, args...)
// Setting up logging objects
var out bytes.Buffer
cmd.Stdout = &out
var stderr bytes.Buffer
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return fmt.Errorf("%v\n\n%v", err, stderr.String()+out.String())
}
fmt.Printf("\n%s Output:\n\n%v\n", command, out.String())
return nil
}