Bigtable instance support.

This commit is contained in:
Riley Karson 2017-06-15 10:41:05 -07:00 committed by Riley Karson
parent dae866228e
commit 53b91630f5
6 changed files with 395 additions and 0 deletions

View File

@ -0,0 +1,22 @@
package google
import (
"context"
"cloud.google.com/go/bigtable"
"golang.org/x/oauth2"
"google.golang.org/api/option"
)
type ClientFactoryBigtable struct {
UserAgent string
TokenSource oauth2.TokenSource
}
func (s *ClientFactoryBigtable) NewInstanceAdminClient(project string) (*bigtable.InstanceAdminClient, error) {
return bigtable.NewInstanceAdminClient(context.Background(), project, option.WithTokenSource(s.TokenSource), option.WithUserAgent(s.UserAgent))
}
func (s *ClientFactoryBigtable) NewAdminClient(project, instance string) (*bigtable.AdminClient, error) {
return bigtable.NewAdminClient(context.Background(), project, instance, option.WithTokenSource(s.TokenSource), option.WithUserAgent(s.UserAgent))
}

View File

@ -1,6 +1,7 @@
package google package google
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log" "log"
@ -11,6 +12,7 @@ import (
"github.com/hashicorp/terraform/helper/logging" "github.com/hashicorp/terraform/helper/logging"
"github.com/hashicorp/terraform/helper/pathorcontents" "github.com/hashicorp/terraform/helper/pathorcontents"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
"golang.org/x/oauth2/jwt" "golang.org/x/oauth2/jwt"
@ -45,6 +47,8 @@ type Config struct {
clientIAM *iam.Service clientIAM *iam.Service
clientServiceMan *servicemanagement.APIService clientServiceMan *servicemanagement.APIService
clientBigQuery *bigquery.Service clientBigQuery *bigquery.Service
clientFactoryBigtable *ClientFactoryBigtable
} }
func (c *Config) loadAndValidate() error { func (c *Config) loadAndValidate() error {
@ -57,6 +61,7 @@ func (c *Config) loadAndValidate() error {
} }
var client *http.Client var client *http.Client
var tokenSource oauth2.TokenSource
if c.Credentials != "" { if c.Credentials != "" {
contents, _, err := pathorcontents.Read(c.Credentials) contents, _, err := pathorcontents.Read(c.Credentials)
@ -87,6 +92,7 @@ func (c *Config) loadAndValidate() error {
// your service account. // your service account.
client = conf.Client(oauth2.NoContext) client = conf.Client(oauth2.NoContext)
tokenSource = conf.TokenSource(context.Background())
} else { } else {
log.Printf("[INFO] Authenticating using DefaultClient") log.Printf("[INFO] Authenticating using DefaultClient")
err := error(nil) err := error(nil)
@ -94,6 +100,11 @@ func (c *Config) loadAndValidate() error {
if err != nil { if err != nil {
return err return err
} }
tokenSource, err = google.DefaultTokenSource(oauth2.NoContext, clientScopes...)
if err != nil {
return err
}
} }
client.Transport = logging.NewTransport("Google", client.Transport) client.Transport = logging.NewTransport("Google", client.Transport)
@ -181,6 +192,12 @@ func (c *Config) loadAndValidate() error {
} }
c.clientBigQuery.UserAgent = userAgent c.clientBigQuery.UserAgent = userAgent
log.Printf("[INFO] Instantiating Google Cloud Bigtable Client Factory...")
c.clientFactoryBigtable = &ClientFactoryBigtable{
UserAgent: userAgent,
TokenSource: tokenSource,
}
return nil return nil
} }

View File

@ -64,6 +64,7 @@ func Provider() terraform.ResourceProvider {
ResourcesMap: map[string]*schema.Resource{ ResourcesMap: map[string]*schema.Resource{
"google_bigquery_dataset": resourceBigQueryDataset(), "google_bigquery_dataset": resourceBigQueryDataset(),
"google_bigquery_table": resourceBigQueryTable(), "google_bigquery_table": resourceBigQueryTable(),
"google_bigtable_instance": resourceBigtableInstance(),
"google_compute_autoscaler": resourceComputeAutoscaler(), "google_compute_autoscaler": resourceComputeAutoscaler(),
"google_compute_address": resourceComputeAddress(), "google_compute_address": resourceComputeAddress(),
"google_compute_backend_bucket": resourceComputeBackendBucket(), "google_compute_backend_bucket": resourceComputeBackendBucket(),

View File

@ -0,0 +1,188 @@
package google
import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
"cloud.google.com/go/bigtable"
"golang.org/x/net/context"
)
func resourceBigtableInstance() *schema.Resource {
return &schema.Resource{
Create: resourceBigtableInstanceCreate,
Read: resourceBigtableInstanceRead,
Delete: resourceBigtableInstanceDestroy,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"display_name": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Computed: true,
},
"cluster_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"num_nodes": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
// 30 is the maximum number of nodes without a quota increase.
ValidateFunc: validation.IntBetween(3, 30),
},
"storage_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{"SSD", "HDD"}, false),
},
"zone": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"project": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
}
}
func resourceBigtableInstanceCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
ctx := context.Background()
project, err := getProject(d, config)
if err != nil {
return err
}
name := d.Get("name").(string)
displayName, ok := d.GetOk("display_name")
if !ok {
displayName = name
}
clusterId := d.Get("cluster_id").(string)
numNodes := int32(d.Get("num_nodes").(int))
zone := d.Get("zone").(string)
var storageType bigtable.StorageType
switch value := d.Get("storage_type"); value {
case "HDD":
storageType = bigtable.HDD
case "SSD":
storageType = bigtable.SSD
}
instanceConf := &bigtable.InstanceConf{
InstanceId: name,
DisplayName: displayName.(string),
ClusterId: clusterId,
NumNodes: numNodes,
StorageType: storageType,
Zone: zone,
}
c, err := config.clientFactoryBigtable.NewInstanceAdminClient(project)
if err != nil {
return fmt.Errorf("Error starting instance admin client. %s", err)
}
defer c.Close()
err = c.CreateInstance(ctx, instanceConf)
if err != nil {
return fmt.Errorf("Error creating instance. %s", err)
}
d.SetId(name)
return resourceBigtableInstanceRead(d, meta)
}
func resourceBigtableInstanceRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
ctx := context.Background()
project, err := getProject(d, config)
if err != nil {
return err
}
c, err := config.clientFactoryBigtable.NewInstanceAdminClient(project)
if err != nil {
return fmt.Errorf("Error starting instance admin client. %s", err)
}
defer c.Close()
name := d.Id()
instances, err := c.Instances(ctx)
if err != nil {
return fmt.Errorf("Error retrieving instances. %s", err)
}
var instanceInfo *bigtable.InstanceInfo
found := false
for _, i := range instances {
if i.Name == name {
instanceInfo = i
found = true
break
}
}
if !found {
return fmt.Errorf("Error retrieving instance. Could not find %s.", name)
}
d.Set("name", instanceInfo.Name)
d.Set("display_name", instanceInfo.DisplayName)
return nil
}
func resourceBigtableInstanceDestroy(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
ctx := context.Background()
project, err := getProject(d, config)
if err != nil {
return err
}
c, err := config.clientFactoryBigtable.NewInstanceAdminClient(project)
if err != nil {
return fmt.Errorf("Error starting instance admin client. %s", err)
}
defer c.Close()
name := d.Id()
err = c.DeleteInstance(ctx, name)
if err != nil {
return fmt.Errorf("Error deleting instance. %s", err)
}
d.SetId("")
return nil
}

View File

@ -0,0 +1,118 @@
package google
import (
"fmt"
"testing"
"context"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccBigtableInstance_basic(t *testing.T) {
instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckBigtableInstanceDestroy,
Steps: []resource.TestStep{
{
Config: testAccBigtableInstance(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccBigtableInstanceExists(
"google_bigtable_instance.instance"),
),
},
},
})
}
func testAccCheckBigtableInstanceDestroy(s *terraform.State) error {
var ctx = context.Background()
for _, rs := range s.RootModule().Resources {
if rs.Type != "google_bigtable_instance" {
continue
}
config := testAccProvider.Meta().(*Config)
c, err := config.clientFactoryBigtable.NewInstanceAdminClient(config.Project)
if err != nil {
return fmt.Errorf("Error starting instance admin client. %s", err)
}
instances, err := c.Instances(ctx)
if err != nil {
return fmt.Errorf("Error retrieving instances. %s", err)
}
found := false
for _, i := range instances {
if i.Name == rs.Primary.Attributes["name"] {
found = true
break
}
}
if found {
return fmt.Errorf("Instance %s still exists.", rs.Primary.Attributes["name"])
}
c.Close()
}
return nil
}
func testAccBigtableInstanceExists(n string) resource.TestCheckFunc {
var ctx = context.Background()
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
config := testAccProvider.Meta().(*Config)
c, err := config.clientFactoryBigtable.NewInstanceAdminClient(config.Project)
if err != nil {
return fmt.Errorf("Error starting instance admin client. %s", err)
}
instances, err := c.Instances(ctx)
if err != nil {
return fmt.Errorf("Error retrieving instances. %s", err)
}
found := false
for _, i := range instances {
if i.Name == rs.Primary.Attributes["name"] {
found = true
break
}
}
if !found {
return fmt.Errorf("Error retrieving instance %s.", rs.Primary.Attributes["name"])
}
c.Close()
return nil
}
}
func testAccBigtableInstance(instanceName string) string {
return fmt.Sprintf(`
resource "google_bigtable_instance" "instance" {
name = "%s"
cluster_id = "%s"
zone = "us-central1-b"
num_nodes = 3
storage_type = "HDD"
}
`, instanceName, instanceName)
}

View File

@ -0,0 +1,49 @@
---
layout: "google"
page_title: "Google: google_bigtable_instance"
sidebar_current: "docs-google-bigtable_instance"
description: |-
Creates a Google Bigtable instance.
---
# google_bigtable_instance
Creates a Google Bigtable instance. For more information see
[the official documentation](https://cloud.google.com/bigtable/) and
[API](https://cloud.google.com/bigtable/docs/go/reference).
## Example Usage
```hcl
resource "google_bigtable_instance" "instance" {
name = "tf-instance"
cluster_id = "tf-instance-cluster"
zone = "us-central1-b"
num_nodes = 3
storage_type = "HDD"
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) The name of the Bigtable instance.
* `cluster_id` - (Required) The name of the Bigtable instance's cluster.
* `zone` - (Required) The zone to create the Bigtable instance in. Note: Many zones do not support Bigtable instances.
* `num_nodes` - (Required) The number of nodes in your Bigtable instance. Minimum of 3.
* `storage_type` - (Required) The storage type to use. One of `"SSD"` or `"HDD"`.
* `project` - (Optional) The project in which the resource belongs. If it
is not provided, the provider project is used.
* `display_name` - (Optional) The human-readable display name of the Bigtable instance. Defaults to the instance `name`.
## Attributes Reference
Only the arguments listed above are exposed as attributes.