Automation is one of the key aspects of provisioning an infrastructure since it saves a lot of time and money. There is always a need to create an infrastructure from code and scripts (the best examples might be CloudFormation and Terraform), but what if a standard infrastructure is already in place and one wants to replicate or convert the same infrastructure to code? Therefore, we came across two tools, aws2tf, and Terraformer, that help us do that. This blog gives a walkthrough of a basic example where we create a .tf file from an existing EC2 instance in the AWS console.
Terraformer
Terraformer is a CLI tool to convert your existing infrastructure to tf/json and tfstate files. The supported providers include major cloud like AWS, Azure, AliCloud, and IBM Cloud. The tfstate file has information about the provisioned infrastructure the terraform manages.
Terraformer supports terraform 0.13. To upgrade resources with new fields, upgrade the relevant Terraform providers.
How to install Terraformer
Follow the link here to install Terraformer according to the OS you prefer. If you are using Windows, install via Chocolatey.
Care should be taken that you have Terraform installed and added to the path variables (Windows).
Check for installation:
$ terraformer version
Terraformer v0.8.13
Terraformer Example
In this example, we will launch a simple EC2 instance in the AWS console and generate terraform files from the infrastructure. We give the Instance a “Name” tag with the value “terraformer.”
Create an empty folder to store the generated files. Open cmd inside this folder, and enter the following command:
terraformer import aws –resources=ec2_instance –filter=\”Name=tags.Name;Value=Terraformer\” –regions=us-east-1
The above command highlights two important things, — the resources parameter and the –filter parameter. The resources parameter indicates the name of the service that needs to be imported. We use –resources=\”*\”, and when using the “*” if there is a service that needs to be excluded, then –resources=\”*\” –excludes=\”iam\”.
With the –filter parameter, one can choose which resource Terraform imports. The filters work with resource identifiers or attributes, and multiple filtering values are separated by ‘:’. The resource identifier should be wrapped in “ ‘ ” if it contains’:. ‘ Identifier-based filters will be executed before Terraformer tries to refresh the remote state.
Filtering also has a Type option; this helps in filtering several types of resources. Also, multiple filters can be combined when importing different resource types. For example:
terraformer import aws -r sg,vpc –filter Type=sg;Name=vpc_id;Value=VPC_ID –filter Type=vpc;Name=id;Value=VPC_ID
The sg Name is different for both the filtering options.Furthermore, filtering is based on Terraform resource ID patterns. For valid ID patterns for your resources, refer Terraform documentation here. Example:
terraformer import aws –resources=vpc,subnet –filter=vpc=myvpcid –regions=us-east-1
After the brief introduction to the filtering and resources parameters, we will try to create a tf file from a simple EC2 infrastructure we created earlier with the Instance “Name” tag with value “terraformer”.
First, we go to the directory where we want all the files generated from Terraformer. Then, enter the below command:
terraformer import aws –resources=ec2_instance –filter=\”Name=tags.Name;Value=terraformer\” –regions=us-east-1
Upon entering the command chooses from the ec2 instance resource, filters the instance with tag terraformer from us-east-1 region.The respective terraform files are generated in the directory where terraformer import is run. For me here, that directory is “terraformer_poc”. So, the files generated by terraformer will be inside generated/aws/ec2_instance. If terraformer import is done other resources, then the tf files are generated with their respective resource names as shown below:We can see a new instance.tf file is created along with other files.
Reuploading The Terraformer File Created
Let us try uploading the instance.tf created by terraformer and see if we can directly create the exact same resource from the .tf file.
Below is the instance.tf file which was generated from terraformer:
resource \"aws_instance\" \"tfer--i-002D-xxxxxxxxxxxxxxxxxxxx_terraformer\" { ami = \"ami-0e1d30f2c40c4c701\" associate_public_ip_address = \"true\" availability_zone = \"us-east-1a\" capacity_reservation_specification { capacity_reservation_preference = \"open\" } cpu_core_count = \"1\" cpu_threads_per_core = \"1\" credit_specification { cpu_credits = \"standard\" } disable_api_termination = \"false\" ebs_optimized = \"false\" enclave_options { enabled = \"false\" } get_password_data = \"false\" hibernation = \"false\" instance_initiated_shutdown_behavior = \"stop\" instance_type = \"t2.micro\" ipv6_address_count = \"0\" key_name = \"xxxxxxxx\" metadata_options { http_endpoint = \"enabled\" http_put_response_hop_limit = \"1\" http_tokens = \"optional\" instance_metadata_tags = \"disabled\" } monitoring = \"false\" private_ip = \"10.10.x.xxx\" root_block_device { delete_on_termination = \"true\" encrypted = \"false\" tags = { Name = \"aw2tfsqs\" } resource \"aws_instance\" \"tfer--i-002D-xxxxxxxxxxxxxxxxxxxx_terraformer\" { ami = \"ami-0e1d30f2c40c4c701\" associate_public_ip_address = \"true\" availability_zone = \"us-east-1a\" capacity_reservation_specification { capacity_reservation_preference = \"open\" } cpu_core_count = \"1\" cpu_threads_per_core = \"1\" credit_specification { cpu_credits = \"standard\" } disable_api_termination = \"false\" ebs_optimized = \"false\" enclave_options { enabled = \"false\" } get_password_data = \"false\" hibernation = \"false\" instance_initiated_shutdown_behavior = \"stop\" instance_type = \"t2.micro\" ipv6_address_count = \"0\" key_name = \"xxxxxxx\" metadata_options { http_endpoint = \"enabled\" http_put_response_hop_limit = \"1\" http_tokens = \"optional\" instance_metadata_tags = \"disabled\" } monitoring = \"false\" private_ip = \"10.10.x.xxx\" root_block_device { delete_on_termination = \"true\" encrypted = \"false\" tags = { Name = \"aw2tfsqs\" } volume_size = \"8\" volume_type = \"gp2\" } source_dest_check = \"true\" subnet_id = \"subnet-xxxxxxxxxxxxxxxxxxxx\" tags = { Name = \"terraformer\" } tags_all = { Name = \"terraformer\" } tenancy = \"default\" vpc_security_group_ids = [\"sg-xxxxxxxxxxxxxxxxxxxx\"] } volume_size = \"8\" volume_type = \"gp2\" } source_dest_check = \"true\" subnet_id = \"subnet-xxxxxxxxxxxxxxxxxxxx\" tags = { Name = \"terraformer\" } tags_all = { Name = \"terraformer\" } tenancy = \"default\" vpc_security_group_ids = [\"sg-xxxxxxxxxxxxxxxxxxxx\"] }
When you run “terraform plan” after initializing Terraform inside this directory (terraform init), there will an output saying that there are no changes in the infrastructure, this proves that there is a correct “replication” of the infrastructure to the instance.tf, as shown below:Now, let’s delete the instance we created the Name tag “terraformer” and try to create infrastructure FROM code via the terraformer created instance.tf file.
After deleting, run “terraform plan” once again. This will detect changes and informs that there is a Plan: 1 to add, 0 to change, 0 to destroy. This indicates that there is a resource to be added.
Now run “terraform apply”. When the process is complete, it ends in an error as shown below: So, this shows us that the instance.tf file generated by terraformer has to modify for reusability.
Conclusion
After going through a basic example of terraformer, i.e., creating a basic EC2 instance terraform file, it is evident that terraformer does indeed have the capacity to convert the infrastructure into code which is acknowledged by Terraform (“terraform plan”). However, going through a more complex architecture remains to be seen, which will be explored in further blogs based on this topic. Also, another advantage of using this CLI tool is that one can also look at some best practices about terraform file creation.