main: configure credentials from the CLI config file

This commit is contained in:
Martin Atkins 2017-10-19 17:40:20 -07:00
parent 47c45788bc
commit 35a058fb3d
4 changed files with 100 additions and 3 deletions

View File

@ -4,10 +4,11 @@ import (
"os"
"os/signal"
"github.com/hashicorp/terraform/command"
pluginDiscovery "github.com/hashicorp/terraform/plugin/discovery"
"github.com/hashicorp/terraform/svchost"
"github.com/hashicorp/terraform/svchost/auth"
"github.com/hashicorp/terraform/svchost/disco"
"github.com/hashicorp/terraform/command"
"github.com/mitchellh/cli"
)
@ -34,7 +35,7 @@ func initCommands(config *Config) {
inAutomation = true
}
credsSrc := auth.NoCredentials // TODO: Actually expose credentials here
credsSrc := credentialsSource(config)
services := disco.NewDisco()
services.SetCredentialsSource(credsSrc)
@ -342,3 +343,43 @@ func makeShutdownCh() <-chan struct{} {
return resultCh
}
func credentialsSource(config *Config) auth.CredentialsSource {
creds := auth.NoCredentials
if len(config.Credentials) > 0 {
staticTable := map[svchost.Hostname]map[string]interface{}{}
for userHost, creds := range config.Credentials {
host, err := svchost.ForComparison(userHost)
if err != nil {
// We expect the config was already validated by the time we get
// here, so we'll just ignore invalid hostnames.
continue
}
staticTable[host] = creds
}
creds = auth.StaticCredentialsSource(staticTable)
}
for helperType, helperConfig := range config.CredentialsHelpers {
available := pluginDiscovery.FindPlugins("credentials", globalPluginDirs())
available = available.WithName(helperType)
if available.Count() == 0 {
break
}
selected := available.Newest()
helperSource := auth.HelperProgramCredentialsSource(selected.Path, helperConfig.Args...)
creds = auth.Credentials{
creds,
auth.CachingCredentialsSource(helperSource), // cached because external operation may be slow/expensive
}
// There should only be zero or one "credentials_helper" blocks. We
// assume that the config was validated earlier and so we don't check
// for extras here.
break
}
return creds
}

View File

@ -27,6 +27,15 @@ type Config struct {
// If set, enables local caching of plugins in this directory to
// avoid repeatedly re-downloading over the Internet.
PluginCacheDir string `hcl:"plugin_cache_dir"`
Credentials map[string]map[string]interface{} `hcl:"credentials"`
CredentialsHelpers map[string]*ConfigCredentialsHelper `hcl:"credentials_helper"`
}
// ConfigCredentialsHelper is the structure of the "credentials_helper"
// nested block within the CLI configuration.
type ConfigCredentialsHelper struct {
Args []string `hcl:"args"`
}
// BuiltinConfig is the built-in defaults for the configuration. These

View File

@ -5,6 +5,8 @@ import (
"path/filepath"
"reflect"
"testing"
"github.com/davecgh/go-spew/spew"
)
// This is the directory where our test fixtures are.
@ -52,6 +54,34 @@ func TestLoadConfig_env(t *testing.T) {
}
}
func TestLoadConfig_credentials(t *testing.T) {
got, err := LoadConfig(filepath.Join(fixtureDir, "credentials"))
if err != nil {
t.Fatal(err)
}
want := &Config{
Credentials: map[string]map[string]interface{}{
"example.com": map[string]interface{}{
"token": "foo the bar baz",
},
"example.net": map[string]interface{}{
"username": "foo",
"password": "baz",
},
},
CredentialsHelpers: map[string]*ConfigCredentialsHelper{
"foo": &ConfigCredentialsHelper{
Args: []string{"bar", "baz"},
},
},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(want))
}
}
func TestConfig_Merge(t *testing.T) {
c1 := &Config{
Providers: map[string]string{

17
test-fixtures/credentials Normal file
View File

@ -0,0 +1,17 @@
credentials "example.com" {
token = "foo the bar baz"
}
credentials "example.net" {
# Username and password are not currently supported, but we want to tolerate
# unknown keys in case future versions add new keys when both old and new
# versions of Terraform are installed on a system, sharing the same
# CLI config.
username = "foo"
password = "baz"
}
credentials_helper "foo" {
args = ["bar", "baz"]
}