When working on already created existing Azure from portal or other scripting tool then managing it using terraform tool can be little bit tedious. I encountered in a situation while working on one of my client's Azure infrastructure, I needed to modify/update existing resources. Here is the view of resource group on Azure ARM portal and on the existing resource group I will update tags using terraform.
Importing already created module Infrastructure into Terraform and update state file
Here is my simple hashicorp terraform HCL language tf file to update resource group tags. Note: there is no tfstate file exists yet.
# We strongly recommend using the required_providers block to set the # Azure Provider source and version being used terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = ">=2.99.0" } } } # Configure the Microsoft Azure Provider provider "azurerm" { features {} } resource "azurerm_resource_group" "rg" { name = "vCloud-lab.com" location = "East US" tags = { owner = "vjani" orgnization = "vcloud-lab.com" } }
When tested the script with terraform init and terraform plan commands, I got that terraform will create a resource, but in actual it should modify/update the existing resource. Any how plan shows tf script is good no errors and it will create services, if no tfstate file exists.
terraform plan Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.rg will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "eastus" + name = "vCloud-lab.com" + tags = { + "orgnization" = "vcloud-lab.com" + "owner" = "vjani" } } Plan: 1 to add, 0 to change, 0 to destroy. ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 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.
Next I applied the terraform configuration. After applying its showing me the actual error that resource already exist and it need to be imported first in the tfstate state file.
terraform apply --auto-approve Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # azurerm_resource_group.rg will be created + resource "azurerm_resource_group" "rg" { + id = (known after apply) + location = "eastus" + name = "vCloud-lab.com" + tags = { + "orgnization" = "vcloud-lab.com" + "owner" = "vjani" } } Plan: 1 to add, 0 to change, 0 to destroy. azurerm_resource_group.rg: Creating... ╷ │ Error: A resource with the ID "/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_resource_group" for more information. │ │ with azurerm_resource_group.rg, │ on main.tf line 17, in resource "azurerm_resource_group" "rg": │ 17: resource "azurerm_resource_group" "rg" { │ ╵
To import it run the below terraform import command with terraform resource reference in the tf script and id of the resource as shown below. Information will be fetched from azure and file tfstate will be updated with the necessary information and I got message resource is imported successfully.
terraform import azurerm_resource_group.rg /subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com azurerm_resource_group.rg: Importing from ID "/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com"... azurerm_resource_group.rg: Import prepared! Prepared azurerm_resource_group for import azurerm_resource_group.rg: Refreshing state... [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
Next it's time to apply the tf configuration again, this time it is showing correct information update in-place and tags will be updated with 1 change applied.
terraform apply --auto-approve azurerm_resource_group.rg: Refreshing state... [id=/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: ~ update in-place Terraform will perform the following actions: # azurerm_resource_group.rg will be updated in-place ~ resource "azurerm_resource_group" "rg" { id = "/subscriptions/9e22xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vCloud-lab.com" name = "vCloud-lab.com" ~ tags = { + "orgnization" = "vcloud-lab.com" + "owner" = "vjani" } # (1 unchanged attribute hidden) # (1 unchanged block hidden) } Plan: 0 to add, 1 to change, 0 to destroy. azurerm_resource_group.rg: Modifying... [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/vCloud-lab.com] azurerm_resource_group.rg: Modifications complete after 4s [id=/subscriptions/9e22fba3-00a9-447c-b954-a26fec38e029/resourceGroups/vCloud-lab.com] Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
I verified on the azure portal, tags are added.
Useful Articles
Create an Azure virtual machine scale set and load balancer using Terraform
Azure Terraform fixed Availibility Zones on Virtual Machine Scale Set
Writing and Using Terraform modules
Terraform Using one module variable in another module
Hashicorp Terraform dynamic block with example
Terraform for_each loop on map example
Terraform for_each loop on resource example
Terraform manage similar resources with for_each loop inside modules