diff --git a/config.go b/config.go index 3edb68ef..218fda06 100644 --- a/config.go +++ b/config.go @@ -3,13 +3,12 @@ package google import ( "encoding/json" "fmt" - "io/ioutil" "log" "net/http" - "os" "runtime" "strings" + "github.com/hashicorp/terraform/helper/pathorcontents" "github.com/hashicorp/terraform/terraform" "golang.org/x/oauth2" "golang.org/x/oauth2/google" @@ -24,7 +23,7 @@ import ( // Config is the configuration structure used to instantiate the Google // provider. type Config struct { - AccountFile string + Credentials string Project string Region string @@ -44,46 +43,17 @@ func (c *Config) loadAndValidate() error { "https://www.googleapis.com/auth/devstorage.full_control", } - if c.AccountFile == "" { - c.AccountFile = os.Getenv("GOOGLE_ACCOUNT_FILE") - } - if c.Project == "" { - c.Project = os.Getenv("GOOGLE_PROJECT") - } - if c.Region == "" { - c.Region = os.Getenv("GOOGLE_REGION") - } - var client *http.Client - if c.AccountFile != "" { - contents := c.AccountFile + if c.Credentials != "" { + contents, _, err := pathorcontents.Read(c.Credentials) + if err != nil { + return fmt.Errorf("Error loading credentials: %s", err) + } // Assume account_file is a JSON string if err := parseJSON(&account, contents); err != nil { - // If account_file was not JSON, assume it is a file path instead - if _, err := os.Stat(c.AccountFile); os.IsNotExist(err) { - return fmt.Errorf( - "account_file path does not exist: %s", - c.AccountFile) - } - - b, err := ioutil.ReadFile(c.AccountFile) - if err != nil { - return fmt.Errorf( - "Error reading account_file from path '%s': %s", - c.AccountFile, - err) - } - - contents = string(b) - - if err := parseJSON(&account, contents); err != nil { - return fmt.Errorf( - "Error parsing account file '%s': %s", - contents, - err) - } + return fmt.Errorf("Error parsing credentials '%s': %s", contents, err) } // Get the token for use in our requests diff --git a/config_test.go b/config_test.go index cc1b6213..648f93a6 100644 --- a/config_test.go +++ b/config_test.go @@ -5,11 +5,11 @@ import ( "testing" ) -const testFakeAccountFilePath = "./test-fixtures/fake_account.json" +const testFakeCredentialsPath = "./test-fixtures/fake_account.json" func TestConfigLoadAndValidate_accountFilePath(t *testing.T) { config := Config{ - AccountFile: testFakeAccountFilePath, + Credentials: testFakeCredentialsPath, Project: "my-gce-project", Region: "us-central1", } @@ -21,12 +21,12 @@ func TestConfigLoadAndValidate_accountFilePath(t *testing.T) { } func TestConfigLoadAndValidate_accountFileJSON(t *testing.T) { - contents, err := ioutil.ReadFile(testFakeAccountFilePath) + contents, err := ioutil.ReadFile(testFakeCredentialsPath) if err != nil { t.Fatalf("error: %v", err) } config := Config{ - AccountFile: string(contents), + Credentials: string(contents), Project: "my-gce-project", Region: "us-central1", } @@ -39,7 +39,7 @@ func TestConfigLoadAndValidate_accountFileJSON(t *testing.T) { func TestConfigLoadAndValidate_accountFileJSONInvalid(t *testing.T) { config := Config{ - AccountFile: "{this is not json}", + Credentials: "{this is not json}", Project: "my-gce-project", Region: "us-central1", } diff --git a/provider.go b/provider.go index 3cfc363d..b2d083bc 100644 --- a/provider.go +++ b/provider.go @@ -3,8 +3,8 @@ package google import ( "encoding/json" "fmt" - "os" + "github.com/hashicorp/terraform/helper/pathorcontents" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" ) @@ -18,6 +18,14 @@ func Provider() terraform.ResourceProvider { Optional: true, DefaultFunc: schema.EnvDefaultFunc("GOOGLE_ACCOUNT_FILE", nil), ValidateFunc: validateAccountFile, + Deprecated: "Use the credentials field instead", + }, + + "credentials": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("GOOGLE_CREDENTIALS", nil), + ValidateFunc: validateCredentials, }, "project": &schema.Schema{ @@ -73,8 +81,12 @@ func Provider() terraform.ResourceProvider { } func providerConfigure(d *schema.ResourceData) (interface{}, error) { + credentials := d.Get("credentials").(string) + if credentials == "" { + credentials = d.Get("account_file").(string) + } config := Config{ - AccountFile: d.Get("account_file").(string), + Credentials: credentials, Project: d.Get("project").(string), Region: d.Get("region").(string), } @@ -97,22 +109,34 @@ func validateAccountFile(v interface{}, k string) (warnings []string, errors []e return } - var account accountFile - if err := json.Unmarshal([]byte(value), &account); err != nil { - warnings = append(warnings, ` -account_file is not valid JSON, so we are assuming it is a file path. This -support will be removed in the future. Please update your configuration to use -${file("filename.json")} instead.`) - } else { - return + contents, wasPath, err := pathorcontents.Read(value) + if err != nil { + errors = append(errors, fmt.Errorf("Error loading Account File: %s", err)) + } + if wasPath { + warnings = append(warnings, `account_file was provided as a path instead of +as file contents. This support will be removed in the future. Please update +your configuration to use ${file("filename.json")} instead.`) } - if _, err := os.Stat(value); err != nil { + var account accountFile + if err := json.Unmarshal([]byte(contents), &account); err != nil { errors = append(errors, - fmt.Errorf( - "account_file path could not be read from '%s': %s", - value, - err)) + fmt.Errorf("account_file not valid JSON '%s': %s", contents, err)) + } + + return +} + +func validateCredentials(v interface{}, k string) (warnings []string, errors []error) { + if v == nil || v.(string) == "" { + return + } + creds := v.(string) + var account accountFile + if err := json.Unmarshal([]byte(creds), &account); err != nil { + errors = append(errors, + fmt.Errorf("credentials are not valid JSON '%s': %s", creds, err)) } return diff --git a/provider_test.go b/provider_test.go index 2275e188..827a7f57 100644 --- a/provider_test.go +++ b/provider_test.go @@ -29,8 +29,8 @@ func TestProvider_impl(t *testing.T) { } func testAccPreCheck(t *testing.T) { - if v := os.Getenv("GOOGLE_ACCOUNT_FILE"); v == "" { - t.Fatal("GOOGLE_ACCOUNT_FILE must be set for acceptance tests") + if v := os.Getenv("GOOGLE_CREDENTIALS"); v == "" { + t.Fatal("GOOGLE_CREDENTIALS must be set for acceptance tests") } if v := os.Getenv("GOOGLE_PROJECT"); v == "" {