Terraform list from different maps

Hi All,
I’m trying to set via vsphere provider an anti-affinity rule and I have to iterate on different virtual_machine resources output map, and this bug reported a for loop to extract from a single map.

The loop statement is:

virtual_machine_ids = [ for k, v in vsphere_virtual_machine.vm : v.id ]
}

Is it possibile to extract and merge from different maps as reported below and pass them to virual_machine_ids as a single list:

  • vsphere_virtual_machine.vm_fe
  • vsphere_virtual_machine.vm_be

?

Thanks,
Marcello

Hi @cello86,

The main idea here would be to either use the merge function on the source value or the setunion function on the result of this for expression to combine the collections together either before or after you project them to extract the ids.

There are many different ways to write this which will do the individual steps in different orders and use slightly different Terraform language features. The following is the way I would write it, though this is really just a matter of personal preference and other ways to write it would be valid too.

setunion(
  values(vsphere_virtual_machine.vm_fe[*]).id,
  values(vsphere_virtual_machine.vm_be[*]).id,
)

This is a slightly different approach than how you wrote it but still similar:

  • I used values to take just the list of values from each map, which is then compatible with the splat operator [*].
  • I used the splat operator instead of a for expression. It achieves the same result but I tend to find this style more readable for simple cases.
  • I used setunion to merge these two lists of ids into a single set of unique values.

HI @apparentlymart,
I tried the setunion in the resource definition as reported below:

locals {
  pr_vm_ids = setunion(values(vsphere_virtual_machine.infra_dc1[*]).id, values(vsphere_virtual_machine.compute_env1_dc1[*]).id, values(vsphere_virtual_machine.compute_env2_dc1[*]).id)
}

resource "vsphere_compute_cluster_vm_group" "cluster_vm_group_infra_dc1" {
  name                = "pr_devapi_vm"
  compute_cluster_id  = "${data.vsphere_compute_cluster.cluster.id}"
  virtual_machine_ids = [ local.pr_vm_ids ]
}

I received this error with plan and apply commands:

terraform plan 
╷
│ Error: Incorrect attribute value type
│
│   on resources.tf line 595, in resource "vsphere_compute_cluster_vm_group" "cluster_vm_group_infra_dc1":
│  595:   virtual_machine_ids = [ local.pr_vm_ids ]
│     ├────────────────
│     │ local.pr_vm_ids is a set of dynamic, known only after apply
│
│ Inappropriate value for attribute "virtual_machine_ids": element 0: string required.

Thanks,
Marcello

Hi @cello86,

You have written [ local.pr_vm_ids ], which tells Terraform to generate a tuple whose first element is the set. That’s not correct because this argument just wants a collection of strings, not a collection of sets of strings.

If you just write local.pr_vm_ids without the brackets then I expect it will work, because this value is already of a type that is compatible with the argument.

Hi @apparentlymart
I tested this working configuration:

locals {
  dc1_vm_ids = setunion([for k, v in vsphere_virtual_machine.infra_dc1 : v.id], [for k, v in vsphere_virtual_machine.compute_env1_dc1 : v.id], [for k, v in vsphere_virtual_machine.compute_env2_dc1 : v.id])
}

resource "vsphere_compute_cluster_vm_group" "cluster_vm_group_dc1" {
  name                = var.vm_dc1_vm_group_name
  compute_cluster_id  = data.vsphere_compute_cluster.cluster.id
  virtual_machine_ids = local.dc1_vm_ids
}