diff --git a/builtin/providers/google/resource_compute_instance.go b/builtin/providers/google/resource_compute_instance.go index 92065fb68..ca3120a0d 100644 --- a/builtin/providers/google/resource_compute_instance.go +++ b/builtin/providers/google/resource_compute_instance.go @@ -124,6 +124,33 @@ func resourceComputeInstance() *schema.Resource { }, }, + "service_account": &schema.Schema{ + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "email": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + ForceNew: true, + }, + + "scopes": &schema.Schema{ + Type: schema.TypeList, + Required: true, + ForceNew: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + StateFunc: func(v interface{}) string { + return canonicalizeServiceScope(v.(string)) + }, + }, + }, + }, + }, + }, + "tags": &schema.Schema{ Type: schema.TypeSet, Optional: true, @@ -259,6 +286,26 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err networks = append(networks, &iface) } + serviceAccountsCount := d.Get("service_account.#").(int) + serviceAccounts := make([]*compute.ServiceAccount, 0, serviceAccountsCount) + for i := 0; i < serviceAccountsCount; i++ { + prefix := fmt.Sprintf("service_account.%d", i) + + scopesCount := d.Get(prefix + ".scopes.#").(int) + scopes := make([]string, 0, scopesCount) + for j := 0; j < scopesCount; j++ { + scope := d.Get(fmt.Sprintf(prefix + ".scopes.%d", j)).(string) + scopes = append(scopes, canonicalizeServiceScope(scope)) + } + + serviceAccount := &compute.ServiceAccount { + Email: "default", + Scopes: scopes, + } + + serviceAccounts = append(serviceAccounts, serviceAccount) + } + // Create the instance information instance := compute.Instance{ CanIpForward: d.Get("can_ip_forward").(bool), @@ -269,18 +316,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err Name: d.Get("name").(string), NetworkInterfaces: networks, Tags: resourceInstanceTags(d), - /* - ServiceAccounts: []*compute.ServiceAccount{ - &compute.ServiceAccount{ - Email: "default", - Scopes: []string{ - "https://www.googleapis.com/auth/userinfo.email", - "https://www.googleapis.com/auth/compute", - "https://www.googleapis.com/auth/devstorage.full_control", - }, - }, - }, - */ + ServiceAccounts: serviceAccounts, } log.Printf("[INFO] Requesting instance creation") @@ -339,6 +375,16 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error d.Set("can_ip_forward", instance.CanIpForward) + // Set the service accounts + for i, serviceAccount := range instance.ServiceAccounts { + prefix := fmt.Sprintf("service_account.%d", i) + d.Set(prefix + ".email", serviceAccount.Email) + d.Set(prefix + ".scopes.#", len(serviceAccount.Scopes)) + for j, scope := range serviceAccount.Scopes { + d.Set(fmt.Sprintf("%s.scopes.%d", prefix, j), scope) + } + } + // Set the networks externalIP := "" for i, iface := range instance.NetworkInterfaces { diff --git a/builtin/providers/google/service_scope.go b/builtin/providers/google/service_scope.go new file mode 100644 index 000000000..e4d5203c6 --- /dev/null +++ b/builtin/providers/google/service_scope.go @@ -0,0 +1,25 @@ +package google + +func canonicalizeServiceScope(scope string) string { + // This is a convenience map of short names used by the gcloud tool + // to the GCE auth endpoints they alias to. + scopeMap := map[string]string{ + "bigquery": "https://www.googleapis.com/auth/bigquery", + "compute-ro": "https://www.googleapis.com/auth/compute.readonly", + "compute-rw": "https://www.googleapis.com/auth/compute", + "datastore": "https://www.googleapis.com/auth/datastore", + "sql": "https://www.googleapis.com/auth/sqlservice", + "sql-admin": "https://www.googleapis.com/auth/sqlservice.admin", + "storage-full": "https://www.googleapis.com/auth/devstorage.full_control", + "storage-ro": "https://www.googleapis.com/auth/devstorage.read_only", + "storage-rw": "https://www.googleapis.com/auth/devstorage.read_write", + "taskqueue": "https://www.googleapis.com/auth/taskqueue", + "userinfo-email": "https://www.googleapis.com/auth/userinfo.email", + } + + if matchedUrl, ok := scopeMap[scope]; ok { + return matchedUrl + } else { + return scope + } +} diff --git a/website/source/docs/providers/google/r/compute_instance.html.markdown b/website/source/docs/providers/google/r/compute_instance.html.markdown index a30860947..a9e6a6687 100644 --- a/website/source/docs/providers/google/r/compute_instance.html.markdown +++ b/website/source/docs/providers/google/r/compute_instance.html.markdown @@ -30,6 +30,10 @@ resource "google_compute_instance" "default" { metadata { foo = "bar" } + + service_account { + scopes = ["userinfo-email", "compute-ro", "storage-ro"] + } } ``` @@ -60,6 +64,8 @@ The following arguments are supported: specified multiple times for multiple networks. Structure is documented below. +* `service_account` - (Optional) Service account to attach to the instance. + * `tags` - (Optional) Tags to attach to the instance. The `disk` block supports: @@ -82,6 +88,11 @@ The `network` block supports: * `address` - (Optional) The IP address of a reserved IP address to assign to this interface. +The `service_account` block supports: + +* `scopes` - (Required) A list of service scopes. Both OAuth2 URLs and gcloud + short names are supported. + ## Attributes Reference The following attributes are exported: