From d0d116fa3e22cbb7671c251bf3d6d1dfa10757e2 Mon Sep 17 00:00:00 2001 From: Riley Karson Date: Mon, 26 Jun 2017 15:40:01 -0700 Subject: [PATCH] Add support for Bigtable table. --- google/provider.go | 1 + google/resource_bigtable_table.go | 134 ++++++++++++++++++++ google/resource_bigtable_table_test.go | 127 +++++++++++++++++++ website/docs/r/bigtable_table.html.markdown | 49 +++++++ 4 files changed, 311 insertions(+) create mode 100644 google/resource_bigtable_table.go create mode 100644 google/resource_bigtable_table_test.go create mode 100644 website/docs/r/bigtable_table.html.markdown diff --git a/google/provider.go b/google/provider.go index 806aa2fb..6cd1f975 100644 --- a/google/provider.go +++ b/google/provider.go @@ -65,6 +65,7 @@ func Provider() terraform.ResourceProvider { "google_bigquery_dataset": resourceBigQueryDataset(), "google_bigquery_table": resourceBigQueryTable(), "google_bigtable_instance": resourceBigtableInstance(), + "google_bigtable_table": resourceBigtableTable(), "google_compute_autoscaler": resourceComputeAutoscaler(), "google_compute_address": resourceComputeAddress(), "google_compute_backend_bucket": resourceComputeBackendBucket(), diff --git a/google/resource_bigtable_table.go b/google/resource_bigtable_table.go new file mode 100644 index 00000000..b662aa61 --- /dev/null +++ b/google/resource_bigtable_table.go @@ -0,0 +1,134 @@ +package google + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + + "golang.org/x/net/context" +) + +func resourceBigtableTable() *schema.Resource { + return &schema.Resource{ + Create: resourceBigtableTableCreate, + Read: resourceBigtableTableRead, + Delete: resourceBigtableTableDestroy, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "instance_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "split_keys": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "project": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + } +} + +func resourceBigtableTableCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + ctx := context.Background() + + project, err := getProject(d, config) + if err != nil { + return err + } + + instanceName := d.Get("instance_name").(string) + c, err := config.bigtableClientFactory.NewAdminClient(project, instanceName) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + + defer c.Close() + + name := d.Get("name").(string) + if v, ok := d.GetOk("split_keys"); ok { + splitKeys := convertSchemaArrayToStringArray(v.([]interface{})) + err = c.CreatePresplitTable(ctx, name, splitKeys) + if err != nil { + return fmt.Errorf("Error creating presplit table. %s", err) + } + } else { + err = c.CreateTable(ctx, name) + if err != nil { + return fmt.Errorf("Error creating table. %s", err) + } + } + + d.SetId(name) + + return resourceBigtableTableRead(d, meta) +} + +func resourceBigtableTableRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + ctx := context.Background() + + project, err := getProject(d, config) + if err != nil { + return err + } + + instanceName := d.Get("instance_name").(string) + c, err := config.bigtableClientFactory.NewAdminClient(project, instanceName) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + + defer c.Close() + + name := d.Id() + _, err = c.TableInfo(ctx, name) + if err != nil { + return fmt.Errorf("Error retrieving table. Could not find %s in %s.", name, instanceName) + } + + return nil +} + +func resourceBigtableTableDestroy(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + ctx := context.Background() + + project, err := getProject(d, config) + if err != nil { + return err + } + + instanceName := d.Get("instance_name").(string) + c, err := config.bigtableClientFactory.NewAdminClient(project, instanceName) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + + defer c.Close() + + name := d.Get("name").(string) + err = c.DeleteTable(ctx, name) + if err != nil { + return fmt.Errorf("Error deleting instance. %s", err) + } + + d.SetId("") + + return nil +} diff --git a/google/resource_bigtable_table_test.go b/google/resource_bigtable_table_test.go new file mode 100644 index 00000000..216073e8 --- /dev/null +++ b/google/resource_bigtable_table_test.go @@ -0,0 +1,127 @@ +package google + +import ( + "context" + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccBigtableTable_basic(t *testing.T) { + instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + tableName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckBigtableTableDestroy, + Steps: []resource.TestStep{ + { + Config: testAccBigtableTable(instanceName, tableName), + Check: resource.ComposeTestCheckFunc( + testAccBigtableTableExists( + "google_bigtable_table.table"), + ), + }, + }, + }) +} + +func testAccCheckBigtableTableDestroy(s *terraform.State) error { + var ctx = context.Background() + for _, rs := range s.RootModule().Resources { + if rs.Type != "google_bigtable_table" { + continue + } + + config := testAccProvider.Meta().(*Config) + c, err := config.bigtableClientFactory.NewAdminClient(config.Project, rs.Primary.Attributes["instance_name"]) + if err != nil { + // The instance is already gone + return nil + } + + tables, err := c.Tables(ctx) + if err != nil { + // The instance is already gone. + return nil + } + + found := false + for _, t := range tables { + if t == rs.Primary.Attributes["name"] { + found = true + break + } + } + + if found { + return fmt.Errorf("Table still present. Found %s in %s.", rs.Primary.Attributes["name"], rs.Primary.Attributes["instance_name"]) + } + + c.Close() + } + + return nil +} + +func testAccBigtableTableExists(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.bigtableClientFactory.NewAdminClient(config.Project, rs.Primary.Attributes["instance_name"]) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + + tables, err := c.Tables(ctx) + if err != nil { + return fmt.Errorf("Error starting admin client. %s", err) + } + + found := false + for _, t := range tables { + if t == rs.Primary.Attributes["name"] { + found = true + break + } + } + + if !found { + return fmt.Errorf("Error retrieving table. Could not find %s in %s.", rs.Primary.Attributes["name"], rs.Primary.Attributes["instance_name"]) + } + + c.Close() + + return nil + } +} + +func testAccBigtableTable(instanceName, tableName 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" +} + +resource "google_bigtable_table" "table" { + name = "%s" + instance_name = "${google_bigtable_instance.instance.name}" + split_keys = ["a", "b", "c"] +} +`, instanceName, instanceName, tableName) +} diff --git a/website/docs/r/bigtable_table.html.markdown b/website/docs/r/bigtable_table.html.markdown new file mode 100644 index 00000000..b37b5fb0 --- /dev/null +++ b/website/docs/r/bigtable_table.html.markdown @@ -0,0 +1,49 @@ +--- +layout: "google" +page_title: "Google: google_bigtable_table" +sidebar_current: "docs-google-bigtable_table" +description: |- + Creates a Google Bigtable table inside an instance. +--- + +# google_bigtable_table + +Creates a Google Bigtable table inside an 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" +} + +resource "google_bigtable_table" "table" { + name = "tf-table" + instance_name = "${google_bigtable_instance.instance.name}" + split_keys = ["a", "b", "c"] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the table. + +* `instance_name` - (Required) The name of the Bigtable instance. + +* `split_keys` - (Optional) A list of predefined keys to split the table on. + +* `project` - (Optional) The project in which the resource belongs. If it + is not provided, the provider project is used. + +## Attributes Reference + +Only the arguments listed above are exposed as attributes.