provider/azurerm: destroy azurerm_virtual_machine OS Disk VHD on deletion (#7584)
* provider/azurerm: destroy azurerm_virtual_machine OS Disk VHD on deletion The OS Disk previously wasn't deleted with the VM, this causes subsequent apply operations which recreate the VM to fail as the VHD blob already exists. Fixes #6610 * provider/azurerm: add delete_os_disk_on_termination to azurerm_virtual_machine delete_os_disk_on_termination is a bool which defaults to false to avoid making a breaking change, and to follow the same flow as the Azure API
This commit is contained in:
parent
d1666ba76c
commit
37e3aa9d8c
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
@ -158,6 +159,12 @@ func resourceArmVirtualMachine() *schema.Resource {
|
|||
Set: resourceArmVirtualMachineStorageOsDiskHash,
|
||||
},
|
||||
|
||||
"delete_os_disk_on_termination": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"storage_data_disk": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
|
@ -550,9 +557,48 @@ func resourceArmVirtualMachineDelete(d *schema.ResourceData, meta interface{}) e
|
|||
resGroup := id.ResourceGroup
|
||||
name := id.Path["virtualMachines"]
|
||||
|
||||
_, err = vmClient.Delete(resGroup, name, make(chan struct{}))
|
||||
if _, err = vmClient.Delete(resGroup, name, make(chan struct{})); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
if deleteOsDisk := d.Get("delete_os_disk_on_termination").(bool); !deleteOsDisk {
|
||||
log.Printf("[INFO] delete_os_disk_on_termination is false, skipping delete")
|
||||
return nil
|
||||
}
|
||||
|
||||
osDisk, err := expandAzureRmVirtualMachineOsDisk(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error expanding OS Disk")
|
||||
}
|
||||
|
||||
vhdURL, err := url.Parse(*osDisk.Vhd.URI)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot parse OS Disk VHD URI: %s", err)
|
||||
}
|
||||
|
||||
// VHD URI is in the form: https://storageAccountName.blob.core.windows.net/containerName/blobName
|
||||
storageAccountName := strings.Split(vhdURL.Host, ".")[0]
|
||||
path := strings.Split(strings.TrimPrefix(vhdURL.Path, "/"), "/")
|
||||
containerName := path[0]
|
||||
blobName := path[1]
|
||||
|
||||
blobClient, storageAccountExists, err := meta.(*ArmClient).getBlobStorageClientForStorageAccount(id.ResourceGroup, storageAccountName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating blob store account for VHD deletion: %s", err)
|
||||
}
|
||||
|
||||
if !storageAccountExists {
|
||||
log.Printf("[INFO] Storage Account %q doesn't exist so the VHD blob won't exist", storageAccountName)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Deleting VHD blob %s", blobName)
|
||||
_, err = blobClient.DeleteBlobIfExists(containerName, blobName, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting VHD blob: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceArmVirtualMachinePlanHash(v interface{}) int {
|
||||
|
|
|
@ -14,9 +14,13 @@ func TestAccAzureRMVirtualMachine_basicLinuxMachine(t *testing.T) {
|
|||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccAzureRMVirtualMachine_basicLinuxMachine, ri, ri, ri, ri, ri, ri, ri)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testCheckAzureRMVirtualMachineDestroy,
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: resource.ComposeTestCheckFunc(
|
||||
testCheckAzureRMVirtualMachineDestroy,
|
||||
// deletion of OS Disk VHD is opt in
|
||||
testCheckAzureRMVirtualMachineOSDiskVHDExistance(true),
|
||||
),
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
|
@ -167,6 +171,29 @@ func TestAccAzureRMVirtualMachine_winRMConfig(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAzureRMVirtualMachine_deleteVHD(t *testing.T) {
|
||||
ri := acctest.RandInt()
|
||||
preConfig := fmt.Sprintf(testAccAzureRMVirtualMachine_basicLinuxMachineDestroyOSDisk, ri, ri, ri, ri, ri, ri, ri)
|
||||
postConfig := fmt.Sprintf(testAccAzureRMVirtualMachine_basicLinuxMachineDeleteVM, ri, ri, ri, ri, ri)
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testCheckAzureRMVirtualMachineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: preConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testCheckAzureRMVirtualMachineExists("azurerm_virtual_machine.test"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: postConfig,
|
||||
Check: testCheckAzureRMVirtualMachineOSDiskVHDExistance(false),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testCheckAzureRMVirtualMachineExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
// Ensure we have enough information in state to look up in API
|
||||
|
@ -221,6 +248,36 @@ func testCheckAzureRMVirtualMachineDestroy(s *terraform.State) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func testCheckAzureRMVirtualMachineOSDiskVHDExistance(shouldExist bool) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "azurerm_storage_container" {
|
||||
continue
|
||||
}
|
||||
|
||||
// fetch storage account and container name
|
||||
resourceGroup := rs.Primary.Attributes["resource_group_name"]
|
||||
storageAccountName := rs.Primary.Attributes["storage_account_name"]
|
||||
containerName := rs.Primary.Attributes["name"]
|
||||
storageClient, _, err := testAccProvider.Meta().(*ArmClient).getBlobStorageClientForStorageAccount(resourceGroup, storageAccountName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating Blob storage client: %s", err)
|
||||
}
|
||||
|
||||
exists, err := storageClient.BlobExists(containerName, "myosdisk1.vhd")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error checking if OS Disk VHD Blob exists: %s", err)
|
||||
}
|
||||
|
||||
if exists && !shouldExist {
|
||||
return fmt.Errorf("OS Disk VHD Blob still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var testAccAzureRMVirtualMachine_basicLinuxMachine = `
|
||||
resource "azurerm_resource_group" "test" {
|
||||
name = "acctestrg-%d"
|
||||
|
@ -309,6 +366,147 @@ resource "azurerm_virtual_machine" "test" {
|
|||
}
|
||||
`
|
||||
|
||||
var testAccAzureRMVirtualMachine_basicLinuxMachineDestroyOSDisk = `
|
||||
resource "azurerm_resource_group" "test" {
|
||||
name = "acctestrg-%d"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
resource "azurerm_virtual_network" "test" {
|
||||
name = "acctvn-%d"
|
||||
address_space = ["10.0.0.0/16"]
|
||||
location = "West US"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
}
|
||||
|
||||
resource "azurerm_subnet" "test" {
|
||||
name = "acctsub-%d"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
virtual_network_name = "${azurerm_virtual_network.test.name}"
|
||||
address_prefix = "10.0.2.0/24"
|
||||
}
|
||||
|
||||
resource "azurerm_network_interface" "test" {
|
||||
name = "acctni-%d"
|
||||
location = "West US"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
|
||||
ip_configuration {
|
||||
name = "testconfiguration1"
|
||||
subnet_id = "${azurerm_subnet.test.id}"
|
||||
private_ip_address_allocation = "dynamic"
|
||||
}
|
||||
}
|
||||
|
||||
resource "azurerm_storage_account" "test" {
|
||||
name = "accsa%d"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
location = "westus"
|
||||
account_type = "Standard_LRS"
|
||||
|
||||
tags {
|
||||
environment = "staging"
|
||||
}
|
||||
}
|
||||
|
||||
resource "azurerm_storage_container" "test" {
|
||||
name = "vhds"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
storage_account_name = "${azurerm_storage_account.test.name}"
|
||||
container_access_type = "private"
|
||||
}
|
||||
|
||||
resource "azurerm_virtual_machine" "test" {
|
||||
name = "acctvm-%d"
|
||||
location = "West US"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
network_interface_ids = ["${azurerm_network_interface.test.id}"]
|
||||
vm_size = "Standard_A0"
|
||||
|
||||
storage_image_reference {
|
||||
publisher = "Canonical"
|
||||
offer = "UbuntuServer"
|
||||
sku = "14.04.2-LTS"
|
||||
version = "latest"
|
||||
}
|
||||
|
||||
storage_os_disk {
|
||||
name = "myosdisk1"
|
||||
vhd_uri = "${azurerm_storage_account.test.primary_blob_endpoint}${azurerm_storage_container.test.name}/myosdisk1.vhd"
|
||||
caching = "ReadWrite"
|
||||
create_option = "FromImage"
|
||||
}
|
||||
|
||||
delete_os_disk_on_termination = true
|
||||
|
||||
os_profile {
|
||||
computer_name = "hostname%d"
|
||||
admin_username = "testadmin"
|
||||
admin_password = "Password1234!"
|
||||
}
|
||||
|
||||
os_profile_linux_config {
|
||||
disable_password_authentication = false
|
||||
}
|
||||
|
||||
tags {
|
||||
environment = "Production"
|
||||
cost-center = "Ops"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAzureRMVirtualMachine_basicLinuxMachineDeleteVM = `
|
||||
resource "azurerm_resource_group" "test" {
|
||||
name = "acctestrg-%d"
|
||||
location = "West US"
|
||||
}
|
||||
|
||||
resource "azurerm_virtual_network" "test" {
|
||||
name = "acctvn-%d"
|
||||
address_space = ["10.0.0.0/16"]
|
||||
location = "West US"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
}
|
||||
|
||||
resource "azurerm_subnet" "test" {
|
||||
name = "acctsub-%d"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
virtual_network_name = "${azurerm_virtual_network.test.name}"
|
||||
address_prefix = "10.0.2.0/24"
|
||||
}
|
||||
|
||||
resource "azurerm_network_interface" "test" {
|
||||
name = "acctni-%d"
|
||||
location = "West US"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
|
||||
ip_configuration {
|
||||
name = "testconfiguration1"
|
||||
subnet_id = "${azurerm_subnet.test.id}"
|
||||
private_ip_address_allocation = "dynamic"
|
||||
}
|
||||
}
|
||||
|
||||
resource "azurerm_storage_account" "test" {
|
||||
name = "accsa%d"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
location = "westus"
|
||||
account_type = "Standard_LRS"
|
||||
|
||||
tags {
|
||||
environment = "staging"
|
||||
}
|
||||
}
|
||||
|
||||
resource "azurerm_storage_container" "test" {
|
||||
name = "vhds"
|
||||
resource_group_name = "${azurerm_resource_group.test.name}"
|
||||
storage_account_name = "${azurerm_storage_account.test.name}"
|
||||
container_access_type = "private"
|
||||
}
|
||||
`
|
||||
|
||||
var testAccAzureRMVirtualMachine_withDataDisk = `
|
||||
resource "azurerm_resource_group" "test" {
|
||||
name = "acctestrg-%d"
|
||||
|
|
Loading…
Reference in New Issue