197 lines
4.3 KiB
Go
197 lines
4.3 KiB
Go
package tfexec
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
tfjson "github.com/hashicorp/terraform-json"
|
|
)
|
|
|
|
type showConfig struct {
|
|
reattachInfo ReattachInfo
|
|
}
|
|
|
|
var defaultShowOptions = showConfig{}
|
|
|
|
type ShowOption interface {
|
|
configureShow(*showConfig)
|
|
}
|
|
|
|
func (opt *ReattachOption) configureShow(conf *showConfig) {
|
|
conf.reattachInfo = opt.info
|
|
}
|
|
|
|
// Show reads the default state path and outputs the state.
|
|
// To read a state or plan file, ShowState or ShowPlan must be used instead.
|
|
func (tf *Terraform) Show(ctx context.Context, opts ...ShowOption) (*tfjson.State, error) {
|
|
err := tf.compatible(ctx, tf0_12_0, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("terraform show -json was added in 0.12.0: %w", err)
|
|
}
|
|
|
|
c := defaultShowOptions
|
|
|
|
for _, o := range opts {
|
|
o.configureShow(&c)
|
|
}
|
|
|
|
mergeEnv := map[string]string{}
|
|
if c.reattachInfo != nil {
|
|
reattachStr, err := c.reattachInfo.marshalString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mergeEnv[reattachEnvVar] = reattachStr
|
|
}
|
|
|
|
showCmd := tf.showCmd(ctx, true, mergeEnv)
|
|
|
|
var ret tfjson.State
|
|
ret.UseJSONNumber(true)
|
|
err = tf.runTerraformCmdJSON(ctx, showCmd, &ret)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = ret.Validate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ret, nil
|
|
}
|
|
|
|
// ShowStateFile reads a given state file and outputs the state.
|
|
func (tf *Terraform) ShowStateFile(ctx context.Context, statePath string, opts ...ShowOption) (*tfjson.State, error) {
|
|
err := tf.compatible(ctx, tf0_12_0, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("terraform show -json was added in 0.12.0: %w", err)
|
|
}
|
|
|
|
if statePath == "" {
|
|
return nil, fmt.Errorf("statePath cannot be blank: use Show() if not passing statePath")
|
|
}
|
|
|
|
c := defaultShowOptions
|
|
|
|
for _, o := range opts {
|
|
o.configureShow(&c)
|
|
}
|
|
|
|
mergeEnv := map[string]string{}
|
|
if c.reattachInfo != nil {
|
|
reattachStr, err := c.reattachInfo.marshalString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mergeEnv[reattachEnvVar] = reattachStr
|
|
}
|
|
|
|
showCmd := tf.showCmd(ctx, true, mergeEnv, statePath)
|
|
|
|
var ret tfjson.State
|
|
ret.UseJSONNumber(true)
|
|
err = tf.runTerraformCmdJSON(ctx, showCmd, &ret)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = ret.Validate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ret, nil
|
|
}
|
|
|
|
// ShowPlanFile reads a given plan file and outputs the plan.
|
|
func (tf *Terraform) ShowPlanFile(ctx context.Context, planPath string, opts ...ShowOption) (*tfjson.Plan, error) {
|
|
err := tf.compatible(ctx, tf0_12_0, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("terraform show -json was added in 0.12.0: %w", err)
|
|
}
|
|
|
|
if planPath == "" {
|
|
return nil, fmt.Errorf("planPath cannot be blank: use Show() if not passing planPath")
|
|
}
|
|
|
|
c := defaultShowOptions
|
|
|
|
for _, o := range opts {
|
|
o.configureShow(&c)
|
|
}
|
|
|
|
mergeEnv := map[string]string{}
|
|
if c.reattachInfo != nil {
|
|
reattachStr, err := c.reattachInfo.marshalString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
mergeEnv[reattachEnvVar] = reattachStr
|
|
}
|
|
|
|
showCmd := tf.showCmd(ctx, true, mergeEnv, planPath)
|
|
|
|
var ret tfjson.Plan
|
|
err = tf.runTerraformCmdJSON(ctx, showCmd, &ret)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = ret.Validate()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ret, nil
|
|
|
|
}
|
|
|
|
// ShowPlanFileRaw reads a given plan file and outputs the plan in a
|
|
// human-friendly, opaque format.
|
|
func (tf *Terraform) ShowPlanFileRaw(ctx context.Context, planPath string, opts ...ShowOption) (string, error) {
|
|
if planPath == "" {
|
|
return "", fmt.Errorf("planPath cannot be blank: use Show() if not passing planPath")
|
|
}
|
|
|
|
c := defaultShowOptions
|
|
|
|
for _, o := range opts {
|
|
o.configureShow(&c)
|
|
}
|
|
|
|
mergeEnv := map[string]string{}
|
|
if c.reattachInfo != nil {
|
|
reattachStr, err := c.reattachInfo.marshalString()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
mergeEnv[reattachEnvVar] = reattachStr
|
|
}
|
|
|
|
showCmd := tf.showCmd(ctx, false, mergeEnv, planPath)
|
|
|
|
var outBuf strings.Builder
|
|
showCmd.Stdout = &outBuf
|
|
err := tf.runTerraformCmd(ctx, showCmd)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return outBuf.String(), nil
|
|
|
|
}
|
|
|
|
func (tf *Terraform) showCmd(ctx context.Context, jsonOutput bool, mergeEnv map[string]string, args ...string) *exec.Cmd {
|
|
allArgs := []string{"show"}
|
|
if jsonOutput {
|
|
allArgs = append(allArgs, "-json")
|
|
}
|
|
allArgs = append(allArgs, "-no-color")
|
|
allArgs = append(allArgs, args...)
|
|
|
|
return tf.buildTerraformCmd(ctx, mergeEnv, allArgs...)
|
|
}
|