Add deletion protection to resource_compute_instance (#1205)

This commit is contained in:
Nick Jacques 2018-03-16 13:57:42 -05:00 committed by Nathan McKinley
parent ea0b05d287
commit 46a3d2fd47
3 changed files with 169 additions and 13 deletions

View File

@ -552,6 +552,12 @@ func resourceComputeInstance() *schema.Resource {
Optional: true,
},
"deletion_protection": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
"label_fingerprint": &schema.Schema{
Type: schema.TypeString,
Computed: true,
@ -717,19 +723,20 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err
// Create the instance information
instance := &computeBeta.Instance{
CanIpForward: d.Get("can_ip_forward").(bool),
Description: d.Get("description").(string),
Disks: disks,
MachineType: machineType.SelfLink,
Metadata: metadata,
Name: d.Get("name").(string),
NetworkInterfaces: networkInterfaces,
Tags: resourceInstanceTags(d),
Labels: expandLabels(d),
ServiceAccounts: expandServiceAccounts(d.Get("service_account").([]interface{})),
GuestAccelerators: accels,
MinCpuPlatform: d.Get("min_cpu_platform").(string),
Scheduling: scheduling,
CanIpForward: d.Get("can_ip_forward").(bool),
Description: d.Get("description").(string),
Disks: disks,
MachineType: machineType.SelfLink,
Metadata: metadata,
Name: d.Get("name").(string),
NetworkInterfaces: networkInterfaces,
Tags: resourceInstanceTags(d),
Labels: expandLabels(d),
ServiceAccounts: expandServiceAccounts(d.Get("service_account").([]interface{})),
GuestAccelerators: accels,
MinCpuPlatform: d.Get("min_cpu_platform").(string),
Scheduling: scheduling,
DeletionProtection: d.Get("deletion_protection").(bool),
}
log.Printf("[INFO] Requesting instance creation")
@ -898,6 +905,7 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error
d.Set("guest_accelerator", flattenGuestAccelerators(instance.GuestAccelerators))
d.Set("cpu_platform", instance.CpuPlatform)
d.Set("min_cpu_platform", instance.MinCpuPlatform)
d.Set("deletion_protection", instance.DeletionProtection)
d.Set("self_link", ConvertSelfLinkToV1(instance.SelfLink))
d.Set("instance_id", fmt.Sprintf("%d", instance.Id))
d.Set("project", project)
@ -1268,6 +1276,22 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err
scopesChange = !oScopes.Equal(nScopes)
}
if d.HasChange("deletion_protection") {
nDeletionProtection := d.Get("deletion_protection").(bool)
op, err := config.clientCompute.Instances.SetDeletionProtection(project, zone, d.Id()).DeletionProtection(nDeletionProtection).Do()
if err != nil {
return fmt.Errorf("Error updating deletion protection flag: %s", err)
}
opErr := computeOperationWaitTime(config.clientCompute, op, project, "deletion protection to update", int(d.Timeout(schema.TimeoutUpdate).Minutes()))
if opErr != nil {
return opErr
}
d.SetPartial("deletion_protection")
}
// Attributes which can only be changed if the instance is stopped
if scopesChange || d.HasChange("service_account.0.email") || d.HasChange("machine_type") || d.HasChange("min_cpu_platform") {
if !d.Get("allow_stopping_for_update").(bool) {

View File

@ -35,6 +35,10 @@ func TestAccComputeInstance_basic1(t *testing.T) {
testAccCheckComputeInstanceMetadata(&instance, "foo", "bar"),
testAccCheckComputeInstanceMetadata(&instance, "baz", "qux"),
testAccCheckComputeInstanceDisk(&instance, instanceName, true, true),
// by default, DeletionProtection is implicitly false. This should be false on any
// instance resource without an explicit deletion_protection = true declaration.
// Other tests check explicit true/false configs: TestAccComputeInstance_deletionProtectionExplicit[True | False]
testAccCheckComputeInstanceHasConfiguredDeletionProtection(&instance, false),
),
},
resource.TestStep{
@ -951,6 +955,67 @@ func TestAccComputeInstance_minCpuPlatform(t *testing.T) {
})
}
func TestAccComputeInstance_deletionProtectionExplicitFalse(t *testing.T) {
t.Parallel()
var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeInstance_basic_deletionProtectionFalse(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceHasConfiguredDeletionProtection(&instance, false),
),
},
},
})
}
func TestAccComputeInstance_deletionProtectionExplicitTrueAndUpdateFalse(t *testing.T) {
t.Parallel()
var instance compute.Instance
var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeInstanceDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeInstance_basic_deletionProtectionTrue(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceHasConfiguredDeletionProtection(&instance, true),
),
},
resource.TestStep{
ResourceName: "google_compute_instance.foobar",
ImportState: true,
ImportStateId: fmt.Sprintf("%s/%s/%s", getTestProjectFromEnv(), "us-central1-a", instanceName),
ImportStateVerifyIgnore: []string{"create_timeout"},
},
// Update deletion_protection to false, otherwise the test harness can't delete the instance
resource.TestStep{
Config: testAccComputeInstance_basic_deletionProtectionFalse(instanceName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeInstanceExists(
"google_compute_instance.foobar", &instance),
testAccCheckComputeInstanceHasConfiguredDeletionProtection(&instance, false),
),
},
},
})
}
func TestAccComputeInstance_primaryAliasIpRange(t *testing.T) {
t.Parallel()
@ -1466,6 +1531,16 @@ func testAccCheckComputeInstanceHasAssignedIP(s *terraform.State) error {
return nil
}
func testAccCheckComputeInstanceHasConfiguredDeletionProtection(instance *compute.Instance, configuredDeletionProtection bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
if instance.DeletionProtection != configuredDeletionProtection {
return fmt.Errorf("Wrong deletion protection flag: expected %t, got %t", configuredDeletionProtection, instance.DeletionProtection)
}
return nil
}
}
func testAccComputeInstance_basic(instance string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foobar" {
@ -1474,6 +1549,7 @@ resource "google_compute_instance" "foobar" {
zone = "us-central1-a"
can_ip_forward = false
tags = ["foo", "bar"]
//deletion_protection = false is implicit in this config due to default value
boot_disk {
initialize_params{
@ -1609,6 +1685,60 @@ resource "google_compute_instance" "foobar" {
`, instance)
}
func testAccComputeInstance_basic_deletionProtectionFalse(instance string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
can_ip_forward = false
tags = ["foo", "bar"]
deletion_protection = false
boot_disk {
initialize_params{
image = "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20160803"
}
}
network_interface {
network = "default"
}
metadata {
foo = "bar"
}
}
`, instance)
}
func testAccComputeInstance_basic_deletionProtectionTrue(instance string) string {
return fmt.Sprintf(`
resource "google_compute_instance" "foobar" {
name = "%s"
machine_type = "n1-standard-1"
zone = "us-central1-a"
can_ip_forward = false
tags = ["foo", "bar"]
deletion_protection = true
boot_disk {
initialize_params{
image = "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-8-jessie-v20160803"
}
}
network_interface {
network = "default"
}
metadata {
foo = "bar"
}
}
`, instance)
}
// Update zone to ForceNew, and change metadata k/v entirely
// Generates diff mismatch
func testAccComputeInstance_forceNewAndChangeMetadata(instance string) string {

View File

@ -90,6 +90,8 @@ The following arguments are supported:
* `description` - (Optional) A brief description of this resource.
* `deletion_protection` - (Optional) Enable deletion protection on this instance. Defaults to false.
* `guest_accelerator` - (Optional) List of the type and count of accelerator cards attached to the instance. Structure documented below.
* `labels` - (Optional) A set of key/value label pairs to assign to the instance.