| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- package tools
- import (
- "context"
- "encoding/json"
- "fmt"
- "io"
- "os/exec"
- "github.com/hashicorp/go-version"
- "github.com/hashicorp/hc-install/product"
- "github.com/hashicorp/hc-install/releases"
- "github.com/hashicorp/terraform-exec/tfexec"
- tfjson "github.com/hashicorp/terraform-json"
- )
- func Terraform(workingDir string) *terraform {
- return &terraform{
- workingDir: workingDir,
- version: "1.14.5",
- logger: tfLogParser{},
- vars: []string{},
- }
- }
- type (
- terraform struct {
- tf *tfexec.Terraform
- state *tfjson.State
- workingDir string
- version string
- logger io.Writer
- vars []string
- }
- tfLogParser struct{}
- )
- func (_ tfLogParser) Write(p []byte) (n int, err error) {
- var logEntry tfjson.LogMessage
- err = json.Unmarshal(p, &logEntry)
- if err != nil {
- return 0, err
- }
- msg := []byte(fmt.Sprintf("[%s] %s\n", logEntry.Level(), logEntry.Message()))
- log.Write(msg)
- return len(msg), nil
- }
- func (t *terraform) VarsFile(path string) *terraform {
- t.vars = append(t.vars, path)
- return t
- }
- func (t *terraform) Version(version string) *terraform {
- t.version = version
- return t
- }
- func (t *terraform) Init() error {
- var err error
- var execPath = ""
- var install = true
- execPath, err = exec.LookPath("terraform")
- if err == nil {
- t.tf, err = tfexec.NewTerraform(t.workingDir, execPath)
- if err == nil {
- v, _, err := t.tf.Version(context.Background(), true)
- if err == nil {
- if v.String() == t.version {
- install = false
- }
- }
- }
- }
- if install {
- installer := &releases.ExactVersion{
- Product: product.Terraform,
- Version: version.Must(version.NewVersion(t.version)),
- }
- execPath, err = installer.Install(context.Background())
- if err != nil {
- return err
- }
- }
- t.tf, err = tfexec.NewTerraform(t.workingDir, execPath)
- if err != nil {
- return err
- }
- err = t.tf.InitJSON(context.Background(),
- t.logger,
- tfexec.Upgrade(true),
- )
- if err != nil {
- return err
- }
- t.state, err = t.tf.Show(context.Background())
- if err != nil {
- return err
- }
- return nil
- }
- func (t *terraform) Plan() (*tfjson.Plan, error) {
- if t.tf == nil {
- err := t.Init()
- if err != nil {
- return nil, err
- }
- }
- opts := []tfexec.PlanOption{
- tfexec.Out("terraform.plan"),
- }
- for _, f := range t.vars {
- tfexec.VarFile(f)
- }
- _, err := t.tf.PlanJSON(context.Background(),
- t.logger,
- opts...,
- )
- if err != nil {
- return nil, err
- }
- plan, err := t.tf.ShowPlanFile(context.Background(), t.workingDir+"/terraform.plan")
- if err != nil {
- return nil, err
- }
- return plan, nil
- }
- func (t *terraform) Apply() error {
- if t.tf == nil {
- err := t.Init()
- if err != nil {
- return err
- }
- }
- err := t.tf.ApplyJSON(context.Background(), t.logger)
- if err != nil {
- return err
- }
- t.state, err = t.tf.Show(context.Background())
- if err != nil {
- return err
- }
- return nil
- }
- func (t *terraform) Show() error {
- if t.tf == nil {
- err := t.Init()
- if err != nil {
- return err
- }
- }
- var err error
- t.state, err = t.tf.Show(context.Background())
- if err != nil {
- return err
- }
- return nil
- }
- func (t *terraform) Outputs() map[string]any {
- outputs := map[string]any{}
- if t.state != nil {
- if t.state.Values != nil {
- if t.state.Values.Outputs != nil {
- for k, v := range t.state.Values.Outputs {
- outputs[k] = v.Value
- }
- }
- }
- }
- return outputs
- }
- func (t *terraform) State() *tfjson.StateModule {
- if t.state != nil {
- if t.state.Values != nil {
- return t.state.Values.RootModule
- }
- }
- return nil
- }
- func (t *terraform) Destroy() error {
- if t.tf == nil {
- err := t.Init()
- if err != nil {
- return err
- }
- }
- err := t.tf.DestroyJSON(context.Background(), t.logger)
- if err != nil {
- return err
- }
- t.state, err = t.tf.Show(context.Background())
- if err != nil {
- return err
- }
- return nil
- }
|