providers/google: Change account_file to JSON
If JSON fails to parse, treat it as a file path
This commit is contained in:
parent
2a04708d66
commit
773852e2d5
|
@ -25,10 +25,9 @@ import (
|
|||
// Config is the configuration structure used to instantiate the Google
|
||||
// provider.
|
||||
type Config struct {
|
||||
AccountFile string
|
||||
AccountFileContents string
|
||||
Project string
|
||||
Region string
|
||||
AccountFile string
|
||||
Project string
|
||||
Region string
|
||||
|
||||
clientCompute *compute.Service
|
||||
clientContainer *container.Service
|
||||
|
@ -39,13 +38,9 @@ type Config struct {
|
|||
func (c *Config) loadAndValidate() error {
|
||||
var account accountFile
|
||||
|
||||
// TODO: validation that it isn't blank
|
||||
if c.AccountFile == "" {
|
||||
c.AccountFile = os.Getenv("GOOGLE_ACCOUNT_FILE")
|
||||
}
|
||||
if c.AccountFileContents == "" {
|
||||
c.AccountFileContents = os.Getenv("GOOGLE_ACCOUNT_FILE_CONTENTS")
|
||||
}
|
||||
if c.Project == "" {
|
||||
c.Project = os.Getenv("GOOGLE_PROJECT")
|
||||
}
|
||||
|
@ -56,25 +51,32 @@ func (c *Config) loadAndValidate() error {
|
|||
var client *http.Client
|
||||
|
||||
if c.AccountFile != "" {
|
||||
if c.AccountFileContents != "" {
|
||||
return fmt.Errorf(
|
||||
"Cannot provide both account_file and account_file_contents",
|
||||
)
|
||||
contents := c.AccountFile
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadFile(c.AccountFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.AccountFileContents = string(b)
|
||||
}
|
||||
|
||||
if c.AccountFileContents != "" {
|
||||
if err := parseJSON(&account, c.AccountFileContents); err != nil {
|
||||
if err := parseJSON(&account, contents); err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error parsing account file contents '%s': %s",
|
||||
c.AccountFileContents,
|
||||
"Error parsing account file '%s': %s",
|
||||
contents,
|
||||
err)
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
const testFakeAccountFilePath = "./test-fixtures/fake_account.json"
|
||||
|
||||
func TestConfigLoadAndValidate_accountFile(t *testing.T) {
|
||||
func TestConfigLoadAndValidate_accountFilePath(t *testing.T) {
|
||||
config := Config{
|
||||
AccountFile: testFakeAccountFilePath,
|
||||
Project: "my-gce-project",
|
||||
|
@ -20,15 +20,15 @@ func TestConfigLoadAndValidate_accountFile(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConfigLoadAndValidate_accountFileContents(t *testing.T) {
|
||||
func TestConfigLoadAndValidate_accountFileJSON(t *testing.T) {
|
||||
contents, err := ioutil.ReadFile(testFakeAccountFilePath)
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
config := Config{
|
||||
AccountFileContents: string(contents),
|
||||
Project: "my-gce-project",
|
||||
Region: "us-central1",
|
||||
AccountFile: string(contents),
|
||||
Project: "my-gce-project",
|
||||
Region: "us-central1",
|
||||
}
|
||||
|
||||
err = config.loadAndValidate()
|
||||
|
@ -37,24 +37,11 @@ func TestConfigLoadAndValidate_accountFileContents(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConfigLoadAndValidate_none(t *testing.T) {
|
||||
func TestConfigLoadAndValidate_accountFileJSONInvalid(t *testing.T) {
|
||||
config := Config{
|
||||
Project: "my-gce-project",
|
||||
Region: "us-central1",
|
||||
}
|
||||
|
||||
err := config.loadAndValidate()
|
||||
if err != nil {
|
||||
t.Fatalf("error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigLoadAndValidate_both(t *testing.T) {
|
||||
config := Config{
|
||||
AccountFile: testFakeAccountFilePath,
|
||||
AccountFileContents: "{}",
|
||||
Project: "my-gce-project",
|
||||
Region: "us-central1",
|
||||
AccountFile: "{this is not json}",
|
||||
Project: "my-gce-project",
|
||||
Region: "us-central1",
|
||||
}
|
||||
|
||||
if config.loadAndValidate() == nil {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package google
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
@ -10,15 +14,10 @@ func Provider() terraform.ResourceProvider {
|
|||
return &schema.Provider{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"account_file": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("GOOGLE_ACCOUNT_FILE", ""),
|
||||
},
|
||||
|
||||
"account_file_contents": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("GOOGLE_ACCOUNT_FILE_CONTENTS", ""),
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
DefaultFunc: schema.EnvDefaultFunc("GOOGLE_ACCOUNT_FILE", nil),
|
||||
ValidateFunc: validateAccountFile,
|
||||
},
|
||||
|
||||
"project": &schema.Schema{
|
||||
|
@ -59,10 +58,9 @@ func Provider() terraform.ResourceProvider {
|
|||
|
||||
func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
||||
config := Config{
|
||||
AccountFile: d.Get("account_file").(string),
|
||||
AccountFileContents: d.Get("account_file_contents").(string),
|
||||
Project: d.Get("project").(string),
|
||||
Region: d.Get("region").(string),
|
||||
AccountFile: d.Get("account_file").(string),
|
||||
Project: d.Get("project").(string),
|
||||
Region: d.Get("region").(string),
|
||||
}
|
||||
|
||||
if err := config.loadAndValidate(); err != nil {
|
||||
|
@ -71,3 +69,28 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
|
|||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func validateAccountFile(v interface{}, k string) (warnings []string, errors []error) {
|
||||
value := v.(string)
|
||||
|
||||
if value == "" {
|
||||
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.`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := os.Stat(value); os.IsNotExist(err) {
|
||||
errors = append(errors, err)
|
||||
fmt.Errorf("account_file path does not exist: %s", value)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ Use the navigation to the left to read about the available resources.
|
|||
```
|
||||
# Configure the Google Cloud provider
|
||||
provider "google" {
|
||||
account_file = "account.json"
|
||||
account_file = "${file("account.json")}"
|
||||
project = "my-gce-project"
|
||||
region = "us-central1"
|
||||
}
|
||||
|
@ -34,19 +34,13 @@ resource "google_compute_instance" "default" {
|
|||
|
||||
The following keys can be used to configure the provider.
|
||||
|
||||
* `account_file` - (Required, unless `account_file_contents` is present) Path
|
||||
to the JSON file used to describe your account credentials, downloaded from
|
||||
Google Cloud Console. More details on retrieving this file are below. The
|
||||
_account file_ can be "" if you are running terraform from a GCE instance with
|
||||
a properly-configured [Compute Engine Service
|
||||
Account](https://cloud.google.com/compute/docs/authentication). This can also
|
||||
be specified with the `GOOGLE_ACCOUNT_FILE` shell environment variable.
|
||||
|
||||
* `account_file_contents` - (Required, unless `account_file` is present) The
|
||||
contents of `account_file`. This can be used to pass the account credentials
|
||||
with a Terraform var or environment variable if the account file is not
|
||||
accessible. This can also be specified with the `GOOGLE_ACCOUNT_FILE_CONTENTS`
|
||||
shell environment variable.
|
||||
* `account_file` - (Required) Contents of the JSON file used to describe your
|
||||
account credentials, downloaded from Google Cloud Console. More details on
|
||||
retrieving this file are below. The `account file` can be "" if you are running
|
||||
terraform from a GCE instance with a properly-configured [Compute Engine
|
||||
Service Account](https://cloud.google.com/compute/docs/authentication). This
|
||||
can also be specified with the `GOOGLE_ACCOUNT_FILE` shell environment
|
||||
variable.
|
||||
|
||||
* `project` - (Required) The ID of the project to apply any resources to. This
|
||||
can also be specified with the `GOOGLE_PROJECT` shell environment variable.
|
||||
|
|
Loading…
Reference in New Issue