2
votes

I am using terraform version 0.14.3. I have a module for creating an Azure Network Interface Card, as below:

resource "azurerm_network_interface" "nic" {

  name                = var.nic_name
  location            = var.location
  resource_group_name = var.rg_name

  ip_configuration {
    name                          = var.ipconfig_name
    subnet_id                     = var.subnet_id
    private_ip_address_allocation = "Dynamic"
  }
}

Its output is defined as :

output "nic_id" {
     value = azurerm_network_interface.nic.id 
}

I am calling this module in this parent module:

module "NIC" {
  source = "./NIC"
  for_each = var.nics

  nic_name      = each.value.nic_name
  location      = "eastus2"
  rg_name       = "abc-test-rg"
  ipconfig_name = each.value.ipconfig_name
  subnet_id     = <subnet_id>
}

output "nic_ids" {
  value = [for k in module.NIC.nic_id : k.id]
} 

The NIC values are defined as below:

nics = {
  nic1 = {
    nic_name      = "abc-nic-1"
    ipconfig_name = "nic-1-ipconfig"
  }
}

I want to loop around the NIC output IDs, and want them displayed. When I run above code, I get below error in terraform plan :

Error: Unsupported attribute

  on main.tf line 15, in output "nic_ids":
  15:   value = [for k in module.NIC.nic_id : k.id]
    |----------------
    | module.NIC is object with 1 attribute "nic1"

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

How do I get around it ?

1

1 Answers

4
votes

Your module "NIC" block has for_each set, and so the module.NIC symbol elsewhere in the module is a mapping from instance keys to output objects, rather than just a single output object as for a singleton module.

Terraform's error message is attempting to draw attention to that with the following message:

  • module.NIC is object with 1 attribute "nic1"

Notice that nic1 here is a key from your var.nics, and not one of the output values defined in your module.

Assuming that the nic_id output you showed here is the only one defined in that module, the module.NIC value would be shaped something like this:

{
  nic1 = {
    nic_id = "eni-e5aa89a3"
  }
}

It sounds like you instead want to produce a value shaped like this:

{
  nic1 = "eni-e5aa89a3"
}

If so, a suitable expression to get that result would be the following:

output "nic_ids" {
  value = { for k, nic in module.NIC : k => nic.nic_id }
} 

The above means: produce a mapping with one element for each instance of the NIC module, whose key is the module instance key and whose value is the nic_id output value.

Alternatively, if it doesn't matter which id belongs to which instance then you could produce an unordered set of ids, like this:

output "nic_ids" {
  value = toset([for nic in module.NIC : nic.nic_id])
} 

In this case the for expression only defines a local symbol nic, which represents the module instance object, because it doesn't do anything with the instance key. The toset here is to represent that the IDs are not in any particular order: that isn't strictly necessary but I think it's a good practice to make sure that any other Terraform code depending on that value doesn't inadvertently depend on the current arbitrary ordering of the ids, which might change in future if you add or remove elements in var.nics.