Collecting one variable from resource with for_each

Hello

May be I do something complete wrong but is there any way to collect one variable of resources to list.
I have very simple custom provider for solarwinds ipam to set/remove IP reservation which have one resource swm_ip_reservation with several arguments (ipam host, user, password, vlan, etc…) and one Computed argument ip_addr - which populated by provider after successful IP reservation.

Like this in provider code:

            "ip_addr": &schema.Schema{
                Type:    schema.TypeString,
                Computed: true,

I need to put this output variables of module and while this work for one resource it doesn’t work for several.

Simple tf for test:

output managed_ip {
	value = swm_ip_reservation.test1[*]
}

variable hosts {
	type = set(string)
	default = ["host1.example.com", "host2.example.com"]
}

resource "swm_ip_reservation" "test1" {
	for_each = var.hosts
	ipam_user = "user"
	ipam_pass = "password"
	ipam_host = "ipam.example.com"
	
	vlan = 123
	hostname = each.key
}

In this case I have all values from resource including computed value. If I change output to swm_ip_reservation.test1["host1.example.com"].ip_addr terraform successfully returns output variable with only ip_addr.

Changing to swm_ip_reservation.test1[*].ip_addr gives me error:

    Error: Unsupported attribute

      on main.tf line 2, in output "managed_ip":
       2: 	value = swm_ip_reservation.test1[*].ip_addr

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

Tried different approaches to convert however I think I missing something

Hi @adyakin,

The [*] operator only applies to lists, but the for_each feature causes the resource to appear as a map. Therefore we need to use a for expression instead:

output "ip_addrs" {
  value = { for k, res in swm_ip_reservation.test1 : k => res.ip_addr}
}

In your case this would produce a map from hostname to IP address, perhaps like this:

{
  "host1.example.com" = "10.1.2.1"
  "host2.example.com" = "10.1.2.5"
}

If you want it to be a list, as would’ve been the case with count and a splat expression, you can write it slightly differently:

output "ip_addrs" {
  value = [ for res in swm_ip_reservation.test1 : res.ip_addr ]
}

Note that this list will end up being ordered by a lexical sort of the hostnames, because that’s the default ordering imposed by the for expression when projecting a map into a list.

1 Like

Thank you! That is what I needed, seems I completely miss this part from doc. Map looks even better as more readable and predicable output