9
votes

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?

4

4 Answers

21
votes

Found an easy solution using the index function:

tags = { Name = "Company0${index(var.vpc_cidrs, each.value) + 1}" }
16
votes

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) }
}
6
votes

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) }
}
0
votes

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}" }
}