
Now that we understand what Terraform State is, how do we manipulate it, and when should we? Most of the time you shouldn't touch state at all, since keeping it correct is the job of your Terraform code. But sometimes you don't have a choice, or you want to test out a particular scenario. That's when state manipulation comes into play.
First let's look at the terraform state CLI command. It comes with 7 subcommands:
list - list all resources within the state filemv - move an item within the state filepull - pull the current state file and output it to our terminalpush - update remote state from a local state filereplace-provider - replace a provider within the state filerm - remove a resource from our state fileshow - show a single resource within the state fileGenerally I use list and show fairly frequently to interrogate what's in the state file, especially if it is a new codebase that I am looking at.
The rm subcommand can also be very useful if someone has been unkind enough to remove a resource (e.g. from the Azure portal). This allows us to remove that reference in state so that Terraform won't complain, although if we don't also remove it from the code, Terraform will try to create it on the next apply.
Here are some scenarios and how we would resolve them:
This comes up fairly often during development on larger projects. Say you've built an entire cloud environment and now you want to recreate the network. taint lets you do that. The alternatives are deleting the resource by hand or commenting the code out, and neither is a good option.
# Find the resource in state
terraform state list
# Inspect the resource
terraform state show azurerm_virtual_network.this
# Taint the resource
terraform taint azurerm_virtual_network.thisOn the next terraform apply the azurerm_virtual_network.this will be recreated. If you change your mind and no longer require the resource to be tainted then you can use the aptly named untaint command.
terraform untaint azurerm_virtual_network.thisSometimes we define all of our resources in our Terraform code but for some reason the resource is manually created. This leaves us in a state where Terraform can see the resource on the remote end and in its code but not in state. In order to fix that we need to import the resource into state. This is where the import command comes into play. (For the full, modern import workflow, including import {} blocks, code generation, and bulk imports, see the Terraform import guide.)
As an example we are going to import the above virtual network into our state file.
terraform import azurerm_virtual_network.this /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/Resource_Group/providers/Microsoft.Network/virtualNetworks/Virtual NetworkAs you can see from the above the import process is pretty simple, we simply need to pass in the address in Terraform state and the ID that is used for the resource. This will be different between providers.
This happens as our Terraform code grows. We might start with a single instance of something and then move to multiple instances through the use of the for expression or through creation of a module. To tell Terraform that we want to move our currently existing resource into one of those constructs we can either use the moved block or the Terraform mv command. Here's an example.
# `for` expression
terraform mv azurerm_virtual_network.this azurerm_virtual_network.this["primary"]
# Module
terraform mv azurerm_virtual_network.this module.virtual_networks.azurerm_virtual_network.thisIn this instance we want to force our state to go and check what the real state of our resources is and update state with any changes. This can be done with a very simple command.
terraform refreshThis post covered the basics of working with Terraform state: tainting and untainting a resource, moving a resource to a new address, importing existing resources, and refreshing state from the resource APIs. There's more you can do, but this is about as much as you should be doing in state for 95% of cases. As a general rule of thumb, if you're editing a state file by hand, you're doing something wrong.
