Terraform Version Upgrade

Starting the blog with the question – What is Terraform?

It can be called a magic wand that creates Infrastructure on the basis of the code that you write. 

In Hashicorp’s words, “Terraform is an open-source Infrastructure as A Code software tool that enables you to safely and predictably create, change, and improve infrastructure.

Well coming to our topic, Terraform upgrade. Let’s see what ways we can follow to upgrade Terraform in an environment that is running on a lower Terraform version.

Scenario

Upgrade from Terraform v0.11.11 → latest version 

My reaction when I had to perform the upgrade activity:

There are basically 2 ways in which we can perform the upgrade, do let us know if you have come across any other ways in the comment.

  1. Upgrade to 0.11.14 if you are running a version lesser than that to move to 0.12.x version
  2. Take the state file of the current environment, and follow the blog to know further 😉 

GitHub link: https://github.com/prakashjha08/vpc-module

Module block:

provider "aws" {
  region  = "ap-south-1"
}

module "vpc" {
  source      = "[email protected]:prakashjha08/vpc-module.git?ref=main"
  # source = "./vpc"
  vpc_cidr    = "10.0.0.0/16"
  subnet_cidr = ["10.0.0.0/20", "10.0.16.0/20"]
  sg_name     = "tf-upgrade"
  ingress_rules = {
    "tcp,443,443" = "10.0.0.0/20,10.0.16.0/20"
    "tcp,1,65535" = "10.0.32.0/20,10.0.48.0/20"
    "tcp,80,80"   = "10.0.64.0/20,10.0.80.0/20"
  }
}

Option-1:

Terraform suggests installing version 0.11.14 at first to seamlessly move to further versions.

Let’s have a look.

To check the TF version → Use terraform -version command 

Download version 0.11.14 from https://releases.hashicorp.com/terraform/0.11.14/ 

Checking TF version

Terraform provides us with a command to check/instruct how to upgrade.

terraform 0.12checklist

Changes need to be made in the provider block.

provider "aws" {
  region = "ap-south-1"
  version = "~> 4.22.0"
}

Validation succeeds once you change the version, now we will have to download 0.12.31 as it supports AWS provider version ~> 4.22.0 and run terraform init, then terraform 0.12upgrade

And, you have successfully upgraded to v0.12.31!!

After upgrading to terraform 0.12.31, you will be able to see a few warnings related to interpolation as below

You can work on these, else, SPOILER ALERT!!, these errors will come back in the later versions.

Remove “${,}” and quoted types like “string” -> string

Install 0.13.5 and run terraform 0.13upgrade and terraform init

Install 0.14.0, move version constraint to required_providers block or remove the version argument and run terraform init and apply to update the state file.

You can directly upgrade to the latest version from here and run terraform init -upgrade

Congratulations, your infra is upgraded to the latest version.

That’s all about a straightforward upgrade.

Option-2:

I was working on an Infra, where the code in v0.11.11 was out of sync, in that case, we will have to use Option 2, which seems a little tricky as we will be seeing a new command, terraform import.

Terraform import helps you to import resources to state file that were created either manually or via some other IaC tools (Cloudformation, Pulumi, boto3, etc). Once the import is done, we will be able to manage the resources using Terraform, so apply destroy commands can be used.

Before importing, we need to make sure that a resource block already exists in the configuration files.

Syntax: 

  1. Import module: terraform import module.<module_name>.aws_vpc.<resource_name> <resource_id>
  2. Import resource: terraform import aws_vpc.<resource_name> <resource_id>

Module blocks were present on a git repository and were cloned on an EC2 Instance, from where it was getting managed.

I followed these steps on the instance:

  1. terraform show for the v0.11.11 state.
  2. Take the ID and resource names 
  3. Copied the output of terraform show and cloned the git repository to local
terraform show

I had to remove the interpolations(warnings) and quoted types(errors) from variables as they are not supported in the latest version.

Backend block for v0.11.11
Backend block for v1.2.2

Once you change the backend config in a different directory, you are good to go with the importing of resources that were created with earlier versions.

Importing VPC:
Command:
terraform import module.vpc.aws_vpc.vpc vpc-09b279ec86986776d
Output:
module.vpc.aws_vpc.vpc: Importing from ID "vpc-09b279ec86986776d"...
module.vpc.aws_vpc.vpc: Import prepared!
  Prepared aws_vpc for import
module.vpc.aws_vpc.vpc: Refreshing state... [id=vpc-09b279ec86986776d]

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.
Importing subnets:
Command:
terraform import module.vpc.aws_subnet.subnet[0] subnet-0b1829adb8d262da6
terraform import module.vpc.aws_subnet.subnet[1] subnet-0d2d485fab98d7d6c
Output:
module.vpc.aws_subnet.subnet[0]: Importing from ID "subnet-0b1829adb8d262da6"...
module.vpc.aws_subnet.subnet[0]: Import prepared!
  Prepared aws_subnet for import
module.vpc.aws_subnet.subnet[0]: Refreshing state... [id=subnet-0b1829adb8d262da6]


module.vpc.aws_subnet.subnet[1]: Importing from ID "subnet-0d2d485fab98d7d6c"...
module.vpc.aws_subnet.subnet[1]: Import prepared!
  Prepared aws_subnet for import
module.vpc.aws_subnet.subnet[1]: Refreshing state... [id=subnet-0d2d485fab98d7d6c]

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.
Importing security group and rules:
Command:
$ terraform import module.vpc.aws_security_group.sg sg-08ed5e41159e59299

$ terraform import module.vpc.aws_security_group_rule.ingress[0] sg-08ed5e41159e59299_ingress_tcp_1_65535_10.0.32.0/20_10.0.48.0/20

$ terraform import module.vpc.aws_security_group_rule.ingress[1] sg-08ed5e41159e59299_ingress_tcp_443_443_10.0.0.0/20_10.0.16.0/20

$ terraform import module.vpc.aws_security_group_rule.ingress[2] sg-08ed5e41159e59299_ingress_tcp_80_80_10.0.64.0/20_10.0.80.0/20

$ terraform import module.vpc.aws_security_group_rule.egress sg-08ed5e41159e59299_egress_all_0_0_0.0.0.0/0
Output:
module.vpc.aws_security_group.sg: Importing from ID "sg-08ed5e41159e59299"...
module.vpc.aws_security_group.sg: Import prepared!
  Prepared aws_security_group for import
module.vpc.aws_security_group.sg: Refreshing state... [id=sg-08ed5e41159e59299]

module.vpc.aws_security_group_rule.ingress[0]: Importing from ID "sg-08ed5e41159e59299_ingress_tcp_1_65535_10.0.32.0/20_10.0.48.0/20"...
module.vpc.aws_security_group_rule.ingress[0]: Import prepared!
  Prepared aws_security_group_rule for import
module.vpc.aws_security_group_rule.ingress[0]: Refreshing state... [id=sg-08ed5e41159e59299_ingress_tcp_1_65535_10.0.32.0/20_10.0.48.0/20]

module.vpc.aws_security_group_rule.ingress[1]: Importing from ID "sg-08ed5e41159e59299_ingress_tcp_443_443_10.0.0.0/20_10.0.16.0/20"...
module.vpc.aws_security_group_rule.ingress[1]: Import prepared!
  Prepared aws_security_group_rule for import
module.vpc.aws_security_group_rule.ingress[1]: Refreshing state... [id=sg-08ed5e41159e59299_ingress_tcp_443_443_10.0.0.0/20_10.0.16.0/20]

module.vpc.aws_security_group_rule.ingress[2]: Importing from ID "sg-08ed5e41159e59299_ingress_tcp_80_80_10.0.64.0/20_10.0.80.0/20"...
module.vpc.aws_security_group_rule.ingress[2]: Import prepared!
  Prepared aws_security_group_rule for import
module.vpc.aws_security_group_rule.ingress[2]: Refreshing state... [id=sg-08ed5e41159e59299_ingress_tcp_80_80_10.0.64.0/20_10.0.80.0/20]

module.vpc.aws_security_group_rule.egress: Importing from ID "sg-08ed5e41159e59299_egress_all_0_0_0.0.0.0/0"...
module.vpc.aws_security_group_rule.egress: Import prepared!
  Prepared aws_security_group_rule for import
module.vpc.aws_security_group_rule.egress: Refreshing state... [id=sg-08ed5e41159e59299_egress_all_0_0_0.0.0.0/0]

Once all the resources are imported, run the plan command to check if anything is getting changed/destroyed, resolve it, and apply the configuration.

So, Terraform upgrade is now completed with the import command.

Conclusion:

Key takeaways from this blog:

  1. How to upgrade the TF version
  2. Multiple terraform commands

Both the ways seem to work fine for upgrade, Option-1 is best suited for infrastructure that is in sync with the TF code, and Option-2 can be used to cut the middle versions out and directly import existing resources to new code.

The choice is yours. Hope this blog helps.

Time to go!

If you have come this far, a big shout-out to you. Thanks for reading the whole blog. 

Happy Learning! 🙂

Image References:

Blog Pundit: Bhupender rawat and Sandeep Rawat

Opstree is an End to End DevOps solution provider.

Connect Us

One thought on “Terraform Version Upgrade”

Leave a Reply