Skip to content

Commit

Permalink
Bigtable: Add support for abandoning GC policy (#6817) (#13066)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <magic-modules@google.com>

Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician committed Nov 17, 2022
1 parent 9a47b61 commit e61e869
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/6817.txt
@@ -0,0 +1,3 @@
```release-note:enhancement
bigtable: added support for abandoning GC policy
```
17 changes: 17 additions & 0 deletions google/resource_bigtable_gc_policy.go
Expand Up @@ -164,6 +164,15 @@ func resourceBigtableGCPolicy() *schema.Resource {
ForceNew: true,
Description: `The ID of the project in which the resource belongs. If it is not provided, the provider project is used.`,
},

"deletion_policy": {
Type: schema.TypeString,
Optional: true,
Description: `The deletion policy for the GC policy. Setting ABANDON allows the resource
to be abandoned rather than deleted. This is useful for GC policy as it cannot be deleted
in a replicated instance. Possible values are: "ABANDON".`,
ValidateFunc: validation.StringInSlice([]string{"ABANDON", ""}, false),
},
},
UseJSONNumber: true,
}
Expand Down Expand Up @@ -367,6 +376,14 @@ func gcPolicyToGCRuleString(gc bigtable.GCPolicy, topLevel bool) (map[string]int

func resourceBigtableGCPolicyDestroy(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)

if deletionPolicy := d.Get("deletion_policy"); deletionPolicy == "ABANDON" {
// Allows for the GC policy to be abandoned without deletion to avoid possible
// deletion failure in a replicated instance.
log.Printf("[WARN] The GC policy is abandoned")
return nil
}

userAgent, err := generateUserAgentString(d, config.userAgent)
if err != nil {
return err
Expand Down
135 changes: 135 additions & 0 deletions google/resource_bigtable_gc_policy_test.go
Expand Up @@ -37,6 +37,39 @@ func TestAccBigtableGCPolicy_basic(t *testing.T) {
})
}

func TestAccBigtableGCPolicy_abandoned(t *testing.T) {
// bigtable instance does not use the shared HTTP client, this test creates an instance
skipIfVcr(t)
t.Parallel()

instanceName := fmt.Sprintf("tf-test-%s", randString(t, 10))
tableName := fmt.Sprintf("tf-test-%s", randString(t, 10))
familyName := fmt.Sprintf("tf-test-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckBigtableGCPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccBigtableGCPolicyToBeAbandoned(instanceName, tableName, familyName),
Check: resource.ComposeTestCheckFunc(
testAccBigtableGCPolicyExists(
t, "google_bigtable_gc_policy.policy", false),
),
},
// Verify that the remote infrastructure GC policy still exists after it is removed in the config.
{
Config: testAccBigtableGCPolicyNoPolicy(instanceName, tableName, familyName),
Check: resource.ComposeTestCheckFunc(
testAccBigtableRemoteGCPolicyExists(
t, "google_bigtable_table.table"),
),
},
},
})
}

func TestAccBigtableGCPolicy_swapOffDeprecated(t *testing.T) {
// bigtable instance does not use the shared HTTP client, this test creates an instance
skipIfVcr(t)
Expand Down Expand Up @@ -522,6 +555,46 @@ func testAccBigtableGCPolicyExists(t *testing.T, n string, compareGcRules bool)
}
}

func testAccBigtableRemoteGCPolicyExists(t *testing.T, table_name_space string) resource.TestCheckFunc {
var ctx = context.Background()
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[table_name_space]
if !ok {
return fmt.Errorf("Table not found: %s", table_name_space)
}

config := googleProviderConfig(t)
c, err := config.BigTableClientFactory(config.userAgent).NewAdminClient(config.Project, rs.Primary.Attributes["instance_name"])
if err != nil {
return fmt.Errorf("Error starting admin client. %s", err)
}

defer c.Close()

table, err := c.TableInfo(ctx, rs.Primary.Attributes["name"])
if err != nil {
return fmt.Errorf("Error retrieving table. Could not find %s in %s.", rs.Primary.Attributes["name"], rs.Primary.Attributes["instance_name"])
}

// We expect a single local column family in the table.
family, ok := rs.Primary.Attributes["column_family.0.family"]
if !ok {
return fmt.Errorf("Error retrieving the local family")
}

for _, familyInfo := range table.FamilyInfos {
if familyInfo.Name == family {
if familyInfo.GCPolicy == "" {
return fmt.Errorf("The remote GC policy is missing in family %s", family)
}
return nil
}
}

return fmt.Errorf("Error retrieving GC policy. Could not find the column family")
}
}

func testAccBigtableCanWriteData(t *testing.T, n string, numberOfRows int) resource.TestCheckFunc {
var ctx = context.Background()
return func(s *terraform.State) error {
Expand Down Expand Up @@ -668,6 +741,68 @@ resource "google_bigtable_gc_policy" "policy" {
`, instanceName, instanceName, tableName, family, family)
}

func testAccBigtableGCPolicyToBeAbandoned(instanceName, tableName, family string) string {
return fmt.Sprintf(`
resource "google_bigtable_instance" "instance" {
name = "%s"
cluster {
cluster_id = "%s"
zone = "us-central1-b"
}
instance_type = "DEVELOPMENT"
deletion_protection = false
}
resource "google_bigtable_table" "table" {
name = "%s"
instance_name = google_bigtable_instance.instance.id
column_family {
family = "%s"
}
}
resource "google_bigtable_gc_policy" "policy" {
instance_name = google_bigtable_instance.instance.id
table = google_bigtable_table.table.name
column_family = "%s"
max_age {
duration = "72h"
}
deletion_policy = "ABANDON"
}
`, instanceName, instanceName, tableName, family, family)
}

func testAccBigtableGCPolicyNoPolicy(instanceName, tableName, family string) string {
return fmt.Sprintf(`
resource "google_bigtable_instance" "instance" {
name = "%s"
cluster {
cluster_id = "%s"
zone = "us-central1-b"
}
instance_type = "DEVELOPMENT"
deletion_protection = false
}
resource "google_bigtable_table" "table" {
name = "%s"
instance_name = google_bigtable_instance.instance.id
column_family {
family = "%s"
}
}
`, instanceName, instanceName, tableName, family)
}

func testAccBigtableGCPolicyUnion(instanceName, tableName, family string) string {
return fmt.Sprintf(`
resource "google_bigtable_instance" "instance" {
Expand Down
8 changes: 8 additions & 0 deletions website/docs/r/bigtable_gc_policy.html.markdown
Expand Up @@ -45,6 +45,7 @@ resource "google_bigtable_gc_policy" "policy" {
instance_name = google_bigtable_instance.instance.name
table = google_bigtable_table.table.name
column_family = "name"
deletion_policy = "ABANDON"
max_age {
duration = "168h"
Expand All @@ -59,6 +60,7 @@ resource "google_bigtable_gc_policy" "policy" {
instance_name = google_bigtable_instance.instance.name
table = google_bigtable_table.table.name
column_family = "name"
deletion_policy = "ABANDON"
mode = "UNION"
Expand Down Expand Up @@ -101,6 +103,7 @@ resource "google_bigtable_gc_policy" "policy" {
instance_name = google_bigtable_instance.instance.id
table = google_bigtable_table.table.name
column_family = "cf1"
deletion_policy = "ABANDON"
gc_rules = <<EOF
{
Expand Down Expand Up @@ -151,6 +154,11 @@ The following arguments are supported:

* `gc_rules` - (Optional) Serialized JSON object to represent a more complex GC policy. Conflicts with `mode`, `max_age` and `max_version`. Conflicts with `mode`, `max_age` and `max_version`.

* `deletion_policy` - (Optional) The deletion policy for the GC policy.
Setting ABANDON allows the resource to be abandoned rather than deleted. This is useful for GC policy as it cannot be deleted in a replicated instance.

Possible values are: `ABANDON`.

-----

`max_age` supports the following arguments:
Expand Down

0 comments on commit e61e869

Please sign in to comment.