Skip to content

Commit 0334d71

Browse files
add deletion_protection field for bigtable instance (#3450) (#2061)
Signed-off-by: Modular Magician <[email protected]>
1 parent 2fe7047 commit 0334d71

11 files changed

+202
-13
lines changed

.changelog/3450.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
```release-note:enhancement
2+
* bigtable: added `deletion_protection` field to `google_bigtable_instance` to make deleting them require an explicit intent.
3+
```
4+
```release-note:note
5+
* `google_bigtable_instance` resources now cannot be destroyed unless `deletion_protection = false` is set in state for the resource.
6+
```

google-beta/resource_bigtable_app_profile_generated_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ func TestAccBigtableAppProfile_bigtableAppProfileMulticlusterExample(t *testing.
2727
t.Parallel()
2828

2929
context := map[string]interface{}{
30-
"random_suffix": randString(t, 10),
30+
"deletion_protection": false,
31+
"random_suffix": randString(t, 10),
3132
}
3233

3334
vcrTest(t, resource.TestCase{
@@ -58,6 +59,8 @@ resource "google_bigtable_instance" "instance" {
5859
num_nodes = 3
5960
storage_type = "HDD"
6061
}
62+
63+
deletion_protection = "%{deletion_protection}"
6164
}
6265
6366
resource "google_bigtable_app_profile" "ap" {
@@ -74,7 +77,8 @@ func TestAccBigtableAppProfile_bigtableAppProfileSingleclusterExample(t *testing
7477
t.Parallel()
7578

7679
context := map[string]interface{}{
77-
"random_suffix": randString(t, 10),
80+
"deletion_protection": false,
81+
"random_suffix": randString(t, 10),
7882
}
7983

8084
vcrTest(t, resource.TestCase{
@@ -105,6 +109,8 @@ resource "google_bigtable_instance" "instance" {
105109
num_nodes = 3
106110
storage_type = "HDD"
107111
}
112+
113+
deletion_protection = "%{deletion_protection}"
108114
}
109115
110116
resource "google_bigtable_app_profile" "ap" {

google-beta/resource_bigtable_app_profile_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ resource "google_bigtable_instance" "instance" {
4949
num_nodes = 3
5050
storage_type = "HDD"
5151
}
52+
53+
deletion_protection = false
5254
}
5355
5456
resource "google_bigtable_app_profile" "ap" {
@@ -71,6 +73,8 @@ resource "google_bigtable_instance" "instance" {
7173
num_nodes = 3
7274
storage_type = "HDD"
7375
}
76+
77+
deletion_protection = false
7478
}
7579
7680
resource "google_bigtable_app_profile" "ap" {

google-beta/resource_bigtable_gc_policy_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ resource "google_bigtable_instance" "instance" {
136136
}
137137
138138
instance_type = "DEVELOPMENT"
139+
deletion_protection = false
139140
}
140141
141142
resource "google_bigtable_table" "table" {
@@ -170,6 +171,7 @@ resource "google_bigtable_instance" "instance" {
170171
}
171172
172173
instance_type = "DEVELOPMENT"
174+
deletion_protection = false
173175
}
174176
175177
resource "google_bigtable_table" "table" {

google-beta/resource_bigtable_instance.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ func resourceBigtableInstance() *schema.Resource {
2727
resourceBigtableInstanceClusterReorderTypeList,
2828
),
2929

30+
SchemaVersion: 1,
31+
StateUpgraders: []schema.StateUpgrader{
32+
{
33+
Type: resourceBigtableInstanceResourceV0().CoreConfigSchema().ImpliedType(),
34+
Upgrade: resourceBigtableInstanceUpgradeV0,
35+
Version: 0,
36+
},
37+
},
38+
3039
// ----------------------------------------------------------------------
3140
// IMPORTANT: Do not add any additional ForceNew fields to this resource.
3241
// Destroying/recreating instances can lead to data loss for users.
@@ -82,6 +91,12 @@ func resourceBigtableInstance() *schema.Resource {
8291
ValidateFunc: validation.StringInSlice([]string{"DEVELOPMENT", "PRODUCTION"}, false),
8392
},
8493

94+
"deletion_protection": {
95+
Type: schema.TypeBool,
96+
Optional: true,
97+
Default: true,
98+
},
99+
85100
"project": {
86101
Type: schema.TypeString,
87102
Optional: true,
@@ -235,6 +250,9 @@ func resourceBigtableInstanceUpdate(d *schema.ResourceData, meta interface{}) er
235250
}
236251

237252
func resourceBigtableInstanceDestroy(d *schema.ResourceData, meta interface{}) error {
253+
if d.Get("deletion_protection").(bool) {
254+
return fmt.Errorf("cannot destroy instance without setting deletion_protection=false and running `terraform apply`")
255+
}
238256
config := meta.(*Config)
239257
ctx := context.Background()
240258

google-beta/resource_bigtable_instance_iam_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,5 +209,7 @@ resource "google_bigtable_instance" "instance" {
209209
zone = "us-central1-b"
210210
storage_type = "HDD"
211211
}
212+
213+
deletion_protection = false
212214
}
213215
`
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package google
2+
3+
import (
4+
"log"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
8+
)
9+
10+
func resourceBigtableInstanceResourceV0() *schema.Resource {
11+
return &schema.Resource{
12+
Schema: map[string]*schema.Schema{
13+
"name": {
14+
Type: schema.TypeString,
15+
Required: true,
16+
ForceNew: true,
17+
},
18+
19+
"cluster": {
20+
Type: schema.TypeList,
21+
Optional: true,
22+
Computed: true,
23+
Elem: &schema.Resource{
24+
Schema: map[string]*schema.Schema{
25+
"cluster_id": {
26+
Type: schema.TypeString,
27+
Required: true,
28+
},
29+
"zone": {
30+
Type: schema.TypeString,
31+
Required: true,
32+
},
33+
"num_nodes": {
34+
Type: schema.TypeInt,
35+
Optional: true,
36+
// DEVELOPMENT instances could get returned with either zero or one node,
37+
// so mark as computed.
38+
Computed: true,
39+
ValidateFunc: validation.IntAtLeast(1),
40+
},
41+
"storage_type": {
42+
Type: schema.TypeString,
43+
Optional: true,
44+
Default: "SSD",
45+
ValidateFunc: validation.StringInSlice([]string{"SSD", "HDD"}, false),
46+
},
47+
},
48+
},
49+
},
50+
"display_name": {
51+
Type: schema.TypeString,
52+
Optional: true,
53+
Computed: true,
54+
},
55+
56+
"instance_type": {
57+
Type: schema.TypeString,
58+
Optional: true,
59+
Default: "PRODUCTION",
60+
ValidateFunc: validation.StringInSlice([]string{"DEVELOPMENT", "PRODUCTION"}, false),
61+
},
62+
63+
"project": {
64+
Type: schema.TypeString,
65+
Optional: true,
66+
Computed: true,
67+
ForceNew: true,
68+
},
69+
},
70+
}
71+
}
72+
73+
func resourceBigtableInstanceUpgradeV0(rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) {
74+
log.Printf("[DEBUG] Attributes before migration: %#v", rawState)
75+
76+
rawState["deletion_protection"] = true
77+
78+
log.Printf("[DEBUG] Attributes after migration: %#v", rawState)
79+
return rawState, nil
80+
}

google-beta/resource_bigtable_instance_test.go

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestAccBigtableInstance_basic(t *testing.T) {
3131
ResourceName: "google_bigtable_instance.instance",
3232
ImportState: true,
3333
ImportStateVerify: true,
34-
ImportStateVerifyIgnore: []string{"instance_type"}, // we don't read instance type back
34+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
3535
},
3636
{
3737
Config: testAccBigtableInstance(instanceName, 4),
@@ -40,7 +40,7 @@ func TestAccBigtableInstance_basic(t *testing.T) {
4040
ResourceName: "google_bigtable_instance.instance",
4141
ImportState: true,
4242
ImportStateVerify: true,
43-
ImportStateVerifyIgnore: []string{"instance_type"}, // we don't read instance type back
43+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
4444
},
4545
},
4646
})
@@ -67,7 +67,7 @@ func TestAccBigtableInstance_cluster(t *testing.T) {
6767
ResourceName: "google_bigtable_instance.instance",
6868
ImportState: true,
6969
ImportStateVerify: true,
70-
ImportStateVerifyIgnore: []string{"instance_type"}, // we don't read instance type back
70+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
7171
},
7272
{
7373
Config: testAccBigtableInstance_clusterReordered(instanceName, 5),
@@ -76,7 +76,7 @@ func TestAccBigtableInstance_cluster(t *testing.T) {
7676
ResourceName: "google_bigtable_instance.instance",
7777
ImportState: true,
7878
ImportStateVerify: true,
79-
ImportStateVerifyIgnore: []string{"instance_type"}, // we don't read instance type back
79+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
8080
},
8181
{
8282
Config: testAccBigtableInstance_clusterModified(instanceName, 5),
@@ -85,7 +85,7 @@ func TestAccBigtableInstance_cluster(t *testing.T) {
8585
ResourceName: "google_bigtable_instance.instance",
8686
ImportState: true,
8787
ImportStateVerify: true,
88-
ImportStateVerifyIgnore: []string{"instance_type"}, // we don't read instance type back
88+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
8989
},
9090
{
9191
Config: testAccBigtableInstance_clusterReordered(instanceName, 5),
@@ -94,7 +94,7 @@ func TestAccBigtableInstance_cluster(t *testing.T) {
9494
ResourceName: "google_bigtable_instance.instance",
9595
ImportState: true,
9696
ImportStateVerify: true,
97-
ImportStateVerifyIgnore: []string{"instance_type"}, // we don't read instance type back
97+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
9898
},
9999
},
100100
})
@@ -117,7 +117,38 @@ func TestAccBigtableInstance_development(t *testing.T) {
117117
ResourceName: "google_bigtable_instance.instance",
118118
ImportState: true,
119119
ImportStateVerify: true,
120-
ImportStateVerifyIgnore: []string{"instance_type"}, // we don't read instance type back
120+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
121+
},
122+
},
123+
})
124+
}
125+
126+
func TestAccBigtableInstance_allowDestroy(t *testing.T) {
127+
t.Parallel()
128+
129+
instanceName := fmt.Sprintf("tf-test-%s", randString(t, 10))
130+
131+
vcrTest(t, resource.TestCase{
132+
PreCheck: func() { testAccPreCheck(t) },
133+
Providers: testAccProviders,
134+
CheckDestroy: testAccCheckBigtableInstanceDestroyProducer(t),
135+
Steps: []resource.TestStep{
136+
{
137+
Config: testAccBigtableInstance_noAllowDestroy(instanceName, 3),
138+
},
139+
{
140+
ResourceName: "google_bigtable_instance.instance",
141+
ImportState: true,
142+
ImportStateVerify: true,
143+
ImportStateVerifyIgnore: []string{"deletion_protection", "instance_type"}, // we don't read instance type back
144+
},
145+
{
146+
Config: testAccBigtableInstance_noAllowDestroy(instanceName, 3),
147+
Destroy: true,
148+
ExpectError: regexp.MustCompile("deletion_protection"),
149+
},
150+
{
151+
Config: testAccBigtableInstance(instanceName, 3),
121152
},
122153
},
123154
})
@@ -159,6 +190,8 @@ resource "google_bigtable_instance" "instance" {
159190
num_nodes = %d
160191
storage_type = "HDD"
161192
}
193+
194+
deletion_protection = false
162195
}
163196
`, instanceName, instanceName, numNodes)
164197
}
@@ -199,6 +232,8 @@ resource "google_bigtable_instance" "instance" {
199232
num_nodes = %d
200233
storage_type = "HDD"
201234
}
235+
236+
deletion_protection = false
202237
}
203238
`, instanceName, instanceName, numNodes, instanceName, numNodes, instanceName, numNodes, instanceName, numNodes)
204239
}
@@ -237,6 +272,8 @@ resource "google_bigtable_instance" "instance" {
237272
num_nodes = 3
238273
storage_type = "HDD"
239274
}
275+
276+
deletion_protection = false
240277
}
241278
`, instanceName, instanceName, instanceName, instanceName, instanceName, instanceName)
242279
}
@@ -269,6 +306,8 @@ resource "google_bigtable_instance" "instance" {
269306
num_nodes = %d
270307
storage_type = "HDD"
271308
}
309+
310+
deletion_protection = false
272311
}
273312
`, instanceName, instanceName, numNodes, instanceName, numNodes, instanceName, numNodes, instanceName, numNodes)
274313
}
@@ -295,6 +334,8 @@ resource "google_bigtable_instance" "instance" {
295334
num_nodes = %d
296335
storage_type = "HDD"
297336
}
337+
338+
deletion_protection = false
298339
}
299340
`, instanceName, instanceName, numNodes, instanceName, numNodes, instanceName, numNodes)
300341
}
@@ -308,6 +349,22 @@ resource "google_bigtable_instance" "instance" {
308349
zone = "us-central1-b"
309350
}
310351
instance_type = "DEVELOPMENT"
352+
353+
deletion_protection = false
311354
}
312355
`, instanceName, instanceName)
313356
}
357+
358+
func testAccBigtableInstance_noAllowDestroy(instanceName string, numNodes int) string {
359+
return fmt.Sprintf(`
360+
resource "google_bigtable_instance" "instance" {
361+
name = "%s"
362+
cluster {
363+
cluster_id = "%s"
364+
zone = "us-central1-b"
365+
num_nodes = %d
366+
storage_type = "HDD"
367+
}
368+
}
369+
`, instanceName, instanceName, numNodes)
370+
}

0 commit comments

Comments
 (0)