From ebc966cd0ba4443922822310b7c495bf32a8aab3 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 11:19:44 +0200 Subject: [PATCH 01/16] provider: adding a new feature flag for `force_delete` within the `virtual_machine` block --- azurerm/internal/features/defaults.go | 1 + azurerm/internal/features/user_flags.go | 1 + azurerm/internal/provider/features.go | 3 ++ azurerm/internal/provider/features_test.go | 59 ++++++++++++++++++++-- website/docs/index.html.markdown | 4 ++ 5 files changed, 65 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/features/defaults.go b/azurerm/internal/features/defaults.go index 7a54dadb2f7f..50efe3a2f6b6 100644 --- a/azurerm/internal/features/defaults.go +++ b/azurerm/internal/features/defaults.go @@ -19,6 +19,7 @@ func Default() UserFeatures { VirtualMachine: VirtualMachineFeatures{ DeleteOSDiskOnDeletion: true, GracefulShutdown: false, + ForceDelete: false, }, VirtualMachineScaleSet: VirtualMachineScaleSetFeatures{ RollInstancesWhenRequired: true, diff --git a/azurerm/internal/features/user_flags.go b/azurerm/internal/features/user_flags.go index 72157d354d99..638386a7259c 100644 --- a/azurerm/internal/features/user_flags.go +++ b/azurerm/internal/features/user_flags.go @@ -12,6 +12,7 @@ type UserFeatures struct { type VirtualMachineFeatures struct { DeleteOSDiskOnDeletion bool GracefulShutdown bool + ForceDelete bool } type VirtualMachineScaleSetFeatures struct { diff --git a/azurerm/internal/provider/features.go b/azurerm/internal/provider/features.go index ee157a992a5f..2e44b34a67cd 100644 --- a/azurerm/internal/provider/features.go +++ b/azurerm/internal/provider/features.go @@ -187,6 +187,9 @@ func expandFeatures(input []interface{}) features.UserFeatures { if v, ok := virtualMachinesRaw["graceful_shutdown"]; ok { features.VirtualMachine.GracefulShutdown = v.(bool) } + if v, ok := virtualMachinesRaw["force_delete"]; ok { + features.VirtualMachine.ForceDelete = v.(bool) + } } } diff --git a/azurerm/internal/provider/features_test.go b/azurerm/internal/provider/features_test.go index 86a35d915089..e0f36f1a257f 100644 --- a/azurerm/internal/provider/features_test.go +++ b/azurerm/internal/provider/features_test.go @@ -30,6 +30,8 @@ func TestExpandFeatures(t *testing.T) { }, VirtualMachine: features.VirtualMachineFeatures{ DeleteOSDiskOnDeletion: true, + GracefulShutdown: false, + ForceDelete: false, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ RollInstancesWhenRequired: true, @@ -68,6 +70,7 @@ func TestExpandFeatures(t *testing.T) { map[string]interface{}{ "delete_os_disk_on_deletion": true, "graceful_shutdown": true, + "force_delete": true, }, }, "virtual_machine_scale_set": []interface{}{ @@ -94,6 +97,7 @@ func TestExpandFeatures(t *testing.T) { VirtualMachine: features.VirtualMachineFeatures{ DeleteOSDiskOnDeletion: true, GracefulShutdown: true, + ForceDelete: true, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ RollInstancesWhenRequired: true, @@ -108,6 +112,7 @@ func TestExpandFeatures(t *testing.T) { map[string]interface{}{ "delete_os_disk_on_deletion": false, "graceful_shutdown": false, + "force_delete": false, }, }, "network_locking": []interface{}{ @@ -155,6 +160,7 @@ func TestExpandFeatures(t *testing.T) { VirtualMachine: features.VirtualMachineFeatures{ DeleteOSDiskOnDeletion: false, GracefulShutdown: false, + ForceDelete: false, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ RollInstancesWhenRequired: false, @@ -390,17 +396,19 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { VirtualMachine: features.VirtualMachineFeatures{ DeleteOSDiskOnDeletion: true, GracefulShutdown: false, + ForceDelete: false, }, }, }, { - Name: "Delete OS Disk and Graceful Shutdown Enabled", + Name: "Delete OS Disk Enabled", Input: []interface{}{ map[string]interface{}{ "virtual_machine": []interface{}{ map[string]interface{}{ "delete_os_disk_on_deletion": true, - "graceful_shutdown": true, + "graceful_shutdown": false, + "force_delete": false, }, }, }, @@ -408,18 +416,62 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { Expected: features.UserFeatures{ VirtualMachine: features.VirtualMachineFeatures{ DeleteOSDiskOnDeletion: true, + GracefulShutdown: false, + ForceDelete: false, + }, + }, + }, + { + Name: "Graceful Shutdown Enabled", + Input: []interface{}{ + map[string]interface{}{ + "virtual_machine": []interface{}{ + map[string]interface{}{ + "delete_os_disk_on_deletion": false, + "graceful_shutdown": true, + "force_delete": false, + }, + }, + }, + }, + Expected: features.UserFeatures{ + VirtualMachine: features.VirtualMachineFeatures{ + DeleteOSDiskOnDeletion: false, GracefulShutdown: true, + ForceDelete: false, + }, + }, + }, + { + Name: "Force Delete Enabled", + Input: []interface{}{ + map[string]interface{}{ + "virtual_machine": []interface{}{ + map[string]interface{}{ + "delete_os_disk_on_deletion": false, + "graceful_shutdown": false, + "force_delete": true, + }, + }, + }, + }, + Expected: features.UserFeatures{ + VirtualMachine: features.VirtualMachineFeatures{ + DeleteOSDiskOnDeletion: false, + GracefulShutdown: false, + ForceDelete: true, }, }, }, { - Name: "Delete OS Disk and Graceful Shutdown Disabled", + Name: "All Disabled", Input: []interface{}{ map[string]interface{}{ "virtual_machine": []interface{}{ map[string]interface{}{ "delete_os_disk_on_deletion": false, "graceful_shutdown": false, + "force_delete": false, }, }, }, @@ -428,6 +480,7 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { VirtualMachine: features.VirtualMachineFeatures{ DeleteOSDiskOnDeletion: false, GracefulShutdown: false, + ForceDelete: false, }, }, }, diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index aec6babf74ff..bb29d15cbcd1 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -208,6 +208,10 @@ The `virtual_machine` block supports the following: ~> **Note:** When using a graceful shutdown, Azure gives the Virtual Machine a 5 minutes window in which to complete the shutdown process, at which point the machine will be force powered off - [more information can be found in this blog post](https://azure.microsoft.com/en-us/blog/linux-and-graceful-shutdowns-2/). +* `force_delete` - Should the `azurerm_linux_virtual_machine` and `azurerm_windows_virtual_machine` resources send a `Force Delete` flag when deleting the Virtual Machine? This can help to work around issues within the Azure Platform during deletion of a Virtual Machine. Defaults to `false`. + +~> **Note:** Support for Force Delete is in an opt-in Preview. + --- The `virtual_machine_scale_set` block supports the following: From f093278cbfc6a782cf0480db2109711ee9b11402 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 11:23:24 +0200 Subject: [PATCH 02/16] r/linux_virtual_machine: support for Force Delete --- .../compute/linux_virtual_machine_resource.go | 10 +++- ...nux_virtual_machine_resource_other_test.go | 57 +++++++++++++++++++ .../linux_virtual_machine_resource_test.go | 2 +- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource.go b/azurerm/internal/services/compute/linux_virtual_machine_resource.go index dcd31442f9e9..55b26d8631d9 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource.go @@ -1156,10 +1156,14 @@ func resourceLinuxVirtualMachineDelete(d *schema.ResourceData, meta interface{}) } log.Printf("[DEBUG] Deleting Linux Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) - // @tombuildsstuff: sending `nil` here omits this value from being sent - which matches - // the previous behaviour - we're only splitting this out so it's clear why - // TODO: support force deletion once it's out of Preview, if applicable + + // Force Delete is in an opt-in Preview and can only be specified (true/false) if the feature is enabled + // as such we default this to `nil` which matches the previous behaviour (where this isn't sent) and + // conditionally set this if required var forceDeletion *bool = nil + if meta.(*clients.Client).Features.VirtualMachine.ForceDelete { + forceDeletion = utils.Bool(true) + } deleteFuture, err := client.Delete(ctx, id.ResourceGroup, id.Name, forceDeletion) if err != nil { return fmt.Errorf("deleting Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go b/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go index 762369613ef1..9b9f9fef2605 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go @@ -261,6 +261,21 @@ func TestAccLinuxVirtualMachine_otherCustomData(t *testing.T) { }) } +func TestAccLinuxVirtualMachine_otherForceDelete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") + r := LinuxVirtualMachineResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.otherForceDelete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccLinuxVirtualMachine_otherLicenseType(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") r := LinuxVirtualMachineResource{} @@ -995,6 +1010,48 @@ resource "azurerm_linux_virtual_machine" "test" { `, r.template(data), data.RandomInteger) } +func (r LinuxVirtualMachineResource) otherForceDelete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features { + virtual_machine { + force_delete = true + } + } +} + +%s + +resource "azurerm_linux_virtual_machine" "test" { + name = "acctestVM-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2" + admin_username = "adminuser" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + admin_ssh_key { + username = "adminuser" + public_key = local.first_public_key + } + + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } +} +`, r.template(data), data.RandomInteger) +} + func (r LinuxVirtualMachineResource) otherLicenseType(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource_test.go b/azurerm/internal/services/compute/linux_virtual_machine_resource_test.go index 12272a87b8b3..b52e5d0c10a6 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource_test.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource_test.go @@ -14,7 +14,7 @@ import ( type LinuxVirtualMachineResource struct { } -func (t LinuxVirtualMachineResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { +func (r LinuxVirtualMachineResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { id, err := parse.VirtualMachineID(state.ID) if err != nil { return nil, err From 3bd28ee348556e117f733dcd273b3ac3b82d754b Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 11:27:11 +0200 Subject: [PATCH 03/16] r/windows_virtual_machine: support for Force Delete --- .../windows_virtual_machine_resource.go | 10 +++- ...ows_virtual_machine_resource_other_test.go | 55 +++++++++++++++++++ .../windows_virtual_machine_resource_test.go | 2 +- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource.go b/azurerm/internal/services/compute/windows_virtual_machine_resource.go index 4c46602c408d..69837fff5809 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource.go @@ -1214,10 +1214,14 @@ func resourceWindowsVirtualMachineDelete(d *schema.ResourceData, meta interface{ } log.Printf("[DEBUG] Deleting Windows Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) - // @tombuildsstuff: sending `nil` here omits this value from being sent - which matches - // the previous behaviour - we're only splitting this out so it's clear why - // TODO: support force deletion once it's out of Preview, if applicable + + // Force Delete is in an opt-in Preview and can only be specified (true/false) if the feature is enabled + // as such we default this to `nil` which matches the previous behaviour (where this isn't sent) and + // conditionally set this if required var forceDeletion *bool = nil + if meta.(*clients.Client).Features.VirtualMachine.ForceDelete { + forceDeletion = utils.Bool(true) + } deleteFuture, err := client.Delete(ctx, id.ResourceGroup, id.Name, forceDeletion) if err != nil { return fmt.Errorf("deleting Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go b/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go index a9157371e19d..818226cf93bb 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go @@ -437,6 +437,23 @@ func TestAccWindowsVirtualMachine_otherEnableAutomaticUpdatesDisabled(t *testing }) } +func TestAccWindowsVirtualMachine_otherForceDelete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") + r := WindowsVirtualMachineResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.otherForceDelete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep( + "admin_password", + ), + }) +} + func TestAccWindowsVirtualMachine_otherLicenseTypeNone(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") r := WindowsVirtualMachineResource{} @@ -1485,6 +1502,44 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.template(data)) } +func (r WindowsVirtualMachineResource) otherForceDelete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features { + virtual_machine { + force_delete = true + } + } +} + +%s + +resource "azurerm_windows_virtual_machine" "test" { + name = local.vm_name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2" + admin_username = "adminuser" + admin_password = "P@$$w0rd1234!" + network_interface_ids = [ + azurerm_network_interface.test.id, + ] + + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2016-Datacenter" + version = "latest" + } +} +`, r.template(data)) +} + func (r WindowsVirtualMachineResource) otherLicenseTypeDefault(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource_test.go b/azurerm/internal/services/compute/windows_virtual_machine_resource_test.go index e8f3f8a41b58..b0a0324b74ee 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource_test.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource_test.go @@ -14,7 +14,7 @@ import ( type WindowsVirtualMachineResource struct { } -func (t WindowsVirtualMachineResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { +func (r WindowsVirtualMachineResource) Exists(ctx context.Context, clients *clients.Client, state *terraform.InstanceState) (*bool, error) { id, err := parse.VirtualMachineID(state.ID) if err != nil { return nil, err From 0ca4372e1b63eff9279c69b7877d893015f25022 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 11:32:13 +0200 Subject: [PATCH 04/16] provider: adding `force_delete` to the `virtual_machine_scale_set` features block --- azurerm/internal/features/defaults.go | 1 + azurerm/internal/features/user_flags.go | 1 + azurerm/internal/provider/features.go | 3 + azurerm/internal/provider/features_test.go | 64 ++++++++++++++++------ website/docs/index.html.markdown | 4 ++ 5 files changed, 55 insertions(+), 18 deletions(-) diff --git a/azurerm/internal/features/defaults.go b/azurerm/internal/features/defaults.go index 50efe3a2f6b6..04f57fccdb98 100644 --- a/azurerm/internal/features/defaults.go +++ b/azurerm/internal/features/defaults.go @@ -22,6 +22,7 @@ func Default() UserFeatures { ForceDelete: false, }, VirtualMachineScaleSet: VirtualMachineScaleSetFeatures{ + ForceDelete: false, RollInstancesWhenRequired: true, }, } diff --git a/azurerm/internal/features/user_flags.go b/azurerm/internal/features/user_flags.go index 638386a7259c..7fd310ee179b 100644 --- a/azurerm/internal/features/user_flags.go +++ b/azurerm/internal/features/user_flags.go @@ -16,6 +16,7 @@ type VirtualMachineFeatures struct { } type VirtualMachineScaleSetFeatures struct { + ForceDelete bool RollInstancesWhenRequired bool } diff --git a/azurerm/internal/provider/features.go b/azurerm/internal/provider/features.go index 2e44b34a67cd..589fa3931da5 100644 --- a/azurerm/internal/provider/features.go +++ b/azurerm/internal/provider/features.go @@ -200,6 +200,9 @@ func expandFeatures(input []interface{}) features.UserFeatures { if v, ok := scaleSetRaw["roll_instances_when_required"]; ok { features.VirtualMachineScaleSet.RollInstancesWhenRequired = v.(bool) } + if v, ok := scaleSetRaw["force_delete"]; ok { + features.VirtualMachineScaleSet.ForceDelete = v.(bool) + } } } diff --git a/azurerm/internal/provider/features_test.go b/azurerm/internal/provider/features_test.go index e0f36f1a257f..93d54e351484 100644 --- a/azurerm/internal/provider/features_test.go +++ b/azurerm/internal/provider/features_test.go @@ -22,6 +22,9 @@ func TestExpandFeatures(t *testing.T) { PurgeSoftDeleteOnDestroy: true, RecoverSoftDeletedKeyVaults: true, }, + LogAnalyticsWorkspace: features.LogAnalyticsWorkspaceFeatures{ + PermanentlyDeleteOnDestroy: false, + }, Network: features.NetworkFeatures{ RelaxedLocking: false, }, @@ -34,11 +37,9 @@ func TestExpandFeatures(t *testing.T) { ForceDelete: false, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ + ForceDelete: false, RollInstancesWhenRequired: true, }, - LogAnalyticsWorkspace: features.LogAnalyticsWorkspaceFeatures{ - PermanentlyDeleteOnDestroy: false, - }, }, }, { @@ -76,6 +77,7 @@ func TestExpandFeatures(t *testing.T) { "virtual_machine_scale_set": []interface{}{ map[string]interface{}{ "roll_instances_when_required": true, + "force_delete": true, }, }, }, @@ -101,6 +103,7 @@ func TestExpandFeatures(t *testing.T) { }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ RollInstancesWhenRequired: true, + ForceDelete: true, }, }, }, @@ -108,11 +111,15 @@ func TestExpandFeatures(t *testing.T) { Name: "Complete Disabled", Input: []interface{}{ map[string]interface{}{ - "virtual_machine": []interface{}{ + "key_vault": []interface{}{ map[string]interface{}{ - "delete_os_disk_on_deletion": false, - "graceful_shutdown": false, - "force_delete": false, + "purge_soft_delete_on_destroy": false, + "recover_soft_deleted_key_vaults": false, + }, + }, + "log_analytics_workspace": []interface{}{ + map[string]interface{}{ + "permanently_delete_on_destroy": false, }, }, "network_locking": []interface{}{ @@ -125,20 +132,17 @@ func TestExpandFeatures(t *testing.T) { "delete_nested_items_during_deletion": false, }, }, - "virtual_machine_scale_set": []interface{}{ - map[string]interface{}{ - "roll_instances_when_required": false, - }, - }, - "key_vault": []interface{}{ + "virtual_machine": []interface{}{ map[string]interface{}{ - "purge_soft_delete_on_destroy": false, - "recover_soft_deleted_key_vaults": false, + "delete_os_disk_on_deletion": false, + "graceful_shutdown": false, + "force_delete": false, }, }, - "log_analytics_workspace": []interface{}{ + "virtual_machine_scale_set": []interface{}{ map[string]interface{}{ - "permanently_delete_on_destroy": false, + "force_delete": false, + "roll_instances_when_required": false, }, }, }, @@ -163,6 +167,7 @@ func TestExpandFeatures(t *testing.T) { ForceDelete: false, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ + ForceDelete: false, RollInstancesWhenRequired: false, }, }, @@ -515,12 +520,32 @@ func TestExpandFeaturesVirtualMachineScaleSet(t *testing.T) { }, }, }, + { + Name: "Force Delete Enabled", + Input: []interface{}{ + map[string]interface{}{ + "virtual_machine_scale_set": []interface{}{ + map[string]interface{}{ + "force_delete": true, + "roll_instances_when_required": false, + }, + }, + }, + }, + Expected: features.UserFeatures{ + VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ + ForceDelete: true, + RollInstancesWhenRequired: false, + }, + }, + }, { Name: "Roll Instances Enabled", Input: []interface{}{ map[string]interface{}{ "virtual_machine_scale_set": []interface{}{ map[string]interface{}{ + "force_delete": false, "roll_instances_when_required": true, }, }, @@ -528,16 +553,18 @@ func TestExpandFeaturesVirtualMachineScaleSet(t *testing.T) { }, Expected: features.UserFeatures{ VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ + ForceDelete: false, RollInstancesWhenRequired: true, }, }, }, { - Name: "Roll Instances Disabled", + Name: "All Fields Disabled", Input: []interface{}{ map[string]interface{}{ "virtual_machine_scale_set": []interface{}{ map[string]interface{}{ + "force_delete": false, "roll_instances_when_required": false, }, }, @@ -545,6 +572,7 @@ func TestExpandFeaturesVirtualMachineScaleSet(t *testing.T) { }, Expected: features.UserFeatures{ VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ + ForceDelete: false, RollInstancesWhenRequired: false, }, }, diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index bb29d15cbcd1..662dd3acc420 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -216,4 +216,8 @@ The `virtual_machine` block supports the following: The `virtual_machine_scale_set` block supports the following: +* `force_delete` - Should the `azurerm_linux_virtual_machine_scale_set` and `azurerm_windows_virtual_machine_scale_set` resources send a `Force Delete` flag when deleting the Virtual Machine Scale Set? This can help to work around issues within the Azure Platform during deletion of a Virtual Machine Scale Set. Defaults to `false`. + +~> **Note:** Support for Force Delete is in an opt-in Preview. + * `roll_instances_when_required` - (Optional) Should the `azurerm_linux_virtual_machine_scale_set` and `azurerm_windows_virtual_machine_scale_set` resources automatically roll the instances in the Scale Set when Required (for example when updating the Sku/Image). Defaults to `true`. From 8aa1f0dfc5ca43a4a7f2b44961c06ba82b058318 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 11:39:54 +0200 Subject: [PATCH 05/16] r/linux_virtual_machine_scale_set: support for Force Delete --- ...l_machine_scale_set_other_resource_test.go | 66 +++++++++++++++++++ ...inux_virtual_machine_scale_set_resource.go | 9 ++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go b/azurerm/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go index 26acff68582c..5f3bd622c0db 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_scale_set_other_resource_test.go @@ -154,6 +154,23 @@ func TestAccLinuxVirtualMachineScaleSet_otherCustomData(t *testing.T) { }) } +func TestAccLinuxVirtualMachineScaleSet_otherForceDelete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine_scale_set", "test") + r := LinuxVirtualMachineScaleSetResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.otherForceDelete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep( + "admin_password", + ), + }) +} + func TestAccLinuxVirtualMachineScaleSet_otherPrioritySpotDeallocate(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine_scale_set", "test") r := LinuxVirtualMachineScaleSetResource{} @@ -906,6 +923,55 @@ resource "azurerm_linux_virtual_machine_scale_set" "test" { `, r.template(data), data.RandomInteger, customData) } +func (r LinuxVirtualMachineScaleSetResource) otherForceDelete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features { + virtual_machine_scale_set { + force_delete = true + } + } +} + +%s + +resource "azurerm_linux_virtual_machine_scale_set" "test" { + name = "acctestvmss-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard_F2" + instances = 1 + admin_username = "adminuser" + admin_password = "P@ssword1234!" + + disable_password_authentication = false + + source_image_reference { + publisher = "Canonical" + offer = "UbuntuServer" + sku = "16.04-LTS" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + network_interface { + name = "example" + primary = true + + ip_configuration { + name = "internal" + primary = true + subnet_id = azurerm_subnet.test.id + } + } +} +`, r.template(data), data.RandomInteger) +} + func (r LinuxVirtualMachineScaleSetResource) otherPrioritySpot(data acceptance.TestData, evictionPolicy string) string { return fmt.Sprintf(` %s diff --git a/azurerm/internal/services/compute/linux_virtual_machine_scale_set_resource.go b/azurerm/internal/services/compute/linux_virtual_machine_scale_set_resource.go index bcbe679df140..a6e1161d1d7a 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_scale_set_resource.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_scale_set_resource.go @@ -1082,10 +1082,13 @@ func resourceLinuxVirtualMachineScaleSetDelete(d *schema.ResourceData, meta inte } log.Printf("[DEBUG] Deleting Linux Virtual Machine Scale Set %q (Resource Group %q)..", id.Name, id.ResourceGroup) - // @ArcturusZhang (mimicking from linux_virtual_machine_resource.go): sending `nil` here omits this value from being sent - // which matches the previous behaviour - we're only splitting this out so it's clear why - // TODO: support force deletion once it's out of Preview, if applicable + // Force Delete is in an opt-in Preview and can only be specified (true/false) if the feature is enabled + // as such we default this to `nil` which matches the previous behaviour (where this isn't sent) and + // conditionally set this if required var forceDeletion *bool = nil + if meta.(*clients.Client).Features.VirtualMachineScaleSet.ForceDelete { + forceDeletion = utils.Bool(true) + } future, err := client.Delete(ctx, id.ResourceGroup, id.Name, forceDeletion) if err != nil { return fmt.Errorf("Error deleting Linux Virtual Machine Scale Set %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) From f7b69bd3770426c3484164dfeabd27fba84cc25a Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 11:40:20 +0200 Subject: [PATCH 06/16] r/windows_virtual_machine_scale_set: support for Force Delete --- ...l_machine_scale_set_other_resource_test.go | 65 +++++++++++++++++++ ...dows_virtual_machine_scale_set_resource.go | 9 ++- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go b/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go index b76f18404c3e..b27c74670e15 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go @@ -172,6 +172,23 @@ func TestAccWindowsVirtualMachineScaleSet_otherCustomData(t *testing.T) { }) } +func TestAccWindowsVirtualMachineScaleSet_otherForceDelete(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine_scale_set", "test") + r := WindowsVirtualMachineScaleSetResource{} + + data.ResourceTest(t, r, []resource.TestStep{ + { + Config: r.otherForceDelete(data), + Check: resource.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep( + "admin_password", + ), + }) +} + func TestAccWindowsVirtualMachineScaleSet_otherEnableAutomaticUpdatesDisabled(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine_scale_set", "test") r := WindowsVirtualMachineScaleSetResource{} @@ -1047,6 +1064,54 @@ resource "azurerm_windows_virtual_machine_scale_set" "test" { `, r.template(data), customData) } +func (r WindowsVirtualMachineScaleSetResource) otherForceDelete(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features { + virtual_machine_scale_set { + force_delete = true + } + } +} + +%s + +resource "azurerm_windows_virtual_machine_scale_set" "test" { + name = local.vm_name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Standard_F2" + instances = 1 + admin_username = "adminuser" + admin_password = "P@ssword1234!" + custom_data = base64encode(%q) + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2019-Datacenter" + version = "latest" + } + + os_disk { + storage_account_type = "Standard_LRS" + caching = "ReadWrite" + } + + network_interface { + name = "example" + primary = true + + ip_configuration { + name = "internal" + primary = true + subnet_id = azurerm_subnet.test.id + } + } +} +`, r.template(data)) +} + func (r WindowsVirtualMachineScaleSetResource) otherEnableAutomaticUpdatesDisabled(data acceptance.TestData) string { return fmt.Sprintf(` %s diff --git a/azurerm/internal/services/compute/windows_virtual_machine_scale_set_resource.go b/azurerm/internal/services/compute/windows_virtual_machine_scale_set_resource.go index 7e9ab750c7f5..eb91de8e1ab1 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_scale_set_resource.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_scale_set_resource.go @@ -1128,10 +1128,13 @@ func resourceWindowsVirtualMachineScaleSetDelete(d *schema.ResourceData, meta in } log.Printf("[DEBUG] Deleting Windows Virtual Machine Scale Set %q (Resource Group %q)..", id.Name, id.ResourceGroup) - // @ArcturusZhang (mimicking from windows_virtual_machine_resource.go): sending `nil` here omits this value from being sent - // which matches the previous behaviour - we're only splitting this out so it's clear why - // TODO: support force deletion once it's out of Preview, if applicable + // Force Delete is in an opt-in Preview and can only be specified (true/false) if the feature is enabled + // as such we default this to `nil` which matches the previous behaviour (where this isn't sent) and + // conditionally set this if required var forceDeletion *bool = nil + if meta.(*clients.Client).Features.VirtualMachineScaleSet.ForceDelete { + forceDeletion = utils.Bool(true) + } future, err := client.Delete(ctx, id.ResourceGroup, id.Name, forceDeletion) if err != nil { return fmt.Errorf("Error deleting Windows Virtual Machine Scale Set %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) From 74ef98eb265236006fa77ee0bb8807e8ae75546c Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 11:52:51 +0200 Subject: [PATCH 07/16] features: adding a todo that we should investigate changing this default in 3.0 We can't do this now since the API errors if this preview functionality isn't enabled --- azurerm/internal/features/defaults.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/features/defaults.go b/azurerm/internal/features/defaults.go index 04f57fccdb98..545c5e4e79ce 100644 --- a/azurerm/internal/features/defaults.go +++ b/azurerm/internal/features/defaults.go @@ -19,9 +19,11 @@ func Default() UserFeatures { VirtualMachine: VirtualMachineFeatures{ DeleteOSDiskOnDeletion: true, GracefulShutdown: false, - ForceDelete: false, + // TODO: this should likely be defaulted true in 3.0 + ForceDelete: false, }, VirtualMachineScaleSet: VirtualMachineScaleSetFeatures{ + // TODO: this should likely be defaulted true in 3.0 ForceDelete: false, RollInstancesWhenRequired: true, }, From 61a5c6bb7d1d128cc350c2226dd22013330c4610 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 6 Apr 2021 12:31:10 +0200 Subject: [PATCH 08/16] linting --- .../windows_virtual_machine_resource_other_test.go | 12 ++++++------ ..._virtual_machine_scale_set_other_resource_test.go | 1 - ...ment_group_subscription_association.html.markdown | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go b/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go index 818226cf93bb..00f887c011e2 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go @@ -1515,12 +1515,12 @@ provider "azurerm" { %s resource "azurerm_windows_virtual_machine" "test" { - name = local.vm_name - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - size = "Standard_F2" - admin_username = "adminuser" - admin_password = "P@$$w0rd1234!" + name = local.vm_name + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + size = "Standard_F2" + admin_username = "adminuser" + admin_password = "P@$$w0rd1234!" network_interface_ids = [ azurerm_network_interface.test.id, ] diff --git a/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go b/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go index b27c74670e15..261dd755f5c1 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_scale_set_other_resource_test.go @@ -1084,7 +1084,6 @@ resource "azurerm_windows_virtual_machine_scale_set" "test" { instances = 1 admin_username = "adminuser" admin_password = "P@ssword1234!" - custom_data = base64encode(%q) source_image_reference { publisher = "MicrosoftWindowsServer" diff --git a/website/docs/r/management_group_subscription_association.html.markdown b/website/docs/r/management_group_subscription_association.html.markdown index 8ed1707c985b..508d4964fd2c 100644 --- a/website/docs/r/management_group_subscription_association.html.markdown +++ b/website/docs/r/management_group_subscription_association.html.markdown @@ -57,4 +57,4 @@ Managements can be imported using the `resource id`, e.g. ```shell terraform import azurerm_management_group_subscription_association.example /managementGroup/MyManagementGroup/subscription/12345678-1234-1234-1234-123456789012 -``` \ No newline at end of file +``` From 12cfdc7e661225668f437db44beac085bf9324b5 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 8 Apr 2021 18:20:29 +0200 Subject: [PATCH 09/16] provider: adding the missing feature flags to the provider block --- azurerm/internal/provider/features.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/azurerm/internal/provider/features.go b/azurerm/internal/provider/features.go index 589fa3931da5..28090886158c 100644 --- a/azurerm/internal/provider/features.go +++ b/azurerm/internal/provider/features.go @@ -82,6 +82,10 @@ func schemaFeatures(supportLegacyTestSuite bool) *schema.Schema { Type: schema.TypeBool, Optional: true, }, + "force_delete": { + Type: schema.TypeBool, + Optional: true, + }, }, }, }, @@ -92,9 +96,13 @@ func schemaFeatures(supportLegacyTestSuite bool) *schema.Schema { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "force_delete": { + Type: schema.TypeBool, + Optional: true, + }, "roll_instances_when_required": { Type: schema.TypeBool, - Required: true, + Optional: true, }, }, }, From 4fc77c8eec4d89f5a32124329ac854bbf0f48425 Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Thu, 8 Apr 2021 20:51:43 +0200 Subject: [PATCH 10/16] provider: adding a feature-flag for conditionally shutting down the Virtual Machine prior to deletion This is necessary since there's cost benefits to doing so with larger machines - whilst we could opt to do this automatically in the case of Force Delete based on the Service Teams description of this functionality, Force Delete should likely become the default in 3.x since it's more reliable for other items in the stack than a regular delete, however this can't be done yet until the feature leaves the preview period (as at the moment it's a public preview which errors if it's disabled) Ultimately this allows users who want to use Force Delete without shutting the VM can do so using both feature toggles together - whilst allowing the more resilient deletion (which will become the default at some point in the future) to be used with a gradual shut-down in the case of specific VM's where this can be useful. --- azurerm/internal/features/defaults.go | 3 +- azurerm/internal/features/user_flags.go | 1 + azurerm/internal/provider/features.go | 8 +++++ azurerm/internal/provider/features_test.go | 35 ++++++++++++++++++ .../compute/linux_virtual_machine_resource.go | 36 ++++++++++--------- .../windows_virtual_machine_resource.go | 36 ++++++++++--------- 6 files changed, 84 insertions(+), 35 deletions(-) diff --git a/azurerm/internal/features/defaults.go b/azurerm/internal/features/defaults.go index 545c5e4e79ce..fb41189bc70a 100644 --- a/azurerm/internal/features/defaults.go +++ b/azurerm/internal/features/defaults.go @@ -20,7 +20,8 @@ func Default() UserFeatures { DeleteOSDiskOnDeletion: true, GracefulShutdown: false, // TODO: this should likely be defaulted true in 3.0 - ForceDelete: false, + ForceDelete: false, + ShutdownBeforeDeletion: true, }, VirtualMachineScaleSet: VirtualMachineScaleSetFeatures{ // TODO: this should likely be defaulted true in 3.0 diff --git a/azurerm/internal/features/user_flags.go b/azurerm/internal/features/user_flags.go index 7fd310ee179b..8cab16b99b4a 100644 --- a/azurerm/internal/features/user_flags.go +++ b/azurerm/internal/features/user_flags.go @@ -13,6 +13,7 @@ type VirtualMachineFeatures struct { DeleteOSDiskOnDeletion bool GracefulShutdown bool ForceDelete bool + ShutdownBeforeDeletion bool } type VirtualMachineScaleSetFeatures struct { diff --git a/azurerm/internal/provider/features.go b/azurerm/internal/provider/features.go index 28090886158c..b792fe515c1b 100644 --- a/azurerm/internal/provider/features.go +++ b/azurerm/internal/provider/features.go @@ -86,6 +86,11 @@ func schemaFeatures(supportLegacyTestSuite bool) *schema.Schema { Type: schema.TypeBool, Optional: true, }, + "shutdown_before_deletion": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, }, }, }, @@ -198,6 +203,9 @@ func expandFeatures(input []interface{}) features.UserFeatures { if v, ok := virtualMachinesRaw["force_delete"]; ok { features.VirtualMachine.ForceDelete = v.(bool) } + if v, ok := virtualMachinesRaw["shutdown_before_deletion"]; ok { + features.VirtualMachine.ShutdownBeforeDeletion = v.(bool) + } } } diff --git a/azurerm/internal/provider/features_test.go b/azurerm/internal/provider/features_test.go index 93d54e351484..63302d43e16d 100644 --- a/azurerm/internal/provider/features_test.go +++ b/azurerm/internal/provider/features_test.go @@ -35,6 +35,7 @@ func TestExpandFeatures(t *testing.T) { DeleteOSDiskOnDeletion: true, GracefulShutdown: false, ForceDelete: false, + ShutdownBeforeDeletion: true, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ ForceDelete: false, @@ -72,6 +73,7 @@ func TestExpandFeatures(t *testing.T) { "delete_os_disk_on_deletion": true, "graceful_shutdown": true, "force_delete": true, + "shutdown_before_deletion": true, }, }, "virtual_machine_scale_set": []interface{}{ @@ -100,6 +102,7 @@ func TestExpandFeatures(t *testing.T) { DeleteOSDiskOnDeletion: true, GracefulShutdown: true, ForceDelete: true, + ShutdownBeforeDeletion: true, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ RollInstancesWhenRequired: true, @@ -137,6 +140,7 @@ func TestExpandFeatures(t *testing.T) { "delete_os_disk_on_deletion": false, "graceful_shutdown": false, "force_delete": false, + "shutdown_before_deletion": false, }, }, "virtual_machine_scale_set": []interface{}{ @@ -165,6 +169,7 @@ func TestExpandFeatures(t *testing.T) { DeleteOSDiskOnDeletion: false, GracefulShutdown: false, ForceDelete: false, + ShutdownBeforeDeletion: false, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ ForceDelete: false, @@ -402,6 +407,7 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { DeleteOSDiskOnDeletion: true, GracefulShutdown: false, ForceDelete: false, + ShutdownBeforeDeletion: true, }, }, }, @@ -414,6 +420,7 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { "delete_os_disk_on_deletion": true, "graceful_shutdown": false, "force_delete": false, + "shutdown_before_deletion": false, }, }, }, @@ -435,6 +442,7 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { "delete_os_disk_on_deletion": false, "graceful_shutdown": true, "force_delete": false, + "shutdown_before_deletion": false, }, }, }, @@ -456,6 +464,7 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { "delete_os_disk_on_deletion": false, "graceful_shutdown": false, "force_delete": true, + "shutdown_before_deletion": false, }, }, }, @@ -465,6 +474,30 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { DeleteOSDiskOnDeletion: false, GracefulShutdown: false, ForceDelete: true, + ShutdownBeforeDeletion: false, + }, + }, + }, + { + Name: "Shutdown Before Deletion Enabled", + Input: []interface{}{ + map[string]interface{}{ + "virtual_machine": []interface{}{ + map[string]interface{}{ + "delete_os_disk_on_deletion": false, + "graceful_shutdown": false, + "force_delete": false, + "shutdown_before_deletion": true, + }, + }, + }, + }, + Expected: features.UserFeatures{ + VirtualMachine: features.VirtualMachineFeatures{ + DeleteOSDiskOnDeletion: false, + GracefulShutdown: false, + ForceDelete: false, + ShutdownBeforeDeletion: true, }, }, }, @@ -477,6 +510,7 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { "delete_os_disk_on_deletion": false, "graceful_shutdown": false, "force_delete": false, + "shutdown_before_deletion": false, }, }, }, @@ -486,6 +520,7 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { DeleteOSDiskOnDeletion: false, GracefulShutdown: false, ForceDelete: false, + ShutdownBeforeDeletion: false, }, }, }, diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource.go b/azurerm/internal/services/compute/linux_virtual_machine_resource.go index 55b26d8631d9..36085752b25b 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource.go @@ -1135,24 +1135,26 @@ func resourceLinuxVirtualMachineDelete(d *schema.ResourceData, meta interface{}) return fmt.Errorf("retrieving Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - // If the VM was in a Failed state we can skip powering off, since that'll fail - if strings.EqualFold(*existing.ProvisioningState, "failed") { - log.Printf("[DEBUG] Powering Off Linux Virtual Machine was skipped because the VM was in %q state %q (Resource Group %q).", *existing.ProvisioningState, id.Name, id.ResourceGroup) - } else { - //ISSUE: 4920 - // shutting down the Virtual Machine prior to removing it means users are no longer charged for some Azure resources - // thus this can be a large cost-saving when deleting larger instances - // https://docs.microsoft.com/en-us/azure/virtual-machines/states-lifecycle - log.Printf("[DEBUG] Powering Off Linux Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) - skipShutdown := !meta.(*clients.Client).Features.VirtualMachine.GracefulShutdown - powerOffFuture, err := client.PowerOff(ctx, id.ResourceGroup, id.Name, utils.Bool(skipShutdown)) - if err != nil { - return fmt.Errorf("powering off Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - if err := powerOffFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for power off of Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if meta.(*clients.Client).Features.VirtualMachine.ShutdownBeforeDeletion { + // If the VM was in a Failed state we can skip powering off, since that'll fail + if strings.EqualFold(*existing.ProvisioningState, "failed") { + log.Printf("[DEBUG] Powering Off Linux Virtual Machine was skipped because the VM was in %q state %q (Resource Group %q).", *existing.ProvisioningState, id.Name, id.ResourceGroup) + } else { + //ISSUE: 4920 + // shutting down the Virtual Machine prior to removing it means users are no longer charged for some Azure resources + // thus this can be a large cost-saving when deleting larger instances + // https://docs.microsoft.com/en-us/azure/virtual-machines/states-lifecycle + log.Printf("[DEBUG] Powering Off Linux Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) + skipShutdown := !meta.(*clients.Client).Features.VirtualMachine.GracefulShutdown + powerOffFuture, err := client.PowerOff(ctx, id.ResourceGroup, id.Name, utils.Bool(skipShutdown)) + if err != nil { + return fmt.Errorf("powering off Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + if err := powerOffFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for power off of Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + log.Printf("[DEBUG] Powered Off Linux Virtual Machine %q (Resource Group %q).", id.Name, id.ResourceGroup) } - log.Printf("[DEBUG] Powered Off Linux Virtual Machine %q (Resource Group %q).", id.Name, id.ResourceGroup) } log.Printf("[DEBUG] Deleting Linux Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource.go b/azurerm/internal/services/compute/windows_virtual_machine_resource.go index 69837fff5809..b0991d544590 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource.go @@ -1193,24 +1193,26 @@ func resourceWindowsVirtualMachineDelete(d *schema.ResourceData, meta interface{ return fmt.Errorf("retrieving Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - // If the VM was in a Failed state we can skip powering off, since that'll fail - if strings.EqualFold(*existing.ProvisioningState, "failed") { - log.Printf("[DEBUG] Powering Off Windows Virtual Machine was skipped because the VM was in %q state %q (Resource Group %q).", *existing.ProvisioningState, id.Name, id.ResourceGroup) - } else { - //ISSUE: 4920 - // shutting down the Virtual Machine prior to removing it means users are no longer charged for some Azure resources - // thus this can be a large cost-saving when deleting larger instances - // https://docs.microsoft.com/en-us/azure/virtual-machines/states-lifecycle - log.Printf("[DEBUG] Powering Off Windows Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) - skipShutdown := !meta.(*clients.Client).Features.VirtualMachine.GracefulShutdown - powerOffFuture, err := client.PowerOff(ctx, id.ResourceGroup, id.Name, utils.Bool(skipShutdown)) - if err != nil { - return fmt.Errorf("powering off Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) - } - if err := powerOffFuture.WaitForCompletionRef(ctx, client.Client); err != nil { - return fmt.Errorf("waiting for power off of Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + if meta.(*clients.Client).Features.VirtualMachine.ShutdownBeforeDeletion { + // If the VM was in a Failed state we can skip powering off, since that'll fail + if strings.EqualFold(*existing.ProvisioningState, "failed") { + log.Printf("[DEBUG] Powering Off Windows Virtual Machine was skipped because the VM was in %q state %q (Resource Group %q).", *existing.ProvisioningState, id.Name, id.ResourceGroup) + } else { + //ISSUE: 4920 + // shutting down the Virtual Machine prior to removing it means users are no longer charged for some Azure resources + // thus this can be a large cost-saving when deleting larger instances + // https://docs.microsoft.com/en-us/azure/virtual-machines/states-lifecycle + log.Printf("[DEBUG] Powering Off Windows Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) + skipShutdown := !meta.(*clients.Client).Features.VirtualMachine.GracefulShutdown + powerOffFuture, err := client.PowerOff(ctx, id.ResourceGroup, id.Name, utils.Bool(skipShutdown)) + if err != nil { + return fmt.Errorf("powering off Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + if err := powerOffFuture.WaitForCompletionRef(ctx, client.Client); err != nil { + return fmt.Errorf("waiting for power off of Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) + } + log.Printf("[DEBUG] Powered Off Windows Virtual Machine %q (Resource Group %q).", id.Name, id.ResourceGroup) } - log.Printf("[DEBUG] Powered Off Windows Virtual Machine %q (Resource Group %q).", id.Name, id.ResourceGroup) } log.Printf("[DEBUG] Deleting Windows Virtual Machine %q (Resource Group %q)..", id.Name, id.ResourceGroup) From 424568c8054b89c1e7262be20564d536fa55d37b Mon Sep 17 00:00:00 2001 From: tombuildsstuff Date: Tue, 13 Apr 2021 09:50:37 +0200 Subject: [PATCH 11/16] docs: updating the description for force delete --- website/docs/index.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 662dd3acc420..1eebf208b907 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -208,7 +208,7 @@ The `virtual_machine` block supports the following: ~> **Note:** When using a graceful shutdown, Azure gives the Virtual Machine a 5 minutes window in which to complete the shutdown process, at which point the machine will be force powered off - [more information can be found in this blog post](https://azure.microsoft.com/en-us/blog/linux-and-graceful-shutdowns-2/). -* `force_delete` - Should the `azurerm_linux_virtual_machine` and `azurerm_windows_virtual_machine` resources send a `Force Delete` flag when deleting the Virtual Machine? This can help to work around issues within the Azure Platform during deletion of a Virtual Machine. Defaults to `false`. +* `force_delete` - Should the `azurerm_linux_virtual_machine` and `azurerm_windows_virtual_machine` resources send a `Force Delete` flag when deleting the Virtual Machine? Force Delete force-detaches all devices from the Virtual Machine during deletion, rather than waiting for them to gracefully detach - which can be helpful during the deletion of other resources. Defaults to `false`. ~> **Note:** Support for Force Delete is in an opt-in Preview. @@ -216,7 +216,7 @@ The `virtual_machine` block supports the following: The `virtual_machine_scale_set` block supports the following: -* `force_delete` - Should the `azurerm_linux_virtual_machine_scale_set` and `azurerm_windows_virtual_machine_scale_set` resources send a `Force Delete` flag when deleting the Virtual Machine Scale Set? This can help to work around issues within the Azure Platform during deletion of a Virtual Machine Scale Set. Defaults to `false`. +* `force_delete` - Should the `azurerm_linux_virtual_machine_scale_set` and `azurerm_windows_virtual_machine_scale_set` resources send a `Force Delete` flag when deleting the Virtual Machine Scale Set? Force Delete force-detaches all devices from the Virtual Machine Scale Set during deletion, rather than waiting for them to gracefully detach - which can be helpful during the deletion of other resources. Defaults to `false`. ~> **Note:** Support for Force Delete is in an opt-in Preview. From 18ae1e0dd299991522128f81327675b7a8a76960 Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 11 May 2021 21:32:14 -0700 Subject: [PATCH 12/16] combine flags --- azurerm/internal/features/defaults.go | 3 +- azurerm/internal/features/user_flags.go | 7 +- azurerm/internal/provider/features.go | 14 +-- azurerm/internal/provider/features_test.go | 100 ++++++------------ .../compute/linux_virtual_machine_resource.go | 4 +- .../windows_virtual_machine_resource.go | 4 +- 6 files changed, 45 insertions(+), 87 deletions(-) diff --git a/azurerm/internal/features/defaults.go b/azurerm/internal/features/defaults.go index fb41189bc70a..4f19923b4f0d 100644 --- a/azurerm/internal/features/defaults.go +++ b/azurerm/internal/features/defaults.go @@ -20,8 +20,7 @@ func Default() UserFeatures { DeleteOSDiskOnDeletion: true, GracefulShutdown: false, // TODO: this should likely be defaulted true in 3.0 - ForceDelete: false, - ShutdownBeforeDeletion: true, + SkipShutdownAndForceDelete: false, }, VirtualMachineScaleSet: VirtualMachineScaleSetFeatures{ // TODO: this should likely be defaulted true in 3.0 diff --git a/azurerm/internal/features/user_flags.go b/azurerm/internal/features/user_flags.go index 8cab16b99b4a..d66c53e60891 100644 --- a/azurerm/internal/features/user_flags.go +++ b/azurerm/internal/features/user_flags.go @@ -10,10 +10,9 @@ type UserFeatures struct { } type VirtualMachineFeatures struct { - DeleteOSDiskOnDeletion bool - GracefulShutdown bool - ForceDelete bool - ShutdownBeforeDeletion bool + DeleteOSDiskOnDeletion bool + GracefulShutdown bool + SkipShutdownAndForceDelete bool } type VirtualMachineScaleSetFeatures struct { diff --git a/azurerm/internal/provider/features.go b/azurerm/internal/provider/features.go index b792fe515c1b..93606b587b36 100644 --- a/azurerm/internal/provider/features.go +++ b/azurerm/internal/provider/features.go @@ -82,15 +82,10 @@ func schemaFeatures(supportLegacyTestSuite bool) *schema.Schema { Type: schema.TypeBool, Optional: true, }, - "force_delete": { + "skip_shutdown_and_force_delete": { Type: schema.TypeBool, Optional: true, }, - "shutdown_before_deletion": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, }, }, }, @@ -200,11 +195,8 @@ func expandFeatures(input []interface{}) features.UserFeatures { if v, ok := virtualMachinesRaw["graceful_shutdown"]; ok { features.VirtualMachine.GracefulShutdown = v.(bool) } - if v, ok := virtualMachinesRaw["force_delete"]; ok { - features.VirtualMachine.ForceDelete = v.(bool) - } - if v, ok := virtualMachinesRaw["shutdown_before_deletion"]; ok { - features.VirtualMachine.ShutdownBeforeDeletion = v.(bool) + if v, ok := virtualMachinesRaw["skip_shutdown_and_force_delete"]; ok { + features.VirtualMachine.SkipShutdownAndForceDelete = v.(bool) } } } diff --git a/azurerm/internal/provider/features_test.go b/azurerm/internal/provider/features_test.go index 63302d43e16d..2caaf2f4adba 100644 --- a/azurerm/internal/provider/features_test.go +++ b/azurerm/internal/provider/features_test.go @@ -32,10 +32,9 @@ func TestExpandFeatures(t *testing.T) { DeleteNestedItemsDuringDeletion: true, }, VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: true, - GracefulShutdown: false, - ForceDelete: false, - ShutdownBeforeDeletion: true, + DeleteOSDiskOnDeletion: true, + GracefulShutdown: false, + SkipShutdownAndForceDelete: false, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ ForceDelete: false, @@ -70,10 +69,9 @@ func TestExpandFeatures(t *testing.T) { }, "virtual_machine": []interface{}{ map[string]interface{}{ - "delete_os_disk_on_deletion": true, - "graceful_shutdown": true, - "force_delete": true, - "shutdown_before_deletion": true, + "delete_os_disk_on_deletion": true, + "graceful_shutdown": true, + "skip_shutdown_and_force_delete": true, }, }, "virtual_machine_scale_set": []interface{}{ @@ -99,10 +97,9 @@ func TestExpandFeatures(t *testing.T) { DeleteNestedItemsDuringDeletion: true, }, VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: true, - GracefulShutdown: true, - ForceDelete: true, - ShutdownBeforeDeletion: true, + DeleteOSDiskOnDeletion: true, + GracefulShutdown: true, + SkipShutdownAndForceDelete: true, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ RollInstancesWhenRequired: true, @@ -137,10 +134,9 @@ func TestExpandFeatures(t *testing.T) { }, "virtual_machine": []interface{}{ map[string]interface{}{ - "delete_os_disk_on_deletion": false, - "graceful_shutdown": false, - "force_delete": false, - "shutdown_before_deletion": false, + "delete_os_disk_on_deletion": false, + "graceful_shutdown": false, + "skip_shutdown_and_force_delete": false, }, }, "virtual_machine_scale_set": []interface{}{ @@ -166,10 +162,9 @@ func TestExpandFeatures(t *testing.T) { DeleteNestedItemsDuringDeletion: false, }, VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: false, - GracefulShutdown: false, - ForceDelete: false, - ShutdownBeforeDeletion: false, + DeleteOSDiskOnDeletion: false, + GracefulShutdown: false, + SkipShutdownAndForceDelete: false, }, VirtualMachineScaleSet: features.VirtualMachineScaleSetFeatures{ ForceDelete: false, @@ -404,10 +399,9 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { }, Expected: features.UserFeatures{ VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: true, - GracefulShutdown: false, - ForceDelete: false, - ShutdownBeforeDeletion: true, + DeleteOSDiskOnDeletion: true, + GracefulShutdown: false, + SkipShutdownAndForceDelete: false, }, }, }, @@ -427,9 +421,9 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { }, Expected: features.UserFeatures{ VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: true, - GracefulShutdown: false, - ForceDelete: false, + DeleteOSDiskOnDeletion: true, + GracefulShutdown: false, + SkipShutdownAndForceDelete: false, }, }, }, @@ -449,14 +443,14 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { }, Expected: features.UserFeatures{ VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: false, - GracefulShutdown: true, - ForceDelete: false, + DeleteOSDiskOnDeletion: false, + GracefulShutdown: true, + SkipShutdownAndForceDelete: false, }, }, }, { - Name: "Force Delete Enabled", + Name: "Skip Shutdown and Force Delete Enabled", Input: []interface{}{ map[string]interface{}{ "virtual_machine": []interface{}{ @@ -471,33 +465,9 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { }, Expected: features.UserFeatures{ VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: false, - GracefulShutdown: false, - ForceDelete: true, - ShutdownBeforeDeletion: false, - }, - }, - }, - { - Name: "Shutdown Before Deletion Enabled", - Input: []interface{}{ - map[string]interface{}{ - "virtual_machine": []interface{}{ - map[string]interface{}{ - "delete_os_disk_on_deletion": false, - "graceful_shutdown": false, - "force_delete": false, - "shutdown_before_deletion": true, - }, - }, - }, - }, - Expected: features.UserFeatures{ - VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: false, - GracefulShutdown: false, - ForceDelete: false, - ShutdownBeforeDeletion: true, + DeleteOSDiskOnDeletion: false, + GracefulShutdown: false, + SkipShutdownAndForceDelete: true, }, }, }, @@ -507,20 +477,18 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { map[string]interface{}{ "virtual_machine": []interface{}{ map[string]interface{}{ - "delete_os_disk_on_deletion": false, - "graceful_shutdown": false, - "force_delete": false, - "shutdown_before_deletion": false, + "delete_os_disk_on_deletion": false, + "graceful_shutdown": false, + "skip_shutdown_and_force_delete": false, }, }, }, }, Expected: features.UserFeatures{ VirtualMachine: features.VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: false, - GracefulShutdown: false, - ForceDelete: false, - ShutdownBeforeDeletion: false, + DeleteOSDiskOnDeletion: false, + GracefulShutdown: false, + SkipShutdownAndForceDelete: false, }, }, }, diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource.go b/azurerm/internal/services/compute/linux_virtual_machine_resource.go index 36085752b25b..ff9c1cfac3e1 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource.go @@ -1135,7 +1135,7 @@ func resourceLinuxVirtualMachineDelete(d *schema.ResourceData, meta interface{}) return fmt.Errorf("retrieving Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - if meta.(*clients.Client).Features.VirtualMachine.ShutdownBeforeDeletion { + if !meta.(*clients.Client).Features.VirtualMachine.SkipShutdownAndForceDelete { // If the VM was in a Failed state we can skip powering off, since that'll fail if strings.EqualFold(*existing.ProvisioningState, "failed") { log.Printf("[DEBUG] Powering Off Linux Virtual Machine was skipped because the VM was in %q state %q (Resource Group %q).", *existing.ProvisioningState, id.Name, id.ResourceGroup) @@ -1163,7 +1163,7 @@ func resourceLinuxVirtualMachineDelete(d *schema.ResourceData, meta interface{}) // as such we default this to `nil` which matches the previous behaviour (where this isn't sent) and // conditionally set this if required var forceDeletion *bool = nil - if meta.(*clients.Client).Features.VirtualMachine.ForceDelete { + if meta.(*clients.Client).Features.VirtualMachine.SkipShutdownAndForceDelete { forceDeletion = utils.Bool(true) } deleteFuture, err := client.Delete(ctx, id.ResourceGroup, id.Name, forceDeletion) diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource.go b/azurerm/internal/services/compute/windows_virtual_machine_resource.go index b0991d544590..4b1e829f763c 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource.go @@ -1193,7 +1193,7 @@ func resourceWindowsVirtualMachineDelete(d *schema.ResourceData, meta interface{ return fmt.Errorf("retrieving Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - if meta.(*clients.Client).Features.VirtualMachine.ShutdownBeforeDeletion { + if !meta.(*clients.Client).Features.VirtualMachine.SkipShutdownAndForceDelete { // If the VM was in a Failed state we can skip powering off, since that'll fail if strings.EqualFold(*existing.ProvisioningState, "failed") { log.Printf("[DEBUG] Powering Off Windows Virtual Machine was skipped because the VM was in %q state %q (Resource Group %q).", *existing.ProvisioningState, id.Name, id.ResourceGroup) @@ -1221,7 +1221,7 @@ func resourceWindowsVirtualMachineDelete(d *schema.ResourceData, meta interface{ // as such we default this to `nil` which matches the previous behaviour (where this isn't sent) and // conditionally set this if required var forceDeletion *bool = nil - if meta.(*clients.Client).Features.VirtualMachine.ForceDelete { + if meta.(*clients.Client).Features.VirtualMachine.SkipShutdownAndForceDelete { forceDeletion = utils.Bool(true) } deleteFuture, err := client.Delete(ctx, id.ResourceGroup, id.Name, forceDeletion) From bf59ee379a3f10302f44ebef06a93dbbb74fe876 Mon Sep 17 00:00:00 2001 From: kt Date: Tue, 11 May 2021 21:32:53 -0700 Subject: [PATCH 13/16] update comments --- azurerm/internal/features/defaults.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/azurerm/internal/features/defaults.go b/azurerm/internal/features/defaults.go index 4f19923b4f0d..cb2bd779773a 100644 --- a/azurerm/internal/features/defaults.go +++ b/azurerm/internal/features/defaults.go @@ -19,11 +19,9 @@ func Default() UserFeatures { VirtualMachine: VirtualMachineFeatures{ DeleteOSDiskOnDeletion: true, GracefulShutdown: false, - // TODO: this should likely be defaulted true in 3.0 SkipShutdownAndForceDelete: false, }, VirtualMachineScaleSet: VirtualMachineScaleSetFeatures{ - // TODO: this should likely be defaulted true in 3.0 ForceDelete: false, RollInstancesWhenRequired: true, }, From ce86c9d1b30a986bc26a91941da84cbf381f8f31 Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 13 May 2021 10:44:07 -0700 Subject: [PATCH 14/16] update docs --- azurerm/internal/features/defaults.go | 4 ++-- .../compute/linux_virtual_machine_resource_other_test.go | 8 ++++---- .../windows_virtual_machine_resource_other_test.go | 8 ++++---- website/docs/index.html.markdown | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/azurerm/internal/features/defaults.go b/azurerm/internal/features/defaults.go index cb2bd779773a..e20667114f2d 100644 --- a/azurerm/internal/features/defaults.go +++ b/azurerm/internal/features/defaults.go @@ -17,8 +17,8 @@ func Default() UserFeatures { DeleteNestedItemsDuringDeletion: true, }, VirtualMachine: VirtualMachineFeatures{ - DeleteOSDiskOnDeletion: true, - GracefulShutdown: false, + DeleteOSDiskOnDeletion: true, + GracefulShutdown: false, SkipShutdownAndForceDelete: false, }, VirtualMachineScaleSet: VirtualMachineScaleSetFeatures{ diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go b/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go index 9b9f9fef2605..30151fa01e3f 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource_other_test.go @@ -261,13 +261,13 @@ func TestAccLinuxVirtualMachine_otherCustomData(t *testing.T) { }) } -func TestAccLinuxVirtualMachine_otherForceDelete(t *testing.T) { +func TestAccLinuxVirtualMachine_otherSkipShutdownAndForceDelete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_linux_virtual_machine", "test") r := LinuxVirtualMachineResource{} data.ResourceTest(t, r, []resource.TestStep{ { - Config: r.otherForceDelete(data), + Config: r.otherSkipShutdownAndForceDelete(data), Check: resource.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -1010,12 +1010,12 @@ resource "azurerm_linux_virtual_machine" "test" { `, r.template(data), data.RandomInteger) } -func (r LinuxVirtualMachineResource) otherForceDelete(data acceptance.TestData) string { +func (r LinuxVirtualMachineResource) otherSkipShutdownAndForceDelete(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features { virtual_machine { - force_delete = true + skip_shutdown_and_force_delete = true } } } diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go b/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go index 00f887c011e2..4a3926b136e3 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource_other_test.go @@ -437,13 +437,13 @@ func TestAccWindowsVirtualMachine_otherEnableAutomaticUpdatesDisabled(t *testing }) } -func TestAccWindowsVirtualMachine_otherForceDelete(t *testing.T) { +func TestAccWindowsVirtualMachine_otherSkipShutdownAndForceDelete(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_windows_virtual_machine", "test") r := WindowsVirtualMachineResource{} data.ResourceTest(t, r, []resource.TestStep{ { - Config: r.otherForceDelete(data), + Config: r.otherSkipShutdownAndForceDelete(data), Check: resource.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -1502,12 +1502,12 @@ resource "azurerm_windows_virtual_machine" "test" { `, r.template(data)) } -func (r WindowsVirtualMachineResource) otherForceDelete(data acceptance.TestData) string { +func (r WindowsVirtualMachineResource) otherSkipShutdownAndForceDelete(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { features { virtual_machine { - force_delete = true + skip_shutdown_and_force_delete = true } } } diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 1eebf208b907..ce9e58f53c18 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -208,7 +208,7 @@ The `virtual_machine` block supports the following: ~> **Note:** When using a graceful shutdown, Azure gives the Virtual Machine a 5 minutes window in which to complete the shutdown process, at which point the machine will be force powered off - [more information can be found in this blog post](https://azure.microsoft.com/en-us/blog/linux-and-graceful-shutdowns-2/). -* `force_delete` - Should the `azurerm_linux_virtual_machine` and `azurerm_windows_virtual_machine` resources send a `Force Delete` flag when deleting the Virtual Machine? Force Delete force-detaches all devices from the Virtual Machine during deletion, rather than waiting for them to gracefully detach - which can be helpful during the deletion of other resources. Defaults to `false`. +* `skip_shudown_and_force_delete` - Should the `azurerm_linux_virtual_machine` and `azurerm_windows_virtual_machine` skip the shutdown command and `Force Delete`, this provides the ability to forcefully and immediately delete the VM and detach all sub-resources associated with the virtual machine. This allows those freed resources to be reattached to another VM instance or deleted. Defaults to `false`. ~> **Note:** Support for Force Delete is in an opt-in Preview. @@ -216,7 +216,7 @@ The `virtual_machine` block supports the following: The `virtual_machine_scale_set` block supports the following: -* `force_delete` - Should the `azurerm_linux_virtual_machine_scale_set` and `azurerm_windows_virtual_machine_scale_set` resources send a `Force Delete` flag when deleting the Virtual Machine Scale Set? Force Delete force-detaches all devices from the Virtual Machine Scale Set during deletion, rather than waiting for them to gracefully detach - which can be helpful during the deletion of other resources. Defaults to `false`. +* `force_delete` - Should the `azurerm_linux_virtual_machine_scale_set` and `azurerm_windows_virtual_machine_scale_set` resources `Force Delete`, this provides the ability to forcefully and immediately delete the VM and detach all sub-resources associated with the virtual machine. This allows those freed resources to be reattached to another VM instance or deleted. Defaults to `false`. ~> **Note:** Support for Force Delete is in an opt-in Preview. From 4a5d8f2d2d87d309491cc390b0b542fe57eb5d2f Mon Sep 17 00:00:00 2001 From: kt Date: Mon, 24 May 2021 18:13:34 -0700 Subject: [PATCH 15/16] make fmt --- azurerm/internal/provider/features.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azurerm/internal/provider/features.go b/azurerm/internal/provider/features.go index cb3b52827c69..9acaae4f842c 100644 --- a/azurerm/internal/provider/features.go +++ b/azurerm/internal/provider/features.go @@ -1,7 +1,7 @@ package provider import ( - `github.com/hashicorp/terraform-plugin-sdk/helper/schema` + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/features" "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/tf/pluginsdk" ) From e12e301bff409d5e7fa3a81a110ef88614f69b2d Mon Sep 17 00:00:00 2001 From: kt Date: Wed, 26 May 2021 14:56:33 -0700 Subject: [PATCH 16/16] fix tests --- azurerm/internal/provider/features_test.go | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/azurerm/internal/provider/features_test.go b/azurerm/internal/provider/features_test.go index 2caaf2f4adba..f429f83ad19e 100644 --- a/azurerm/internal/provider/features_test.go +++ b/azurerm/internal/provider/features_test.go @@ -436,7 +436,6 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { "delete_os_disk_on_deletion": false, "graceful_shutdown": true, "force_delete": false, - "shutdown_before_deletion": false, }, }, }, @@ -455,10 +454,9 @@ func TestExpandFeaturesVirtualMachine(t *testing.T) { map[string]interface{}{ "virtual_machine": []interface{}{ map[string]interface{}{ - "delete_os_disk_on_deletion": false, - "graceful_shutdown": false, - "force_delete": true, - "shutdown_before_deletion": false, + "delete_os_disk_on_deletion": false, + "graceful_shutdown": false, + "skip_shutdown_and_force_delete": true, }, }, },