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:
parent
fe7ef7ae5d
commit
a2c59c6ecd
40
config.go
40
config.go
|
@ -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 {
|
||||
|
|
|
@ -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
23
main.go
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue