github.com/blacked/terraform@v0.6.2-0.20150806163846-669c4ad71586/builtin/providers/google/config.go (about)

     1  package google
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"log"
     8  	"net/http"
     9  	"os"
    10  	"runtime"
    11  	"strings"
    12  
    13  
    14  	// TODO(dcunnin): Use version code from version.go
    15  	// "github.com/hashicorp/terraform"
    16  	"golang.org/x/oauth2"
    17  	"golang.org/x/oauth2/google"
    18  	"golang.org/x/oauth2/jwt"
    19  	"google.golang.org/api/compute/v1"
    20  	"google.golang.org/api/container/v1"
    21  	"google.golang.org/api/dns/v1"
    22  	"google.golang.org/api/storage/v1"
    23  )
    24  
    25  // Config is the configuration structure used to instantiate the Google
    26  // provider.
    27  type Config struct {
    28  	AccountFile string
    29  	Project     string
    30  	Region      string
    31  
    32  	clientCompute *compute.Service
    33  	clientContainer *container.Service
    34  	clientDns *dns.Service
    35  	clientStorage *storage.Service
    36  }
    37  
    38  func (c *Config) loadAndValidate() error {
    39  	var account accountFile
    40  
    41  	if c.AccountFile == "" {
    42  		c.AccountFile = os.Getenv("GOOGLE_ACCOUNT_FILE")
    43  	}
    44  	if c.Project == "" {
    45  		c.Project = os.Getenv("GOOGLE_PROJECT")
    46  	}
    47  	if c.Region == "" {
    48  		c.Region = os.Getenv("GOOGLE_REGION")
    49  	}
    50  
    51  	var client *http.Client
    52  
    53  	if c.AccountFile != "" {
    54  		contents := c.AccountFile
    55  
    56  		// Assume account_file is a JSON string
    57  		if err := parseJSON(&account, contents); err != nil {
    58  			// If account_file was not JSON, assume it is a file path instead
    59  			if _, err := os.Stat(c.AccountFile); os.IsNotExist(err) {
    60  				return fmt.Errorf(
    61  					"account_file path does not exist: %s",
    62  					c.AccountFile)
    63  			}
    64  
    65  			b, err := ioutil.ReadFile(c.AccountFile)
    66  			if err != nil {
    67  				return fmt.Errorf(
    68  					"Error reading account_file from path '%s': %s",
    69  					c.AccountFile,
    70  					err)
    71  			}
    72  
    73  			contents = string(b)
    74  
    75  			if err := parseJSON(&account, contents); err != nil {
    76  				return fmt.Errorf(
    77  					"Error parsing account file '%s': %s",
    78  					contents,
    79  					err)
    80  			}
    81  		}
    82  
    83  		clientScopes := []string{
    84  			"https://www.googleapis.com/auth/compute",
    85  			"https://www.googleapis.com/auth/cloud-platform",
    86  			"https://www.googleapis.com/auth/ndev.clouddns.readwrite",
    87  			"https://www.googleapis.com/auth/devstorage.full_control",
    88  		}
    89  
    90  		// Get the token for use in our requests
    91  		log.Printf("[INFO] Requesting Google token...")
    92  		log.Printf("[INFO]   -- Email: %s", account.ClientEmail)
    93  		log.Printf("[INFO]   -- Scopes: %s", clientScopes)
    94  		log.Printf("[INFO]   -- Private Key Length: %d", len(account.PrivateKey))
    95  
    96  		conf := jwt.Config{
    97  			Email:      account.ClientEmail,
    98  			PrivateKey: []byte(account.PrivateKey),
    99  			Scopes:     clientScopes,
   100  			TokenURL:   "https://accounts.google.com/o/oauth2/token",
   101  		}
   102  
   103  		// Initiate an http.Client. The following GET request will be
   104  		// authorized and authenticated on the behalf of
   105  		// your service account.
   106  		client = conf.Client(oauth2.NoContext)
   107  
   108  	} else {
   109  		log.Printf("[INFO] Requesting Google token via GCE Service Role...")
   110  		client = &http.Client{
   111  			Transport: &oauth2.Transport{
   112  				// Fetch from Google Compute Engine's metadata server to retrieve
   113  				// an access token for the provided account.
   114  				// If no account is specified, "default" is used.
   115  				Source: google.ComputeTokenSource(""),
   116  			},
   117  		}
   118  
   119  	}
   120  
   121  	// Build UserAgent
   122  	versionString := "0.0.0"
   123  	// TODO(dcunnin): Use Terraform's version code from version.go
   124  	// versionString := main.Version
   125  	// if main.VersionPrerelease != "" {
   126  	// 	versionString = fmt.Sprintf("%s-%s", versionString, main.VersionPrerelease)
   127  	// }
   128  	userAgent := fmt.Sprintf(
   129  		"(%s %s) Terraform/%s", runtime.GOOS, runtime.GOARCH, versionString)
   130  
   131  	var err error
   132  
   133  	log.Printf("[INFO] Instantiating GCE client...")
   134  	c.clientCompute, err = compute.New(client)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	c.clientCompute.UserAgent = userAgent
   139  
   140  	log.Printf("[INFO] Instantiating GKE client...")
   141  	c.clientContainer, err = container.New(client)
   142  	if err != nil {
   143  		return err
   144  	}
   145  	c.clientContainer.UserAgent = userAgent
   146  
   147  	log.Printf("[INFO] Instantiating Google Cloud DNS client...")
   148  	c.clientDns, err = dns.New(client)
   149  	if err != nil {
   150  		return err
   151  	}
   152  	c.clientDns.UserAgent = userAgent
   153  
   154  	log.Printf("[INFO] Instantiating Google Storage Client...")
   155  	c.clientStorage, err = storage.New(client)
   156  	if err != nil {
   157  		return err
   158  	}
   159  	c.clientStorage.UserAgent = userAgent
   160  
   161  	return nil
   162  }
   163  
   164  // accountFile represents the structure of the account file JSON file.
   165  type accountFile struct {
   166  	PrivateKeyId string `json:"private_key_id"`
   167  	PrivateKey   string `json:"private_key"`
   168  	ClientEmail  string `json:"client_email"`
   169  	ClientId     string `json:"client_id"`
   170  }
   171  
   172  func parseJSON(result interface{}, contents string) error {
   173  	r := strings.NewReader(contents)
   174  	dec := json.NewDecoder(r)
   175  
   176  	return dec.Decode(result)
   177  }