Terraform - Removing a resource from local state file - azure

To create a new Terraform state file, I'm importing some legacy Azure resources into a Terraform configuration with a local state file. As expected, my import syntax is as follows:
terraform import <Terraform Resource Name>.<Resource Label> <Azure Resource ID>
Unfortunately, for one of my resources, I used the wrong Resource Label and had to rename it. I then performed a Terraform plan, but as the earlier Resource Label had already been written into the state file, the plan now displays the message that a resource will be destroyed when applied. Just to clarify, the resource with the corrected Resource Label is also written into the state file, so there's no danger of it being destroyed in Azure.
I however want to clean up the local state file by removing the orphaned resource, so when I ran a Terraform Plan, it reports that:
"No changes. Your infrastructure matches the configuration"
How can I do so safely without compromising my state file or the legacy resources?

As suggested by #luk2302, I tested the command in my environment after I imported a keyvault resource to my local state file and then tried to removed only the keyvault resource from terraform state and it was successful.
The resource is only removed from state file and it can be still found in portal.
Reference:
Command: state rm - Terraform by HashiCorp

Related

how to delete a terraform state file when the azure resources are removed using terraform?

We are building a temp review app in terraform. Currently when review app is finished with the resources are destroyed with terraform using terraform apply -destroy. What i need to do is also remove the terraform state file for this infrastructure from the azure container. Could I use terraform -destroy to also remove the state file and how can i do this?
One of the workaround you can follow,
When we are using terraform destroy that time our resource detailed also removed from terraform.tfstate by removing from portal itself.
So to remove any particular resource from .tfstate you can try something like below;
First would suggest you to after destroy the file list the state file you have then remove those.
This below command is used to get the available instances which are in state file.
terraform state list
After listing those try with below which will remove from .tfstate file as mentioned by #Ansuman Bal i have also tried and it works fine .
terraform state rm "azurerm_resource_group.example"
OUTPUT DETAILS FOR REFERENCE:-
NOTE:- This aforementioned cmdlts will remove the instance/resources from .tfstate file only not from portal. Only terraform destroy can do that.
For more information please refer this SO THREAD| Terraform - Removing a resource from local state file.

Terraform Import - Is the Resource Label critical?

Our terraform remote state file in Azure has been completely destroyed and we're now faced with the challenge of recreating the state file from scratch. My option is to use the Terraform import command, using the following simple syntax:
terraform import <Terraform Resource Name>.<Resource Label> <Azure Resource ID>
To import the existing resource group for example, I will create the following configuration in a main.tf file.
provider "azurerm" {
version="1.39.0"
}
# create resource group
resource "azurerm_resource_group" "rg"{
name = "rg-terraform"
location = "uksouth"
}
Now, the problem I have is as follows:
When the existing Azure resources were originally created, they were assigned names that used an extremely complex naming convention, with some characters even being randomly generated. To further compound matters, they were all unique and there are hundreds of them. All would have been rosy if they were assigned a simplistic name like "main", as is used commonly in a lot of Terraform examples, but unfortunately, that's not the case.
My question therefore, is this:
When putting together my main.tf configuration file to be used for the Import, is it an absolute requirement that my "Resource Label" (given in my Import command) has to match the original "Resource Label" name from when the resource was created?
If it is a mandatory requirement, is there any way I could retrieve the original "Resource Label" from Azure in the same way that I can for instance obtain the "Azure Resource ID" from the Azure Portal or even an Az CLI query?
How can I ensure any child resources such as Subnets are included in the Import, without having to trawl manually through the Azure Portal to identify each one of them?
No, absolutely not. Choose whatever you want.
No, Azure generally does not know about this label, it is something terraform internal.
Unfortunately you need to import each and every resource manually and separately.
Have you made absolutely sure the current state file is lost? The storage location was not versioned? Does no developer still have a local copy of the state file laying around?

How to Conditionally Create an Azure Resource-Group (or Any Resource) if Someone Else Has Not Created One

I know that when I do terraform apply it does not deploy a resource if the previous deployment within the same terraform state, it would not re-create it .
But I want to do something different:
Create a resource if it is not created by someone else.
But if the resource is already there and even it is not in the terraform state, do not generate an error and have refrence to its name.
Is there any known pattern to do this?
By design Terraform providers will typically not automatically "adopt" existing objects as now being managed by Terraform, because to do so would potentially lead to costly mistakes if you inadvertently bind a remote object to a Terraform resource and then run terraform destroy without realizing what is going to be destroyed.
Instead, you must bind existing objects to your Terraform resources using the terraform import command, telling Terraform explicitly that you intend it to become the sole manager of that object.

What is the purpose of an import in Terraform?

This question is not how to import and it's not what's the purpose of tfstate. It's what's the purpose of importing a pre-existing resource, esp. compared to just referencing the ID of the existing resource?
Terraform has the feature of terraform import. HashiCorp describes the purpose of this as:
Terraform is able to import existing infrastructure. This allows you take resources you've created by some other means and bring it under Terraform management.
This is a great way to slowly transition infrastructure to Terraform, or to be able to be confident that you can use Terraform in the future if it potentially doesn't support every feature you need today.
I read the article about the purpose of Terraform state. It does make sense to me to track Terraform state with .tfstate files when those files are mappings back to the configurations in .tf files.
But it's still unclear to me what the purpose of a standalone .tfstate file is when it only maps to an empty resource block. If there is a resource not in terraform yet, I would typically do one of two things:
put the resource in terraform, tear down the resource manually and re-deploy the resource with terraform, or...
keep the resource un-templated, reference its resource ID as a parameter and get its metadata via a data element for terraform-managed resources that rely on it.
Is terraform import an alternative to those two approaches? And if so, why would you use that approach?
The only way to make changes to an imported resource (that only has an empty resource block in the .tf file and detailed state in .tfstate) is to make manual changes and then re-import into .tfstate`, right? And if so, then what's the point of tracking the state of that resource in terraform?
I'm sure there's a good reasons. Just want to understand this deeper! Thanks!
But it's still unclear to me what the purpose of a standalone .tfstate
file is when it only maps to an empty resource block.
You wouldn't use a standalone .tfstate file. You would be using the same .tfstate file that all your other resources are in.
If there is a resource not in terraform yet, I would typically do one
of two things:
put the resource in terraform, tear down the resource manually and re-deploy the resource with terraform, or...
keep the resource un-templated, reference its resource ID as a parameter and get its metadata via a data element for
terraform-managed resources that rely on it.
Is terraform import an alternative to those two approaches? And if so,
why would you use that approach?
Consider the case where you have a production database with terrabytes of data already load in it, and users actively performing actions that query that database 24 hours a day. Your option 1 would require some down time, possibly a lot of down time, because you would have to deal with backing up and restoring terrabytes of data. Your option 2 would never let you manage changes to your database server via Terraform. That's what the Terraform import feature solves. It lets Terraform take "full control" of resources that already exist, without having to recreate them.
I agree that if a system outage is not an issue, and if recreating a resource isn't going to take much time, using option 1 is the way to go. Option 2 is only for resources that you never want to fully manage in Terraform, which is really a separate issue from the one Terraform import solves.
When importing a resource with terraform import it is necessary to write the configuration block to manage it with Terraform. On the same page you linked it states:
The current implementation of Terraform import can only import resources into the state. It does not generate configuration. A future version of Terraform will also generate configuration.
Because of this, prior to running terraform import it is necessary to
write manually a resource configuration block for the resource, to
which the imported object will be mapped.
So to bring preexisting resources under Terraform management, you first write the resource block for it in a .tf file. Next you use terraform import to map the resource to this resource block in your .tfstate. The next time you run terraform plan, Terraform will determine what changes (if any) will need to be made upon the next terraform apply based on the resource block and the actual state of the resource.
EDIT
The "why" of terraform import is to manage resources that are previously unknown to Terraform. As you alluded to in your second bullet point, if you want metadata from a resource but do not want to change the configuration of the resource, you would use a data block and reference that in dependent resources.
When you want to manage the configuration of a resource that was provisioned outside of Terraform you use terraform import. If you tear down the resource there may be data loss or service downtime until you re-deploy with Terraform, but if you use terraform import the resource will be preserved.
The import process can be started with an empty resource block, but the attributes need to be filled out to describe the resource. You will get the benefits of terraform plan after importing, which can help you find the discrepancies between the resource block and the actual state of the resource. Once the two match up, you can continue to make additional changes to the resource like any other resource in Terraform.
Terraform state file is your source of truth for your cloud infrastructure. Terraform uses local state to create plans and make changes to the infrastructure. Before any terraform operation, terraform does a refresh to update the state with the real infrastructure.

Update existing app service with Terraform

in my Azure account a have some resources. Resource groups, app services, storage accounts...
I've created these resources by using the Azure portal or Powershell.
Then i've written a terraform script to add other resources and update some of the existing ones. In particular i'm interested in updating the app service. I want to add some settings and a managed identity to it.
What happens is that terraform says: "look, there is already an app service with the name you specified".
I tried to use "terraform import" to bind the existing app service to my terrafom state file, but doing so i loose the settings that i've put in the terraform file.
How can i solve this problem? Thank you.
terraform import is the way to go. If you have any existing settings in your file: Just remove them until you have fully imported the app service.
Full tutorial - with a resource group instead of an app service, but the principle is the same:
https://azurecitadel.com/automation/terraform/lab6/#lab-importing-resources
Create a resource group:
Grab the ID for the azure resource: id=$(az group show --name deleteme --query id --output tsv)
Create an empty stanza for the resource in a new import.tf file
resource "azurerm_resource_group" "deleteme" {}
Run the import command:
terraform import azurerm_resource_group.deleteme $id
terraform-labs$ terraform import azurerm_resource_group.deleteme $id
Acquiring state lock. This may take a few moments...
azurerm_resource_group.deleteme: Importing from ID "/subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/deleteme"...
azurerm_resource_group.deleteme: Import complete!
Imported azurerm_resource_group (ID: /subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/deleteme)
azurerm_resource_group.deleteme: Refreshing state... (ID: /subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/deleteme)
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.
Run terraform plan and you should see some errors as our block is not populated
Run terraform state show azurerm_resource_group.deleteme
id = /subscriptions/2d31be49-d999-4415-bb65-8aec2c90ba62/resourceGroups/deleteme
location = westeurope
name = deleteme
tags.% = 0
Add in the name argument, and the location using the loc variable
Rerun terraform plan and it should show no errors and no planned changes
The resource is now fully imported and safely under the control of Terraform.

Resources