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