main: factor out CLI config loading into its own function
Previously we handled all of the config sources directly within the main function. We're going to make CLI config loading more complex shortly, so having this encapsulated in its own function will avoid creating even more clutter inside the main function. Along the way here we also switch from using native Go "error" to using tfdiags.Diagnostics, so that we can potentially issue warnings here too in future, and so that we can return multiple errors.
This commit is contained in:
parent
a2c59c6ecd
commit
11ba1d2a4c
47
config.go
47
config.go
|
@ -63,26 +63,55 @@ func ConfigDir() (string, error) {
|
||||||
return configDir()
|
return configDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadConfig loads the CLI configuration from ".terraformrc" files.
|
// LoadConfig reads the CLI configuration from the various filesystem locations
|
||||||
func LoadConfig(path string) (*Config, error) {
|
// and from the environment, returning a merged configuration along with any
|
||||||
|
// diagnostics (errors and warnings) encountered along the way.
|
||||||
|
func LoadConfig() (*Config, tfdiags.Diagnostics) {
|
||||||
|
var diags tfdiags.Diagnostics
|
||||||
|
configVal := BuiltinConfig // copy
|
||||||
|
config := &configVal
|
||||||
|
|
||||||
|
if mainFilename, err := cliConfigFile(); err == nil {
|
||||||
|
if _, err := os.Stat(mainFilename); err == nil {
|
||||||
|
mainConfig, mainDiags := loadConfigFile(mainFilename)
|
||||||
|
diags = diags.Append(mainDiags)
|
||||||
|
config = config.Merge(mainConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if envConfig := EnvConfig(); envConfig != nil {
|
||||||
|
// envConfig takes precedence
|
||||||
|
config = envConfig.Merge(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
diags = diags.Append(config.Validate())
|
||||||
|
|
||||||
|
return config, diags
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadConfigFile loads the CLI configuration from ".terraformrc" files.
|
||||||
|
func loadConfigFile(path string) (*Config, tfdiags.Diagnostics) {
|
||||||
|
var diags tfdiags.Diagnostics
|
||||||
|
result := &Config{}
|
||||||
|
|
||||||
// Read the HCL file and prepare for parsing
|
// Read the HCL file and prepare for parsing
|
||||||
d, err := ioutil.ReadFile(path)
|
d, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf("Error reading %s: %s", path, err))
|
||||||
"Error reading %s: %s", path, err)
|
return result, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse it
|
// Parse it
|
||||||
obj, err := hcl.Parse(string(d))
|
obj, err := hcl.Parse(string(d))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
diags = diags.Append(fmt.Errorf("Error parsing %s: %s", path, err))
|
||||||
"Error parsing %s: %s", path, err)
|
return result, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build up the result
|
// Build up the result
|
||||||
var result Config
|
|
||||||
if err := hcl.DecodeObject(&result, obj); err != nil {
|
if err := hcl.DecodeObject(&result, obj); err != nil {
|
||||||
return nil, err
|
diags = diags.Append(fmt.Errorf("Error parsing %s: %s", path, err))
|
||||||
|
return result, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace all env vars
|
// Replace all env vars
|
||||||
|
@ -97,7 +126,7 @@ func LoadConfig(path string) (*Config, error) {
|
||||||
result.PluginCacheDir = os.ExpandEnv(result.PluginCacheDir)
|
result.PluginCacheDir = os.ExpandEnv(result.PluginCacheDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &result, nil
|
return result, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnvConfig returns a Config populated from environment variables.
|
// EnvConfig returns a Config populated from environment variables.
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
const fixtureDir = "./test-fixtures"
|
const fixtureDir = "./test-fixtures"
|
||||||
|
|
||||||
func TestLoadConfig(t *testing.T) {
|
func TestLoadConfig(t *testing.T) {
|
||||||
c, err := LoadConfig(filepath.Join(fixtureDir, "config"))
|
c, err := loadConfigFile(filepath.Join(fixtureDir, "config"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ func TestLoadConfig_env(t *testing.T) {
|
||||||
defer os.Unsetenv("TFTEST")
|
defer os.Unsetenv("TFTEST")
|
||||||
os.Setenv("TFTEST", "hello")
|
os.Setenv("TFTEST", "hello")
|
||||||
|
|
||||||
c, err := LoadConfig(filepath.Join(fixtureDir, "config-env"))
|
c, err := loadConfigFile(filepath.Join(fixtureDir, "config-env"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ func TestLoadConfig_env(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadConfig_credentials(t *testing.T) {
|
func TestLoadConfig_credentials(t *testing.T) {
|
||||||
got, err := LoadConfig(filepath.Join(fixtureDir, "credentials"))
|
got, err := loadConfigFile(filepath.Join(fixtureDir, "credentials"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
67
main.go
67
main.go
|
@ -17,7 +17,6 @@ import (
|
||||||
"github.com/hashicorp/terraform/command/format"
|
"github.com/hashicorp/terraform/command/format"
|
||||||
"github.com/hashicorp/terraform/helper/logging"
|
"github.com/hashicorp/terraform/helper/logging"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
"github.com/hashicorp/terraform/tfdiags"
|
|
||||||
"github.com/mattn/go-colorable"
|
"github.com/mattn/go-colorable"
|
||||||
"github.com/mattn/go-shellwords"
|
"github.com/mattn/go-shellwords"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
|
@ -111,6 +110,8 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrappedMain() int {
|
func wrappedMain() int {
|
||||||
|
var err error
|
||||||
|
|
||||||
// We always need to close the DebugInfo before we exit.
|
// We always need to close the DebugInfo before we exit.
|
||||||
defer terraform.CloseDebugInfo()
|
defer terraform.CloseDebugInfo()
|
||||||
|
|
||||||
|
@ -121,60 +122,34 @@ func wrappedMain() int {
|
||||||
log.Printf("[INFO] Go runtime version: %s", runtime.Version())
|
log.Printf("[INFO] Go runtime version: %s", runtime.Version())
|
||||||
log.Printf("[INFO] CLI args: %#v", os.Args)
|
log.Printf("[INFO] CLI args: %#v", os.Args)
|
||||||
|
|
||||||
// Load the configuration
|
config, diags := LoadConfig()
|
||||||
config := BuiltinConfig
|
if len(diags) > 0 {
|
||||||
|
// Since we haven't instantiated a command.Meta yet, we need to do
|
||||||
// Load the configuration file if we have one, that can be used to
|
// some things manually here and use some "safe" defaults for things
|
||||||
// define extra providers and provisioners.
|
// that command.Meta could otherwise figure out in smarter ways.
|
||||||
clicfgFile, err := cliConfigFile()
|
Ui.Error("There are some problems with the CLI configuration:")
|
||||||
if err != nil {
|
for _, diag := range diags {
|
||||||
Ui.Error(fmt.Sprintf("Error loading CLI configuration: \n\n%s", err))
|
earlyColor := &colorstring.Colorize{
|
||||||
return 1
|
Colors: colorstring.DefaultColors,
|
||||||
}
|
Disable: true, // Disable color to be conservative until we know better
|
||||||
|
Reset: true,
|
||||||
if clicfgFile != "" {
|
}
|
||||||
usrcfg, err := LoadConfig(clicfgFile)
|
Ui.Error(format.Diagnostic(diag, earlyColor, 78))
|
||||||
if err != nil {
|
|
||||||
Ui.Error(fmt.Sprintf("Error loading CLI configuration: \n\n%s", err))
|
|
||||||
return 1
|
|
||||||
}
|
}
|
||||||
|
if diags.HasErrors() {
|
||||||
config = *config.Merge(usrcfg)
|
Ui.Error("As a result of the above problems, Terraform may not behave as intended.\n\n")
|
||||||
}
|
// We continue to run anyway, since Terraform has reasonable defaults.
|
||||||
|
|
||||||
if envConfig := EnvConfig(); envConfig != nil {
|
|
||||||
// envConfig takes precedence
|
|
||||||
config = *envConfig.Merge(&config)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[DEBUG] CLI Config is %#v", config)
|
|
||||||
|
|
||||||
{
|
|
||||||
var diags tfdiags.Diagnostics
|
|
||||||
diags = diags.Append(config.Validate())
|
|
||||||
if len(diags) > 0 {
|
|
||||||
Ui.Error("There are some problems with the CLI configuration:")
|
|
||||||
for _, diag := range diags {
|
|
||||||
earlyColor := &colorstring.Colorize{
|
|
||||||
Colors: colorstring.DefaultColors,
|
|
||||||
Disable: true, // Disable color to be conservative until we know better
|
|
||||||
Reset: true,
|
|
||||||
}
|
|
||||||
Ui.Error(format.Diagnostic(diag, earlyColor, 78))
|
|
||||||
}
|
|
||||||
if diags.HasErrors() {
|
|
||||||
Ui.Error("As a result of the above problems, Terraform may not behave as intended.\n\n")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
log.Printf("[DEBUG] CLI config is %#v", config)
|
||||||
|
|
||||||
// In tests, Commands may already be set to provide mock commands
|
// In tests, Commands may already be set to provide mock commands
|
||||||
if Commands == nil {
|
if Commands == nil {
|
||||||
initCommands(&config)
|
initCommands(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run checkpoint
|
// Run checkpoint
|
||||||
go runCheckpoint(&config)
|
go runCheckpoint(config)
|
||||||
|
|
||||||
// Make sure we clean up any managed plugins at the end of this
|
// Make sure we clean up any managed plugins at the end of this
|
||||||
defer plugin.CleanupClients()
|
defer plugin.CleanupClients()
|
||||||
|
|
Loading…
Reference in New Issue