Terraform 13 - for_each - Test Drive

3 minute read

"Buy Me A Coffee"

๐Ÿš€Terraform 0.13 is the new trend in the Terraform world IaC and one of the new features is the most wanted for_each๐Ÿš€.

I have all my Azure infrastructure currently deployed using Terraform 12. Given we already got v13 which judging for the number indicates it maybe unlucky, but 2020 cannot be beaten with the unlucky connotation๐Ÿ˜‚

## Why a for_each is great for modules

This allows me to define multiple instances in one block by using a map and of course leveraging the moduleโ€ฆ so the amount of code is reduced considerably

I decided to start modifying my infrastructure to take advantage of this new features and today I started with the for_each one you can refer to Terraform 13 Changelog to find more information about those new changes.

In this case I have a Resource group module which I was calling n times the number of Resource Groups I was creating for my infrastructure which in my case it was 9. Something like this ๐Ÿ”ฝ

module "rg-dmz" {
  source             = "../modules/resource_group"
  name_suffix        = "dmz"
  location           = var.location
  full_env_code      = local.full_env_code
  create             = true
  enable_delete_lock = false
}

module "rg-app" {
  source             = "../modules/resource_group"
  name_suffix        = "app"
  location           = var.location
  full_env_code      = local.full_env_code
  create             = true
  enable_delete_lock = false
}
.
.
.
.
n times the number of RG's required

Modifications required

I started modifying my code to be more "efficient" and "dynamic" by modifying my current deployment and leveraging the for_each as per below. This allows me to define multiple intances in one block by using a map and of course using leveraging the moduleโ€ฆ so the amount of code is reduced considerably. More information about using for_each

module "rgs" {
  for_each = {

    rg-dmz        = "dmz"
    rg-app        = "app"
    rg-services   = "services"
    rg-management = "management"
    rg-data       = "data"
    rg-network    = "network"
    rg-packer     = "packer"
  }

  source             = "../modules/resource_group"
  name_suffix        = each.value
  location           = var.location
  full_env_code      = local.full_env_code
  create             = true
  enable_delete_lock = false
}

State resource reorg

After I made the changes and run a plan, I found a new challenge and it was of course the new resources did not match the information in my state file ๐Ÿƒโ€โ™‚๏ธ๐Ÿƒโ€โ™‚๏ธ๐Ÿƒโ€โ™‚๏ธ๐Ÿƒโ€โ™‚๏ธ๐Ÿƒโ€โ™‚๏ธ run!!!! Some inspection was required and start doing the needfuls(got this word in my head BT). However, I was having issues doing the state movement; I was getting the error below ๐Ÿ˜ฅ

 terraform state mv module.rg-packer.azurerm_resource_group.rg  module.rgs["rg-packer"].azurerm_resource_group.rg                                     

Error: Index value required

  on  line 1:
  (source code not available)

Index brackets must contain either a literal number or a literal string.

Releasing state lock. This may take a few moments...

I started doing some quite powerful investigation (googling) and found in the terraform documentation how to terraform state mv using for_eachโ€ฆ so depending on which terminal are you using you will have to use different syntaxis for the state movement. In my current case, I was using PowerShell during this process hence I did the below

terraform state mv 'module.rg-packer.azurerm_resource_group.rg[0]' 'module.rgs_mel[\"rg-packer\"].azurerm_resource_group.rg[0]'

โ€ฆ..and wolla ๐Ÿ’ƒ!!,, state movement successful. I did the same for the rest of my resources :)

image-center

Calling the module outputs

After my state migration was completed and run a plan to ensure all was good. I faced another needful and it was to replace all the statements where I was consuming my module outputs. Something like this!!!

resource "azurerm_app_service_plan" "various" {
  name                = "azure-functions-cero-service-plan"
  location            = var.location
  resource_group_name = module.rgs["rg-management"].name #using the for_each module output
  kind                = "FunctionApp"
  reserved            = true

  sku {
    tier = "Dynamic"
    size = "Y1"
  }
}

The no changes expected ๐Ÿ‘ผ

Given all those changes were made the expected outcome was to not have any planned changes as we were only redesigning code. After my plan went as expected I run my Terraform Cloud workspace to apply my changes and the result was ๐Ÿง™โ€โ™‚๏ธ

image-center

Summary

Terraform v13 is offering quite good new features that if you have been working with terraform for a while you were willing to have. Ovbiusly, the process for migrating current infrastructure to v13 is not quite straightforward. However, in the end this will be making your code management easier. I will be modifying my current code to leverage all the v13 features so I hope I can keep sharing my small progresses. I hope this helps someone, Hasta la vista!!!

๐Ÿšดโ€โ™‚๏ธ If you enjoyed this blog, you can empower me with some caffeine to continue working in new content ๐Ÿšดโ€โ™‚๏ธ.

"Buy Me A Coffee"

Comments