We want to do it right and do it right the first and every time, whether it is learning to play the guitar or to create software. Or whether it is creating a version-able, re-usable, repeatable, and testable approach to provisioning infrastructure on the cloud. AKA infrastructure as code.
And by the way, before you read any further, I am assuming that you understand how terraform and the AWS/Azure cloud infrastructure work together. To put it in one line, terraform configuration files contain information on the resources to provision in infrastructure providers such as AWS, Azure, etc.
This desire to provision resources using an IaC tool like terraform is fair and holds for most cases where infrastructure is being stood from the ground up. That is also known as a greenfield project -there was nothing, and then there was everything. However, there are times when infrastructure projects are not greenfield. There are times when infrastructure is partially or completely stood up using non-terraform based approach. And later, there might be a desire to convert that to terraform configuration to harness the benefits of IaC.
Well, no problem, I thought. I could quickly write up a terraform configuration project to provision resources. But when I started to execute the code (
terraform apply), I got an error -the resource by that name exists. Hmm. So I had a situation where cloud resources had already been provisioned using non-terraform based approach, and I was trying to find a way to create them using terraform.
I could think of a two options. Option A: I could delete the resource provisioned manually or provisioned using a non-terraform based approach. After deleting, I could execute the terraform configuration, and the resources would be provisioned correctly using the shiny new IaC approach. But what about situations where I could not or do not want to delete the cloud resource. It could be due to the effort that has already gone into creating the infrastructure, or it could be that the resources are currently in use and cannot be deleted. That brought me to Option B:
terraform import. Using the command, I no longer had to destroy the cloud resource and instead could import their current state into the terraform state file of the configuration. Hashicorp has documented this well at Terraform import. The link to the usage of this command is also helpful.
How did I go about using terraform import?
As suggested in the usage doc (link shared above), I created a terraform configuration for the cloud resources I was importing, and then I ran the
terraform plan command. I received the output that terraform would create all the resources specified in the terraform configuration. Well, that was because terraform did not know about the current state of infrastructure. Then I executed the
terraform import command.
Note: Are you familiar with the Terraform registry for AWS? There is an
import block for each resource type (scroll to the bottom of the page). The import command example displays how to identify a resource in the cloud infrastructure uniquely, e.g., name or id, and import that information into a terraform state.
On successful execution of the
terraform import command, I ran the
terraform plan command once again. And this time, I got the message:
No changes. Infrastructure is up-to-date. That is the desired end state of any terraform import project. That meant all existing cloud resources for which I had written terraform configuration have been imported into the terraform state file.
I’ll explain that via an example I worked on. I have an AWS account where I manually created the following cloud resources: a VPC, public subnets, a route table, route table associations, and an internet gateway. And as I mentioned earlier, the task at hand was to import them into terraform. So how did I go about that?
I classified the approach into six high-level steps, and they are as follows.
Step 1: Create a list of all the resources that have to be imported. These resources already exist.
In the above example, there were seven resources – a VPC, a couple of subnets, a route table, an internet gateway, and a couple of route table associations with the two subnets.
Step 2: Create a terraform configuration block for each resource.
I have the code checked-in at my Github repository terraform-import-aws-vpc
Step 3: Run
terraform plan. The output would include all the resources that terraform would have to provision.
terraform plan on the example above, terraform listed all the seven resources to create.
Note: If you are interested, open the
terraform.tfstate file and check that out. That would be pretty much empty since, as per terraform these resources do not exist yet. Close the state file because it will be referenced in the next step.
Step 4: Run
terraform import on one resource.
If successful, terraform would update the state file accordingly. Open the
terraform.tfstate file again and review if the resource state has been imported.
I imported the vpc using the
terraform import command. I have an image of that, along with the output I received.
Step 5: Run
terraform plan again.
This time the resource count should go down because the state file associated with the current terraform configuration is aware of the resource that was imported. And it did when I ran
terraform plan again.
Step 6: Repeat step 4 for the rest of the resources until all the resources are imported.
Once all the resources are imported, the last run of
terraform plan would display –
No changes. Infrastructure is up-to-date.
I could also run a
terraform apply that would not change anything since the terraform configuration, the state file, and the existing cloud infrastructure are all identical.
I noted that terraform deleted none of the cloud resources -their ids remained the same. Multiple runs of
terraform plan and
terraform apply resulted in no change -idempotent.
Once all the vpc changes were imported into a terraform configuration state file, I could manage (add, modify, remove) them using terraform. I also started realizing the benefits of infrastructure-as-code, namely, the consistent end state of infrastructure, re-usable modules, testable, version-controlled code even though, to begin with, these resources were not provisioned by terraform.
And that is how I learned about
terraform import. I hope you found this note helpful. Please let me know if there are any question or suggestions.