Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform get list index on for_each

Tags:

terraform

Terraform newbie here. I'd like to iterate a list using for_each, but it seems like the key and value are the same:

provider "aws" {
  profile = "default"
  region  = "us-east-1"
}

variable "vpc_cidrs" {
  default = ["10.0.0.0/16", "10.1.0.0/16"]
}

resource "aws_vpc" "vpc" {
  for_each             = toset(var.vpc_cidrs)
  cidr_block           = each.value
  enable_dns_hostnames = true
  tags                 = { Name = "Company0${each.key}" }
}

I'd like the tag Name to be "Name" = "Company01" and "Name" = "Company02" but according to terraform apply, I get: "Name" = "Company010.0.0.0/16" and "Name" = "Company010.1.0.0/16" What am I missing?

like image 640
Moshe Avatar asked Apr 21 '20 12:04

Moshe


4 Answers

Found an easy solution using the index function:

tags = { Name = "Company0${index(var.vpc_cidrs, each.value) + 1}" }
like image 175
Moshe Avatar answered Oct 18 '22 21:10

Moshe


There is also another way of achieving the wanted result without using index():

change the following three lines:

for_each   = { for idx, cidr_block in var.vpc_cidrs: cidr_block => idx}
cidr_block = each.key
tags       = { Name = format("Company%02d", each.value + 1) }
  • the for_each will use a map of cidr_block to index mapping as returned by for
  • the cidr_block can then just use the each.key value
  • and in the tags also use format() on each.value to have a two digit with leading zeros of the index

Full example will be:

provider "aws" {
  profile = "default"
  region  = "us-east-1"
}

variable "vpc_cidrs" {
  default = ["10.0.0.0/16", "10.1.0.0/16"]
}

resource "aws_vpc" "vpc" {
  for_each             = { for idx, cidr_block in var.vpc_cidrs: cidr_block => idx}
  cidr_block           = each.key
  enable_dns_hostnames = true
  tags                 = { Name = format("Company%02d", each.value + 1) }
}
like image 27
mariux Avatar answered Oct 18 '22 21:10

mariux


When for_each is used with a set, each.key and each.value are the same.

To generate strings like "Company01", "Company02", etc., you need the index of each CIDR block in the list. One way to do this is to create a local map using a for expression like:

locals {
  vpc_cidrs = {for s in var.vpc_cidrs: index(var.vpc_cidrs, s) => s}
}

resource "aws_vpc" "vpc" {
  for_each             = local.vpc_cidrs
  cidr_block           = each.value
  enable_dns_hostnames = true
  tags                 = { Name = "Company0${each.key}" }
}

As a bonus, you can use the format function to build the zero-padded name string:

resource "aws_vpc" "vpc" {
  ...
  tags                 = { Name = format("Company%02d", each.key) }
}
like image 7
Max Smolens Avatar answered Oct 18 '22 22:10

Max Smolens


You could use the count function and use the index to do this:

provider "aws" {
  profile = "default"
  region  = "us-east-1"
}

variable "vpc_cidrs" {
  type = list(string)
  default = ["10.0.0.0/16", "10.1.0.0/16"]
}

resource "aws_vpc" "vpc" {
  count = length(var.vpc_cidrs)
  cidr_block           = var.vpc_cidrs[count.index]
  enable_dns_hostnames = true
  tags                 = { Name = "Company0${count.index}" }
}
like image 1
Peter Arboleda Avatar answered Oct 18 '22 21:10

Peter Arboleda