| 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...) | |
| } |