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()
|
||||
}
|
||||
|
||||
// LoadConfig loads the CLI configuration from ".terraformrc" files.
|
||||
func LoadConfig(path string) (*Config, error) {
|
||||
// LoadConfig reads the CLI configuration from the various filesystem locations
|
||||
// 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
|
||||
d, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error reading %s: %s", path, err)
|
||||
diags = diags.Append(fmt.Errorf("Error reading %s: %s", path, err))
|
||||
return result, diags
|
||||
}
|
||||
|
||||
// Parse it
|
||||
obj, err := hcl.Parse(string(d))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error parsing %s: %s", path, err)
|
||||
diags = diags.Append(fmt.Errorf("Error parsing %s: %s", path, err))
|
||||
return result, diags
|
||||
}
|
||||
|
||||
// Build up the result
|
||||
var result Config
|
||||
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
|
||||
|
@ -97,7 +126,7 @@ func LoadConfig(path string) (*Config, error) {
|
|||
result.PluginCacheDir = os.ExpandEnv(result.PluginCacheDir)
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
return result, diags
|
||||
}
|
||||
|
||||
// EnvConfig returns a Config populated from environment variables.
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
const fixtureDir = "./test-fixtures"
|
||||
|
||||
func TestLoadConfig(t *testing.T) {
|
||||
c, err := LoadConfig(filepath.Join(fixtureDir, "config"))
|
||||
c, err := loadConfigFile(filepath.Join(fixtureDir, "config"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ func TestLoadConfig_env(t *testing.T) {
|
|||
defer os.Unsetenv("TFTEST")
|
||||
os.Setenv("TFTEST", "hello")
|
||||
|
||||
c, err := LoadConfig(filepath.Join(fixtureDir, "config-env"))
|
||||
c, err := loadConfigFile(filepath.Join(fixtureDir, "config-env"))
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func TestLoadConfig_env(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 {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
45
main.go
45
main.go
|
@ -17,7 +17,6 @@ import (
|
|||
"github.com/hashicorp/terraform/command/format"
|
||||
"github.com/hashicorp/terraform/helper/logging"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"github.com/mitchellh/cli"
|
||||
|
@ -111,6 +110,8 @@ func init() {
|
|||
}
|
||||
|
||||
func wrappedMain() int {
|
||||
var err error
|
||||
|
||||
// We always need to close the DebugInfo before we exit.
|
||||
defer terraform.CloseDebugInfo()
|
||||
|
||||
|
@ -121,38 +122,11 @@ func wrappedMain() int {
|
|||
log.Printf("[INFO] Go runtime version: %s", runtime.Version())
|
||||
log.Printf("[INFO] CLI args: %#v", os.Args)
|
||||
|
||||
// Load the configuration
|
||||
config := BuiltinConfig
|
||||
|
||||
// Load the configuration file if we have one, that can be used to
|
||||
// define extra providers and provisioners.
|
||||
clicfgFile, err := cliConfigFile()
|
||||
if err != nil {
|
||||
Ui.Error(fmt.Sprintf("Error loading CLI configuration: \n\n%s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
if clicfgFile != "" {
|
||||
usrcfg, err := LoadConfig(clicfgFile)
|
||||
if err != nil {
|
||||
Ui.Error(fmt.Sprintf("Error loading CLI configuration: \n\n%s", err))
|
||||
return 1
|
||||
}
|
||||
|
||||
config = *config.Merge(usrcfg)
|
||||
}
|
||||
|
||||
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())
|
||||
config, diags := LoadConfig()
|
||||
if len(diags) > 0 {
|
||||
// Since we haven't instantiated a command.Meta yet, we need to do
|
||||
// some things manually here and use some "safe" defaults for things
|
||||
// that command.Meta could otherwise figure out in smarter ways.
|
||||
Ui.Error("There are some problems with the CLI configuration:")
|
||||
for _, diag := range diags {
|
||||
earlyColor := &colorstring.Colorize{
|
||||
|
@ -164,17 +138,18 @@ func wrappedMain() int {
|
|||
}
|
||||
if diags.HasErrors() {
|
||||
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.
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Printf("[DEBUG] CLI config is %#v", config)
|
||||
|
||||
// In tests, Commands may already be set to provide mock commands
|
||||
if Commands == nil {
|
||||
initCommands(&config)
|
||||
initCommands(config)
|
||||
}
|
||||
|
||||
// Run checkpoint
|
||||
go runCheckpoint(&config)
|
||||
go runCheckpoint(config)
|
||||
|
||||
// Make sure we clean up any managed plugins at the end of this
|
||||
defer plugin.CleanupClients()
|
||||
|
|
Loading…
Reference in New Issue