-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #177 from terraform-providers/bigtable-support
Add support for Google Cloud Bigtable.
- Loading branch information
Showing
14 changed files
with
765 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package google | ||
|
||
import ( | ||
"context" | ||
|
||
"cloud.google.com/go/bigtable" | ||
"golang.org/x/oauth2" | ||
"google.golang.org/api/option" | ||
) | ||
|
||
type BigtableClientFactory struct { | ||
UserAgent string | ||
TokenSource oauth2.TokenSource | ||
} | ||
|
||
func (s BigtableClientFactory) NewInstanceAdminClient(project string) (*bigtable.InstanceAdminClient, error) { | ||
return bigtable.NewInstanceAdminClient(context.Background(), project, option.WithTokenSource(s.TokenSource), option.WithUserAgent(s.UserAgent)) | ||
} | ||
|
||
func (s BigtableClientFactory) NewAdminClient(project, instance string) (*bigtable.AdminClient, error) { | ||
return bigtable.NewAdminClient(context.Background(), project, instance, option.WithTokenSource(s.TokenSource), option.WithUserAgent(s.UserAgent)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"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, | ||
}, | ||
|
||
"cluster_id": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"zone": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
|
||
"display_name": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
Computed: true, | ||
}, | ||
|
||
"num_nodes": { | ||
Type: schema.TypeInt, | ||
Optional: true, | ||
ForceNew: true, | ||
Default: 3, | ||
ValidateFunc: IntAtLeast(3), | ||
}, | ||
|
||
"storage_type": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
Default: "SSD", | ||
ValidateFunc: validation.StringInSlice([]string{"SSD", "HDD"}, false), | ||
}, | ||
|
||
"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 | ||
} | ||
|
||
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: d.Get("cluster_id").(string), | ||
NumNodes: int32(d.Get("num_nodes").(int)), | ||
StorageType: storageType, | ||
Zone: d.Get("zone").(string), | ||
} | ||
|
||
c, err := config.bigtableClientFactory.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.bigtableClientFactory.NewInstanceAdminClient(project) | ||
if err != nil { | ||
return fmt.Errorf("Error starting instance admin client. %s", err) | ||
} | ||
|
||
defer c.Close() | ||
|
||
instance, err := c.InstanceInfo(ctx, d.Id()) | ||
if err != nil { | ||
log.Printf("[WARN] Removing %s because it's gone", d.Id()) | ||
d.SetId("") | ||
return fmt.Errorf("Error retrieving instance. Could not find %s. %s", d.Id(), err) | ||
} | ||
|
||
d.Set("name", instance.Name) | ||
d.Set("display_name", instance.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.bigtableClientFactory.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 | ||
} | ||
|
||
// IntAtLeast returns a SchemaValidateFunc which tests if the provided value | ||
// is of type int and is above min (inclusive) | ||
func IntAtLeast(min int) schema.SchemaValidateFunc { | ||
return func(i interface{}, k string) (s []string, es []error) { | ||
v, ok := i.(int) | ||
if !ok { | ||
es = append(es, fmt.Errorf("expected type of %s to be int", k)) | ||
return | ||
} | ||
|
||
if v < min { | ||
es = append(es, fmt.Errorf("expected %s to be at least %d, got %d", k, min, v)) | ||
return | ||
} | ||
|
||
return | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package google | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"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.bigtableClientFactory.NewInstanceAdminClient(config.Project) | ||
if err != nil { | ||
return fmt.Errorf("Error starting instance admin client. %s", err) | ||
} | ||
|
||
_, err = c.InstanceInfo(ctx, rs.Primary.Attributes["name"]) | ||
if err == nil { | ||
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.bigtableClientFactory.NewInstanceAdminClient(config.Project) | ||
if err != nil { | ||
return fmt.Errorf("Error starting instance admin client. %s", err) | ||
} | ||
|
||
_, err = c.InstanceInfo(ctx, rs.Primary.Attributes["name"]) | ||
if err != nil { | ||
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) | ||
} |
Oops, something went wrong.