Upgrading to Terraform v0.14
Terraform v0.14 is a major release and thus includes some changes that you'll need to consider when upgrading. Current version we use is v0.11, so first upgrade to v0.13.
Using .terragrunt-version and .terraform-version to automatically switch based on folder
tgenv
and tfenv
support switching versions automatically based on a version file (.terragrunt-version
for tgenv
and .terraform-version
for tfenv
).
Explicit Provider Source Locations
In previous version, provider details are mentioned in main.tf. But now terraform requires explicit source information for any providers that are not HashiCorp-maintained, using a new syntax in the required_providers
nested block inside the terraform
configuration block.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.45.0"
}
}
}
provider aws {
profile = var.profile
region = var.region
}
Filling in remote state settings with Terragrunt
To fill in the settings via Terragrunt, create a terragrunt.hcl
file in the root folder, plus one terragrunt.hcl
file in each of the Terraform modules:
In your rootterragrunt.hcl
file, you can define your entire remote state configuration just once in a remote_state
block
remote_state {
backend = "s3"
config = {
encrypt = true
bucket = "wego-terraform-state-335280333914"
profile = "wego-staging-account"
region = "ap-southeast-1"
key = "aws/staging/ap-southeast-1/${path_relative_to_include()}/state.tf"
}
generate = {
path = "backend.tf"
if_exists = "overwrite_terragrunt"
}
}
In each of the childterragrunt.hcl
files, you can tell Terragrunt to automatically include all the settings from the root terragrunt.hcl
file
The include
block tells Terragrunt to use the exact same Terragrunt configuration from the terragrunt.hcl
file specified via the path
parameter
include {
path = find_in_parent_folders()
}
You can also specify dependencies in your terragrunt.hcl
config files using a dependencies
block
dependencies {
paths = [
"../../vpc",
"../../../../modules/databases/elasticache/common",
]
}
New feature : Provider Dependency Lock File
Terraform v0.14 introduces a new dependency lock file, which Terraform will generate automatically after running terraform init
in the same directory as your configuration's root module.
Challenges we faced while upgrading
Warning: Interpolation-only expressions are deprecated :
an expression like "${var.env}"
should be rewritten as just var.env
.
subdomain_prefix = "${var.env}"
subdomain_prefix = var.env
Quoted type constraints are deprecated:
In a variable
block, a type constraint "string"
as just string
.
type = "string"
type = string
Quoted references are deprecated:
In the depends_on
and ignore_changes
meta-arguments, quoted references should be rewritten without the quotes.
ignore_changes = [
"container_definitions",
container_definitions,
]
Working with count
on resources :
count
-related change is that Terraform now requires count
to be assigned a numeric value, and will not automatically convert a boolean value to a number in the interests of clarity. If you wish to use a boolean value to activate or deactivate a particular resource, use the conditional operator to show clearly how the boolean value maps to a number value:
count = var.enabled ? 1 : 0
Referring to List Variables :
In early versions of Terraform, before list support became first-class, we required using seemingly-redundant list brackets around a single expression in order to hint to the language interpreter that a list interpretation was desired:
example = ["${var.any_list}"]
The upgrade version is able to recognize most simple usage of this pattern and rewrite automatically to just refer to the list directly:
example = var.any_list
Provider configuration not found :
After upgrade, when I try to run terragrunt plan
, I got this Provider configuration not found
error :
terraform state replace-provider registry.terraform.io/-/aws hashicorp/aws
State file related issues :
Two issue we face with state file are
- State file present in wrong path, which tend to create all the resources
- Naming standard issue. Previous it was servicename.tf but now changed to state.tf for uniformity. so we need to rename the file to state.tf and place it right path.
changes done with parameter group name :
Database version keeps changing due to minor versioning enabled. So we included only major version in parameter group name.
resource "aws_db_parameter_group" "wego_fares_db_pg" {
name = "${var.name}-db-pg-${replace(var.engine_version, ".", "")}"
name = "${var.name}-db-pg-${element(split(".", var.engine_version),0)}"
Using dynamic block to add multiple listener :
Terraform now includes a first-class feature for dynamically generating nested blocks using expressions, using the special dynamic
block type
dynamic "listener" {
for_each = var.listeners
content {
instance_port = lookup(listener.value, "instance_port", null)
instance_protocol = lookup(listener.value, "instance_protocol", null)
lb_port = lookup(listener.value, "lb_port", null)
lb_protocol = lookup(listener.value, "lb_protocol", null)
ssl_certificate_id = lookup(listener.value, "ssl_certificate_id", null)
}
}
Dashboard into Dynamic Block for Datadog
Previously, the dashboard can be created like below:
widget = "${local.variable]}"
but in V0.14, block type as been introduced. Ex:
dynamic widget {
for_each = local.group_definitions
content {
group_definition {
layout_type = widget.value.layout_type
# title = widget.value.title
dynamic widget {
for_each = widget.value.query_widgets
content {
query_value_definition {
title = widget.value.title
text_align = widget.value.text_align
autoscale = widget.value.autoscale
precision = widget.value.precision
dynamic request {
for_each = widget.value.request
content {
# display_type = request.value.display_type
q = request.value.q
aggregator = request.value.aggregator
dynamic conditional_formats {
for_each = request.value.conditional_formats
content {
comparator = conditional_formats.value.comparator
value = conditional_formats.value.value
palette = conditional_formats.value.palette
}
}
}
}
}
}
}
}
Listener rule priority changes:
we updated the priority of listener rule via aws cli.
/bin/bash
random_pripority=2
while IFS="," read -r col1 col2 col3 col4
do
# set the actual pripority based on csv file
aws elbv2 set-rule-priorities --profile wego-staging-account --region ap-southeast-1 --rule-priorities RuleArn=$col1,Priority=$col4
aws elbv2 set-rule-priorities --profile wego-staging-account --region ap-southeast-1 --rule-priorities RuleArn=$col2,Priority=$col4
done < alb.csv
Plan and apply in Atlantis :
Atlantis does not support Terraform v0.13. So first need to upgrade Terraform v0.13 in local and push the code to remote. Then plan and apply in Atlantis for Terraform v0.14. We need to remove the terraform lock file before pushing the code to remote.