Now that we have a basic understanding of how Terraform states work, let us take a look at some of the Terraform CLI commands which come in handy to work with the same. We shall also take a look at the significance of these commands and why one should be familiar with them.
To refer to the example code, refer to this commit.
Imagine a scenario, where the resources are created but they have some unexpected settings or configurations which are not favorable to the overall scheme of things. In such cases, the obvious choice is to recreate that particular resource instead of recreating the entire stack.
To fulfill this situation, Terraform performs something called “tainting” of the resource. terraform taint command helps to manually mark resources as tainted.
Tainting resources happens in the Terraform state file. Terraform does not perform any operation on the actual resources themselves. As a result of this, the next time you run the terraform plan, it would indicate that one resource will be destroyed and another will be created in its place. Terraform plans this change for all the tainted resources.
Let’s say other resources depend on a certain attribute of the tainted resource. In that case, Terraform plans rebuilding of those resources as well, if required. Meaning if the configuration change is possible without rebuilding, then those resources will not be rebuilt.
Tainting of the resource is done manually by running the command as below.
terraform taint <resource identifier>
In our example, we are creating 2 resources by the names “demo_vm_1” and “demo_vm_2”. Initialize the root directory and run the terraform plan.
As expected, it gives us an output saying, 2 resources to add, and in the output, it is going to provide us with an instance id assigned by AWS. Apply this configuration to create 2 EC2 instances and note the output. In my case, I was assigned the below IDs for 2 different instances.
Apply complete! Resources: 2 added, 0 changed, 0 destroyed. Outputs: instance_id_1 = "i-02506cc9073afe093" instance_id_2 = "i-059e81b2cbc09f400"
Let us assume, we understand that instance 2 was not created properly and we want to mark it as tainted. Run the below command to mark instance_id_2 as tainted.
terraform taint aws_instance.instance_id_2
Terraform confirms the action by outputting below:
Resource instance aws_instance.demo_vm_2 has been marked as tainted.
At this point, if we run the terraform plan, it would give an output something like below. It plans to delete the tainted resource, recreates it, and then output the new ID of the recreated EC2 instance.
Plan: 1 to add, 0 to change, 1 to destroy. Changes to Outputs: ~ instance_id_2 = "i-059e81b2cbc09f400" -> (known after apply) ------------------------------------------------------------------------ Note: You didn't specify an "-out" parameter to save this plan, so Terraform can't guarantee that exactly these actions will be performed if "terraform apply" is subsequently run.
Also, observe the state file at this point. In the resources section, demo_vm_2 is marked with an additional property - “status”: “tainted”.
Let us go ahead and run terraform apply. As expected, it prints the output with 2 instance IDs. Since only one resource was rebuilt. Notice that the ID assigned by AWS is different for instance_id_2 but the same for instance_id_1.
Apply complete! Resources: 1 added, 0 changed, 1 destroyed. Outputs: instance_id_1 = "i-02506cc9073afe093" instance_id_2 = "i-092ea5f280dc558c9"
That’s about the taint command. Of course, we can un-taint the resources by running below command and everything will be back to normal.
terraform untaint aws_instance.demo_vm_2
Renaming and Removal
Terraform trusts and relies completely on the state file. The state file is a representation of real-world deployment. Terraform “manages” real-world infrastructure with the help of states. Sometimes, managing resources requires renaming and removing items from the state.
Terraform achieves this using commands which are very similar to file system management commands - mv and rm.
mv is used to move items from one state to another, or it can also be used to simply rename the items and update the state file. rm is used to remove a certain item from Terraform state management.
These commands work purely from the state file perspective and no changes take place to the real infrastructure. Let us use the same example and try to rename a resource. Currently, we have created 2 VMs whose identifiers are demo_vm_1 and demo_vm_2. We have a requirement to change the name of demo_vm_1 to special_vm.
But before we go ahead and use terraform mv command, take a note of actual EC2 instances in your AWS management console as well as the Terraform state file. In the state file, note the name attributes of the same.
Run the below command to satisfy our requirement:
terraform state mv aws_instance.demo_vm_1 aws_instance.special_vm
Below output is generated. Note that, nothing has changed with actual resources on AWS. Take a look at the state file again, and notice the demo_vm_1 does not exist in it, instead, special_vm exists with the same attributes.
Move "aws_instance.demo_vm_1" to "aws_instance.special_vm" Successfully moved 1 object(s).
We have only made this change in the state file and NOT in the configuration. If we run terraform plan at this point, it treats this as a change in the configuration which triggers deletion of “special_vm”, and triggers the creation of “new” demo_vm_1.
But this is not true since all we wanted to do was to rename the resource. This is one of the limitations as of now and we experienced the same behavior when we tried to import the pre-existing resources into Terraform state for management. Here, to align things correctly, do the changes to the configuration - change aws_instance.demo_vm_1 to aws_instance.special_vm.
Run terraform plan again and check the same this time. No changes should be required.
Similarly, we can also remove the configuration from Terraform management by running the rm command as below.
terraform state rm aws_instance.special_vm
Running the above command removes special_vm from the state file. Having done this, Terraform no longer associates the existence of configuration code written for special_vm in our main.tf file with anything in the state file. Thus, running the terraform plan proposes a plan to create another VM.
Here it is up to us to keep the configuration for special_vm, or completely get rid of it. To completely get rid of it, remove the corresponding configuration from .tf files, and run the plan again.
Make sure to check the output of the terraform plan after this and also observe the state files.
Please note that mv and rm commands are applicable not just for resources but also for modules, providers, etc. We would learn about modules in the next post.