diff --git a/azurerm/internal/services/compute/linux_virtual_machine_resource.go b/azurerm/internal/services/compute/linux_virtual_machine_resource.go index 8b615453b4fc..5ed824dd95f6 100644 --- a/azurerm/internal/services/compute/linux_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/linux_virtual_machine_resource.go @@ -1089,19 +1089,25 @@ func resourceLinuxVirtualMachineDelete(d *schema.ResourceData, meta interface{}) return fmt.Errorf("retrieving Linux Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - // ISSUE: XXX - // shutting down the Virtual Machine prior to removing it means users are no longer charged for the compute - // thus this can be a large cost-saving when deleting larger instances - 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 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) // @tombuildsstuff: sending `nil` here omits this value from being sent - which matches diff --git a/azurerm/internal/services/compute/windows_virtual_machine_resource.go b/azurerm/internal/services/compute/windows_virtual_machine_resource.go index 1d57aae1ae47..da5b03da37c3 100644 --- a/azurerm/internal/services/compute/windows_virtual_machine_resource.go +++ b/azurerm/internal/services/compute/windows_virtual_machine_resource.go @@ -1175,19 +1175,25 @@ func resourceWindowsVirtualMachineDelete(d *schema.ResourceData, meta interface{ return fmt.Errorf("retrieving Windows Virtual Machine %q (Resource Group %q): %+v", id.Name, id.ResourceGroup, err) } - // ISSUE: XXX - // shutting down the Virtual Machine prior to removing it means users are no longer charged for the compute - // thus this can be a large cost-saving when deleting larger instances - 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 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) // @tombuildsstuff: sending `nil` here omits this value from being sent - which matches