main: validate credentials blocks in CLI config

We require that each "credentials" block has a valid hostname and that
there be no more than one "credentials_helper" block.

There are some more sophisticated validations we could do here, such as
checking if the same host is declared more than once, but since this
config handling will be rewritten to use HCL2 in the near future, and this
sort of check is easier to do in the HCL2 API, we just check the basic
stuff for now and plan to revisit later.
This commit is contained in:
Martin Atkins 2017-10-19 16:43:18 -07:00
parent fe7ef7ae5d
commit a2c59c6ecd
3 changed files with 128 additions and 0 deletions

View File

@ -8,7 +8,10 @@ import (
"os"
"github.com/hashicorp/hcl"
"github.com/hashicorp/terraform/command"
"github.com/hashicorp/terraform/svchost"
"github.com/hashicorp/terraform/tfdiags"
)
const pluginCacheDirEnvVar = "TF_PLUGIN_CACHE_DIR"
@ -115,6 +118,43 @@ func EnvConfig() *Config {
return config
}
// Validate checks for errors in the configuration that cannot be detected
// just by HCL decoding, returning any problems as diagnostics.
//
// On success, the returned diagnostics will return false from the HasErrors
// method. A non-nil diagnostics is not necessarily an error, since it may
// contain just warnings.
func (c *Config) Validate() tfdiags.Diagnostics {
var diags tfdiags.Diagnostics
if c == nil {
return diags
}
// FIXME: Right now our config parsing doesn't retain enough information
// to give proper source references to any errors. We should improve
// on this when we change the CLI config parser to use HCL2.
// Check that all "credentials" blocks have valid hostnames.
for givenHost := range c.Credentials {
_, err := svchost.ForComparison(givenHost)
if err != nil {
diags = diags.Append(
fmt.Errorf("The credentials %q block has an invalid hostname: %s", givenHost, err),
)
}
}
// Should have zero or one "credentials_helper" blocks
if len(c.CredentialsHelpers) > 1 {
diags = diags.Append(
fmt.Errorf("No more than one credentials_helper block may be specified"),
)
}
return diags
}
// Merge merges two configurations and returns a third entirely
// new configuration with the two merged.
func (c1 *Config) Merge(c2 *Config) *Config {

View File

@ -82,6 +82,71 @@ func TestLoadConfig_credentials(t *testing.T) {
}
}
func TestConfigValidate(t *testing.T) {
tests := map[string]struct {
Config *Config
DiagCount int
}{
"nil": {
nil,
0,
},
"empty": {
&Config{},
0,
},
"credentials good": {
&Config{
Credentials: map[string]map[string]interface{}{
"example.com": map[string]interface{}{
"token": "foo",
},
},
},
0,
},
"credentials with bad hostname": {
&Config{
Credentials: map[string]map[string]interface{}{
"example..com": map[string]interface{}{
"token": "foo",
},
},
},
1, // credentials block has invalid hostname
},
"credentials helper good": {
&Config{
CredentialsHelpers: map[string]*ConfigCredentialsHelper{
"foo": {},
},
},
0,
},
"credentials helper too many": {
&Config{
CredentialsHelpers: map[string]*ConfigCredentialsHelper{
"foo": {},
"bar": {},
},
},
1, // no more than one credentials_helper block allowed
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
diags := test.Config.Validate()
if len(diags) != test.DiagCount {
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
for _, diag := range diags {
t.Logf("- %#v", diag.Description())
}
}
})
}
}
func TestConfig_Merge(t *testing.T) {
c1 := &Config{
Providers: map[string]string{

23
main.go
View File

@ -11,9 +11,13 @@ import (
"strings"
"sync"
"github.com/mitchellh/colorstring"
"github.com/hashicorp/go-plugin"
"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"
@ -145,6 +149,25 @@ func wrappedMain() int {
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")
}
}
}
// In tests, Commands may already be set to provide mock commands
if Commands == nil {
initCommands(&config)