hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.6k stars 4.64k forks source link

Issue with 'terraform plan -destroy' for resources created with count #25692

Open sameer-mandaokar opened 6 months ago

sameer-mandaokar commented 6 months ago

Is there an existing issue for this?

Community Note

Issue with "terraform plan -destroy -target=<target_id_count[1]>" for count-based resources

Description

We're creating multiple resources using COUNT meta-arg, which reads configuration from JSON array and iterates over JSON objects, and keep on creating resources. We have three VMs (VM[0-2] with their RBAC Role (Contributor) on the resource group.

When we want to delete the VM[1] using command, it marks the RBAC assignment for VM[0] & VM[2] as well, which is not as per expectation

Terraform Version

2.99

AzureRM Provider Version

2.8

Affected Resource(s)/Data Source(s)

azurerm_role_assignment

Terraform Configuration Files

############ START: Terraform Configuration #################
variable "location" { default = "EastUS" }

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.0"
    }
  }
}

# This SP details should NEVER be part of tfvars or tf file, instead it should be supplied via env variables.
provider "azurerm" {
  features {}

  subscription_id = "<subs-id>"
  tenant_id       = "<tenant-id>"
  client_id       = "<service-principal-id>
  client_secret   = "<secret>"

}

locals {
  env_data = jsondecode(file("env_config.json"))["target_vms"]
  ## Specifies how many wcsccm instances we should be creating
  instance_count = length(local.env_data)

}

resource "azurerm_resource_group" "rg" {
  name     = "wcsccm-poc-rg"
  location = "East US"

  tags = {
    Name = "POC-COUNT"
  }
}

resource "azurerm_virtual_network" "vnet" {
  name                = "poc-vnet"
  location            = var.location
  resource_group_name = azurerm_resource_group.rg.name
  address_space       = ["10.207.229.0/24"]

  tags = {
    Name = "POC-COUNT"
  }
}

resource "azurerm_subnet" "subnet" {

  name                 = "poc-vnet-subnet"
  resource_group_name  = azurerm_resource_group.rg.name
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.207.229.0/28"]

}

resource "azurerm_network_interface" "nic" {
  count               = local.instance_count
  name                = "nic-${count.index}"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name

  ip_configuration {
    name                          = "ip-${count.index}"
    subnet_id                     = azurerm_subnet.subnet.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_linux_virtual_machine" "vm" {
  count                 = local.instance_count
  name                  = local.env_data[count.index].name
  location              = azurerm_resource_group.rg.location
  resource_group_name   = azurerm_resource_group.rg.name
  network_interface_ids = [azurerm_network_interface.nic[count.index].id]
  size                  = "Standard_D2ds_v5"
  computer_name         = local.env_data[count.index].name
  admin_username        = "myazureuser"
  #   license_type          = "RHEL_BYOS"

  os_disk {
    name                 = "vm-osdisk-${count.index}"
    caching              = "ReadWrite"
    storage_account_type = "Premium_LRS"
    disk_size_gb         = 128
  }

  source_image_reference {
    publisher = "canonical"
    offer     = "0001-com-ubuntu-minimal-jammy"
    sku       = "minimal-22_04-lts-gen2"
    version   = "latest"
  }

  identity {
    type = "SystemAssigned"
  }

  admin_ssh_key {
    public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQB29Q4Mo+8ueEmCy5enTsch5RR1L5fIM6SFmX21riiGVN0MsiNoUFf5nTeel7J6EbzZJipQy7GfIL0oiMPo/HxkLxLtVw1vB/ZNDo++3Fh3upZP9CWe5YJXdN90kIrGUArLMF3LrZc+iAHzByinpOxLIhUkuzJjTTBpSWvwTRr5XBVyq+cXmSdIab67SrbOoUaeffkR4C6XrEBjl0uJpfPdXfX5kq8wdwUTYs7JiuuachXthX9jtOOx0u98ZSUQbGgsTf4rM6NUEEfhy8Nxiuz3vsnU8z5Ff77sVCBfMhu/Zx9FAm7neiS2qPycxtEblEEZ8e/6D0FOZyQlAyQT+QVN rsa-key-20190305 mycloud admin common key"
    username   = "myazureuser"
  }

  tags = {
    Name = "POC-COUNT"
  }
}

resource "azurerm_role_assignment" "iam_role" {
  count                = local.instance_count
  scope                = azurerm_resource_group.rg.id
  role_definition_name = "Contributor"
  principal_id         = azurerm_linux_virtual_machine.vm[count.index].identity[0].principal_id
}

#------------ OUTPUTS ----------------#
output "vm_output" {
  description = "VM Details"
   value = { for k, v in azurerm_linux_virtual_machine.vm : k => v.id }
}

output "iam_roles_output" {
  description = "IAM Role details"
  value = { for k, v in azurerm_role_assignment.iam_role : k => v.id }
}

############ END: Terraform Configuration #################

############ START: env_config.json #################

{
    "target_vms": [
        {
            "name": "count-poc-vm1"
        },
        {
            "name": "count-poc-vm2"
        },
        {
            "name": "count-poc-vm3"
        }
    ]
}

############ END: env_config.json #################

Debug Output/Panic Output

#[root@vm:4 wcsccm_temp](git:wcsccm_refactor) # terraform plan -destroy -target=azurerm_linux_virtual_machine.vm[1]

azurerm_resource_group.rg: Refreshing state... [id=/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg]
azurerm_virtual_network.vnet: Refreshing state... [id=/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Network/virtualNetworks/poc-vnet]
azurerm_subnet.subnet: Refreshing state... [id=/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Network/virtualNetworks/poc-vnet/subnets/poc-vnet-subnet]
azurerm_network_interface.nic[0]: Refreshing state... [id=/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Network/networkInterfaces/nic-0]
azurerm_network_interface.nic[2]: Refreshing state... [id=/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Network/networkInterfaces/nic-2]
azurerm_network_interface.nic[1]: Refreshing state... [id=/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Network/networkInterfaces/nic-1]
azurerm_linux_virtual_machine.vm[1]: Refreshing state... [id=/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Compute/virtualMachines/count-poc-vm2]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # azurerm_linux_virtual_machine.vm[1] will be destroyed
  - resource "azurerm_linux_virtual_machine" "vm" {
      - admin_username                                         = "myazureuser" -> null
      - allow_extension_operations                             = true -> null
      - bypass_platform_safety_checks_on_user_schedule_enabled = false -> null
      - computer_name                                          = "count-poc-vm2" -> null
      - disable_password_authentication                        = true -> null
      - disk_controller_type                                   = "SCSI" -> null
      - encryption_at_host_enabled                             = false -> null
      - extensions_time_budget                                 = "PT1H30M" -> null
      - id                                                     = "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Compute/virtualMachines/count-poc-vm2" -> null
      - location                                               = "eastus" -> null
      - max_bid_price                                          = -1 -> null
      - name                                                   = "count-poc-vm2" -> null
      - network_interface_ids                                  = [
          - "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Network/networkInterfaces/nic-1",
        ] -> null
      - patch_assessment_mode                                  = "ImageDefault" -> null
      - patch_mode                                             = "ImageDefault" -> null
      - platform_fault_domain                                  = -1 -> null
      - priority                                               = "Regular" -> null
      - private_ip_address                                     = "10.207.229.6" -> null
      - private_ip_addresses                                   = [
          - "10.207.229.6",
        ] -> null
      - provision_vm_agent                                     = true -> null
      - public_ip_addresses                                    = [] -> null
      - resource_group_name                                    = "wcsccm-poc-rg" -> null
      - secure_boot_enabled                                    = false -> null
      - size                                                   = "Standard_D2ds_v5" -> null
      - tags                                                   = {
          - "Name" = "POC-COUNT"
        } -> null
      - virtual_machine_id                                     = "61336656-1aca-4819-8cb2-0f89b3fcffe5" -> null
      - vm_agent_platform_updates_enabled                      = false -> null
      - vtpm_enabled                                           = false -> null

      - admin_ssh_key {
          - public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQB29Q4Mo+8ueEmCy5enTsch5RR1L5fIM6SFmX21riiGVN0MsiNoUFf5nTeel7J6EbzZJipQy7GfIL0oiMPo/HxkLxLtVw1vB/ZNDo++3Fh3upZP9CWe5YJXdN90kIrGUArLMF3LrZc+iAHzByinpOxLIhUkuzJjTTBpSWvwTRr5XBVyq+cXmSdIab67SrbOoUaeffkR4C6XrEBjl0uJpfPdXfX5kq8wdwUTYs7JiuuachXthX9jtOOx0u98ZSUQbGgsTf4rM6NUEEfhy8Nxiuz3vsnU8z5Ff77sVCBfMhu/Zx9FAm7neiS2qPycxtEblEEZ8e/6D0FOZyQlAyQT+QVN rsa-key-20190305 mycloud admin common key" -> null
          - username   = "myazureuser" -> null
        }

      - identity {
          - identity_ids = [] -> null
          - principal_id = "e3c31b16-e430-4fb3-a187-cc41e5132d19" -> null
          - tenant_id    = "0fdcdd31-e3e2-49ba-b748-2c3def81bd6e" -> null
          - type         = "SystemAssigned" -> null
        }

      - os_disk {
          - caching                   = "ReadWrite" -> null
          - disk_size_gb              = 128 -> null
          - name                      = "vm-osdisk-1" -> null
          - storage_account_type      = "Premium_LRS" -> null
          - write_accelerator_enabled = false -> null
        }

      - source_image_reference {
          - offer     = "0001-com-ubuntu-minimal-jammy" -> null
          - publisher = "canonical" -> null
          - sku       = "minimal-22_04-lts-gen2" -> null
          - version   = "latest" -> null
        }
    }

  # azurerm_role_assignment.iam_role[0] will be destroyed
  - resource "azurerm_role_assignment" "iam_role" {
      - id                   = "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Authorization/roleAssignments/5444557e-c96c-d2fa-f90a-490a3005759b" -> null
      - name                 = "5444557e-c96c-d2fa-f90a-490a3005759b" -> null
      - principal_id         = "7ffe82ea-abe8-4225-85c4-38e2229f5060" -> null
      - principal_type       = "ServicePrincipal" -> null
      - role_definition_id   = "/subscriptions/subscription_id_hidden/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" -> null
      - role_definition_name = "Contributor" -> null
      - scope                = "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg" -> null
    }

  # azurerm_role_assignment.iam_role[1] will be destroyed
  - resource "azurerm_role_assignment" "iam_role" {
      - id                   = "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Authorization/roleAssignments/967e9c93-dbdd-edcf-b68f-32424d659d6f" -> null
      - name                 = "967e9c93-dbdd-edcf-b68f-32424d659d6f" -> null
      - principal_id         = "e3c31b16-e430-4fb3-a187-cc41e5132d19" -> null
      - principal_type       = "ServicePrincipal" -> null
      - role_definition_id   = "/subscriptions/subscription_id_hidden/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" -> null
      - role_definition_name = "Contributor" -> null
      - scope                = "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg" -> null
    }

  # azurerm_role_assignment.iam_role[2] will be destroyed
  - resource "azurerm_role_assignment" "iam_role" {
      - id                   = "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg/providers/Microsoft.Authorization/roleAssignments/cb9e712b-9c4c-6212-7367-b755fd558737" -> null
      - name                 = "cb9e712b-9c4c-6212-7367-b755fd558737" -> null
      - principal_id         = "e7b34dc6-c213-4c41-9146-561cb842e4f4" -> null
      - principal_type       = "ServicePrincipal" -> null
      - role_definition_id   = "/subscriptions/subscription_id_hidden/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c" -> null
      - role_definition_name = "Contributor" -> null
      - scope                = "/subscriptions/subscription_id_hidden/resourceGroups/wcsccm-poc-rg" -> null
    }

Plan: 0 to add, 0 to change, 4 to destroy.
╷
│ Warning: Resource targeting is in effect
│
│ You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the
│ current configuration.
│
│ The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when
│ Terraform specifically suggests to use it as part of an error message.
╵

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
[root@vm:4 wcsccm_temp](git:wcsccm_refactor) #

Expected Behaviour

It should have marked only below two resources for deletion

azurerm_role_assignment.iam_role[1] will be destroyed

azurerm_linux_virtual_machine.vm[1] will be destroyed

Actual Behaviour

It is marking below four resources for deletion

azurerm_linux_virtual_machine.vm[1] will be destroyed

azurerm_role_assignment.iam_role[0] will be destroyed

azurerm_role_assignment.iam_role[1] will be destroyed

azurerm_role_assignment.iam_role[2] will be destroyed

Steps to Reproduce

Copy above terraform configuration into issue.tf file then hit below commands

  1. Create one folder name 'count_issue'

  2. Copy/Download JSON content from this file in count_issue folder env_config.json

  3. Copy/download TF.txt configuration in count_issue folder count_issue.tf.txt

  4. Rename above file from count_issue.tf.txt to count_issue.txt

  5. Update tf file section from line 16 to 19.

  6. Make sure Service principal should be able to provide RBAC assignments to VM.

  7. Execute terraform init

  8. Execute terraform plan and review plan for VM/RBAC addition for 3 vms

  9. Execute terraform apply --auto-approve

  10. Verify all the resources are created as per JSON content

  11. Hit below command for generating destroy plan terraform plan -destroy -target=azurerm_linux_virtual_machine.vm[1]

  12. You should be able to see the Actual output, which is not as per Expected output. PSA sample output from my console

    plan_destroy_ouput_1 plan_destroy_ouput_2

Important Factoids

No response

References

No response

neil-yechenwei commented 6 months ago

Thanks for raising this issue. Seems the dependency-handling should be based on the index.

sameer-mandaokar commented 6 months ago

@neil-yechenwei

Thanks for your response. I tried adding the dependency azurerm_role_assignment.iam_role resource as below -

resource "azurerm_role_assignment" "iam_role" {
  count                = local.instance_count
  scope                = azurerm_resource_group.rg.id
  role_definition_name = "Contributor"
  principal_id         = azurerm_linux_virtual_machine.vm[count.index].identity[0].principal_id
  depends_on = [ azurerm_linux_virtual_machine.vm ]
}

and I tried recreating the entire infrastructure after adding the dependency. However, it is marking all the iam_role resources for deletion, which is still the issue.