| package tfexec | 
 |  | 
 | import ( | 
 | 	"context" | 
 | 	"fmt" | 
 | 	"io" | 
 | 	"io/ioutil" | 
 | 	"log" | 
 | 	"os" | 
 | 	"sync" | 
 |  | 
 | 	"github.com/hashicorp/go-version" | 
 | ) | 
 |  | 
 | type printfer interface { | 
 | 	Printf(format string, v ...interface{}) | 
 | } | 
 |  | 
 | // Terraform represents the Terraform CLI executable and working directory. | 
 | // | 
 | // Typically this is constructed against the root module of a Terraform configuration | 
 | // but you can override paths used in some commands depending on the available | 
 | // options. | 
 | // | 
 | // All functions that execute CLI commands take a context.Context. It should be noted that | 
 | // exec.Cmd.Run will not return context.DeadlineExceeded or context.Canceled by default, we | 
 | // have augmented our wrapped errors to respond true to errors.Is for context.DeadlineExceeded | 
 | // and context.Canceled if those are present on the context when the error is parsed. See | 
 | // https://github.com/golang/go/issues/21880 for more about the Go limitations. | 
 | // | 
 | // By default, the instance inherits the environment from the calling code (using os.Environ) | 
 | // but it ignores certain environment variables that are managed within the code and prohibits | 
 | // setting them through SetEnv: | 
 | // | 
 | //  - TF_APPEND_USER_AGENT | 
 | //  - TF_IN_AUTOMATION | 
 | //  - TF_INPUT | 
 | //  - TF_LOG | 
 | //  - TF_LOG_PATH | 
 | //  - TF_REATTACH_PROVIDERS | 
 | //  - TF_DISABLE_PLUGIN_TLS | 
 | //  - TF_SKIP_PROVIDER_VERIFY | 
 | type Terraform struct { | 
 | 	execPath           string | 
 | 	workingDir         string | 
 | 	appendUserAgent    string | 
 | 	disablePluginTLS   bool | 
 | 	skipProviderVerify bool | 
 | 	env                map[string]string | 
 |  | 
 | 	stdout io.Writer | 
 | 	stderr io.Writer | 
 | 	logger printfer | 
 |  | 
 | 	// TF_LOG environment variable, defaults to TRACE if logPath is set. | 
 | 	log string | 
 |  | 
 | 	// TF_LOG_CORE environment variable | 
 | 	logCore string | 
 |  | 
 | 	// TF_LOG_PATH environment variable | 
 | 	logPath string | 
 |  | 
 | 	// TF_LOG_PROVIDER environment variable | 
 | 	logProvider string | 
 |  | 
 | 	versionLock  sync.Mutex | 
 | 	execVersion  *version.Version | 
 | 	provVersions map[string]*version.Version | 
 | } | 
 |  | 
 | // NewTerraform returns a Terraform struct with default values for all fields. | 
 | // If a blank execPath is supplied, NewTerraform will error. | 
 | // Use hc-install or output from os.LookPath to get a desirable execPath. | 
 | func NewTerraform(workingDir string, execPath string) (*Terraform, error) { | 
 | 	if workingDir == "" { | 
 | 		return nil, fmt.Errorf("Terraform cannot be initialised with empty workdir") | 
 | 	} | 
 |  | 
 | 	if _, err := os.Stat(workingDir); err != nil { | 
 | 		return nil, fmt.Errorf("error initialising Terraform with workdir %s: %s", workingDir, err) | 
 | 	} | 
 |  | 
 | 	if execPath == "" { | 
 | 		err := fmt.Errorf("NewTerraform: please supply the path to a Terraform executable using execPath, e.g. using the github.com/hashicorp/hc-install module.") | 
 | 		return nil, &ErrNoSuitableBinary{ | 
 | 			err: err, | 
 | 		} | 
 | 	} | 
 | 	tf := Terraform{ | 
 | 		execPath:   execPath, | 
 | 		workingDir: workingDir, | 
 | 		env:        nil, // explicit nil means copy os.Environ | 
 | 		logger:     log.New(ioutil.Discard, "", 0), | 
 | 	} | 
 |  | 
 | 	return &tf, nil | 
 | } | 
 |  | 
 | // SetEnv allows you to override environment variables, this should not be used for any well known | 
 | // Terraform environment variables that are already covered in options. Pass nil to copy the values | 
 | // from os.Environ. Attempting to set environment variables that should be managed manually will | 
 | // result in ErrManualEnvVar being returned. | 
 | func (tf *Terraform) SetEnv(env map[string]string) error { | 
 | 	prohibited := ProhibitedEnv(env) | 
 | 	if len(prohibited) > 0 { | 
 | 		// just error on the first instance | 
 | 		return &ErrManualEnvVar{prohibited[0]} | 
 | 	} | 
 |  | 
 | 	tf.env = env | 
 | 	return nil | 
 | } | 
 |  | 
 | // SetLogger specifies a logger for tfexec to use. | 
 | func (tf *Terraform) SetLogger(logger printfer) { | 
 | 	tf.logger = logger | 
 | } | 
 |  | 
 | // SetStdout specifies a writer to stream stdout to for every command. | 
 | // | 
 | // This should be used for information or logging purposes only, not control | 
 | // flow. Any parsing necessary should be added as functionality to this package. | 
 | func (tf *Terraform) SetStdout(w io.Writer) { | 
 | 	tf.stdout = w | 
 | } | 
 |  | 
 | // SetStderr specifies a writer to stream stderr to for every command. | 
 | // | 
 | // This should be used for information or logging purposes only, not control | 
 | // flow. Any parsing necessary should be added as functionality to this package. | 
 | func (tf *Terraform) SetStderr(w io.Writer) { | 
 | 	tf.stderr = w | 
 | } | 
 |  | 
 | // SetLog sets the TF_LOG environment variable for Terraform CLI execution. | 
 | // This must be combined with a call to SetLogPath to take effect. | 
 | // | 
 | // This is only compatible with Terraform CLI 0.15.0 or later as setting the | 
 | // log level was unreliable in earlier versions. It will default to TRACE when | 
 | // SetLogPath is called on versions 0.14.11 and earlier, or if SetLogCore and | 
 | // SetLogProvider have not been called before SetLogPath on versions 0.15.0 and | 
 | // later. | 
 | func (tf *Terraform) SetLog(log string) error { | 
 | 	err := tf.compatible(context.Background(), tf0_15_0, nil) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 | 	tf.log = log | 
 | 	return nil | 
 | } | 
 |  | 
 | // SetLogCore sets the TF_LOG_CORE environment variable for Terraform CLI | 
 | // execution. This must be combined with a call to SetLogPath to take effect. | 
 | // | 
 | // This is only compatible with Terraform CLI 0.15.0 or later. | 
 | func (tf *Terraform) SetLogCore(logCore string) error { | 
 | 	err := tf.compatible(context.Background(), tf0_15_0, nil) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 | 	tf.logCore = logCore | 
 | 	return nil | 
 | } | 
 |  | 
 | // SetLogPath sets the TF_LOG_PATH environment variable for Terraform CLI | 
 | // execution. | 
 | func (tf *Terraform) SetLogPath(path string) error { | 
 | 	tf.logPath = path | 
 | 	// Prevent setting the log path without enabling logging | 
 | 	if tf.log == "" && tf.logCore == "" && tf.logProvider == "" { | 
 | 		tf.log = "TRACE" | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | // SetLogProvider sets the TF_LOG_PROVIDER environment variable for Terraform | 
 | // CLI execution. This must be combined with a call to SetLogPath to take | 
 | // effect. | 
 | // | 
 | // This is only compatible with Terraform CLI 0.15.0 or later. | 
 | func (tf *Terraform) SetLogProvider(logProvider string) error { | 
 | 	err := tf.compatible(context.Background(), tf0_15_0, nil) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 | 	tf.logProvider = logProvider | 
 | 	return nil | 
 | } | 
 |  | 
 | // SetAppendUserAgent sets the TF_APPEND_USER_AGENT environment variable for | 
 | // Terraform CLI execution. | 
 | func (tf *Terraform) SetAppendUserAgent(ua string) error { | 
 | 	tf.appendUserAgent = ua | 
 | 	return nil | 
 | } | 
 |  | 
 | // SetDisablePluginTLS sets the TF_DISABLE_PLUGIN_TLS environment variable for | 
 | // Terraform CLI execution. | 
 | func (tf *Terraform) SetDisablePluginTLS(disabled bool) error { | 
 | 	tf.disablePluginTLS = disabled | 
 | 	return nil | 
 | } | 
 |  | 
 | // SetSkipProviderVerify sets the TF_SKIP_PROVIDER_VERIFY environment variable | 
 | // for Terraform CLI execution. This is no longer used in 0.13.0 and greater. | 
 | func (tf *Terraform) SetSkipProviderVerify(skip bool) error { | 
 | 	err := tf.compatible(context.Background(), nil, tf0_13_0) | 
 | 	if err != nil { | 
 | 		return err | 
 | 	} | 
 | 	tf.skipProviderVerify = skip | 
 | 	return nil | 
 | } | 
 |  | 
 | // WorkingDir returns the working directory for Terraform. | 
 | func (tf *Terraform) WorkingDir() string { | 
 | 	return tf.workingDir | 
 | } | 
 |  | 
 | // ExecPath returns the path to the Terraform executable. | 
 | func (tf *Terraform) ExecPath() string { | 
 | 	return tf.execPath | 
 | } |