Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting unsupported attribute error in terraform when using for_each expression

Tags:

terraform

Using for_each expression in Terraform v0.12.6 to dynamically generate inline blocks of vnet subnets (Azure). I have list variable 'subnets' defined, with two subnets 'sub1' and 'sub2' as below

variable "subnets" {
  default = [
    {
      name   = "sub1"
      prefix = "1.1.1.1/32"
    },
    {
      name   = "sub2"
      prefix = "2.2.2.2/32"
    },
  ]
}

then iterate over list variable inside "azurerm_virtual_network" block to create dynamic blocks of subnets

dynamic "subnet" {
    for_each = [for s in var.subnets  : { 
        name   = s.name
        prefix = s.prefix
    }]

    content {
      name           = subnet.name
      address_prefix = subnet.prefix
    }   
  }
}

Getting i.e. first one is Error: Unsupported attribute

on main.tf line 42, in resource "azurerm_virtual_network" "vnet": 42: name = subnet.name

This object does not have an attribute named "name".

like image 980
irom Avatar asked Mar 03 '23 14:03

irom


1 Answers

The iterator object created for a dynamic block has two attributes:

  • key: the map key or list index of the current element
  • value: the value of the current element

In this case, the collection being used for repetition is a list of objects, so subnet.key will be integer indices 0, 1, ... and subnet.value will be the object associated with that index.

To get the result you were looking for, you'll need to access the object attributes on subnet.value instead:

dynamic "subnet" {
    for_each = [for s in var.subnets  : { 
        name   = s.name
        prefix = s.prefix
    }]

    content {
      name           = subnet.value.name
      address_prefix = subnet.value.prefix
    }   
  }
}

It seems like var.subnets is already compatible with the object structure the content block expects, so it may be possible to simplify this further by accessing it directly:

dynamic "subnet" {
    for_each = var.subnets

    content {
      name           = subnet.value.name
      address_prefix = subnet.value.prefix
    }   
  }
}

As long as var.subnets is a list of objects already, this should produce an identical result.

like image 129
Martin Atkins Avatar answered May 05 '23 12:05

Martin Atkins