tf/terraform.go (105 lines of code) (raw):

package tf import ( "context" "fmt" "io" "log" "os" "path" "strings" "github.com/hashicorp/terraform-exec/tfexec" tfjson "github.com/hashicorp/terraform-json" "github.com/magodo/tfadd/tfadd" ) type Terraform struct { exec *tfexec.Terraform LogEnabled bool workingDirectory string } const planfile = "tfplan" func NewTerraform(workingDirectory string, logEnabled bool) (*Terraform, error) { execPath, err := FindTerraform(context.Background()) if err != nil { return nil, err } tf, err := tfexec.NewTerraform(workingDirectory, execPath) if err != nil { return nil, err } t := &Terraform{ exec: tf, workingDirectory: workingDirectory, LogEnabled: logEnabled, } t.SetLogEnabled(true) return t, nil } func (t *Terraform) SetLogEnabled(enabled bool) { if enabled && t.LogEnabled { t.exec.SetStdout(os.Stdout) t.exec.SetStderr(os.Stderr) t.exec.SetLogger(log.New(os.Stdout, "", 0)) } else { t.exec.SetStdout(io.Discard) t.exec.SetStderr(io.Discard) t.exec.SetLogger(log.New(io.Discard, "", 0)) } } func (t *Terraform) Init() error { if _, err := os.Stat(path.Join(t.GetWorkingDirectory(), ".terraform")); os.IsNotExist(err) { err := t.exec.Init(context.Background(), tfexec.Upgrade(false)) // ignore the error if can't find azapi if err != nil && strings.Contains(err.Error(), "Azure/azapi: provider registry registry.terraform.io does not have") { return nil } return err } return nil } func (t *Terraform) Show() (*tfjson.State, error) { return t.exec.Show(context.TODO()) } func (t *Terraform) Plan(varFile *string) (*tfjson.Plan, error) { planOptions := []tfexec.PlanOption{tfexec.Out(planfile)} if varFile != nil && *varFile != "" { planOptions = append(planOptions, tfexec.VarFile(*varFile)) } _, err := t.exec.Plan(context.TODO(), planOptions...) if err != nil { return nil, err } t.SetLogEnabled(false) p, err := t.exec.ShowPlanFile(context.TODO(), planfile) t.SetLogEnabled(true) return p, err } func (t *Terraform) ImportAdd(address string, id string) (string, error) { _ = t.Init() err := t.exec.Import(context.TODO(), address, id) if err != nil { return "", fmt.Errorf("importing resource %s: %w", address, err) } outputs, err := tfadd.StateForTargets(context.TODO(), t.exec, []string{address}, tfadd.Full(true)) if err != nil { return "", fmt.Errorf("converting terraform state to config for resource %s: %w", address, err) } if len(outputs) == 0 { return "", fmt.Errorf("resource %s not found in state", address) } return string(outputs[0]), nil } func (t *Terraform) Import(address string, id string) error { _ = t.Init() return t.exec.Import(context.TODO(), address, id) } func (t *Terraform) Apply() error { return t.exec.Apply(context.TODO()) } func (t *Terraform) Destroy() error { return t.exec.Destroy(context.TODO()) } func (t *Terraform) GetExec() *tfexec.Terraform { return t.exec } func (t *Terraform) GetWorkingDirectory() string { return t.workingDirectory }