Creating a list from multiple resource attributes

This is probably really easy but I’m hitting a brick wall on how to do this, I know I’ll end up kicking myself if someone can offer a pointer.

As a little background, I’m working with Azure, and trying to get some resource attributes (specifically IP address & hostname) passed into a command for a VM extension resource (to add the IP/Name attributes from all VMs to the hosts file on each VM).

So, NIC resource outputs a ‘private_IP_Address’ and VM resource outputs a ‘name’ attribute. Easy way to get these for one resource is to create a local that references the attributes…
locals {
host = “{azurerm_network_interface.network_interface.private_ip_address} {azurerm_virtual_machine.virtual_machine.name}”
}

… and then add “${local.host}” to the “commandToExecute” in the ‘Settings Block’ of the VM Extension. This works and the IP address and name are added to the file.

However, the VM and NIC resources both have a Count value, so the deployment might require 3 VMs & NICs (or 10, or 2 etc). Clearly the example I gave above doesn’t scale with the number of VMs deployed.

I’ve tried various things with elements, count.index and ‘splats’ etc but they either just don’t seem to work (tuple value when string required) or I have to hard code the index value in the local being created (which again, doesn’t scale).

Any ideas greatly appreciated.

Thanks

Hi @bobbydazzler,

Unfortunately the forum didn’t understand your code example and has misinterpreted as math syntax :confounded: … using the <> icon in the toolbar to mark it as code might help, but I’m going to try to guess what your example said:

locals {
  host = "${azurerm_network_interface.network_interface.private_ip_address} ${azurerm_virtual_machine.virtual_machine.name}"
}

Assuming I got that right, we can adapt this to work with a resource that has count set by knowing that a count resource appears in expressions as a list, and that we can derive one list from another using for expressions:

locals {
  hosts = [
    for i in azurerm_network_interface.network_interface :
    "${i.private_ip_address} ${i.name}"
  ]
}

Or, if your goal was to generate a “hosts file” as a single string, a variant using Terraform’s string template syntax:

locals {
  hosts = <<-EOT
    %{ for i in azurerm_network_interface.network_interface ~}
    ${i.private_ip_address} ${i.name}
    %{ endfor ~}
  EOT
}

Both of these use a similar for syntax, but the second example is using string repetition in a template and thus producing a single string as the result, whereas the first example is using a normal for expression and thus deriving a new list with the same number of elements.