Terraform中foreach遍历嵌套数据及flatten函数用法求助
Terraform vSphere 动态配置network数据源解决方案
一、先搞懂flatten函数到底怎么用
flatten的作用就是把嵌套的列表/元组“拍扁”成一维结构。比如你有[[1,2], [3,4]],用flatten处理后就变成[1,2,3,4]。但要注意两个关键点:
- 它只认列表/元组类型的嵌套,如果嵌套里是map,不会自动拆解map的键值对
- 输入是tuple的话,输出也是tuple;输入是list则输出list。而
for_each根本不认tuple——它只接受map类型,或者元素是字符串/数字的set,这就是你报错的核心原因。
二、针对你的场景的正确操作步骤
假设你的virtual_machines变量定义大概是这样(先对齐基础结构):
variable "virtual_machines" { type = list(object({ name = string interfaces = list(object({ network_name = string # 其他接口属性比如vlan_id之类的... })) })) }
1. 用flatten+for表达式生成一维接口列表,再转成map
先把每个虚拟机的interfaces拍平,再转成map(给for_each用的必须有唯一key):
locals { # 第一步:把所有虚拟机的接口拍平成一维列表,每个条目带虚拟机名称、接口索引、网络名 flattened_interfaces = flatten([ for vm in var.virtual_machines : [ for idx, intf in vm.interfaces : { vm_name = vm.name interface_idx = idx network_name = intf.network_name } ] ]) # 第二步:转成map,用虚拟机名+接口索引作为唯一key,值是网络名 vm_network_map = { for intf in local.flattened_interfaces : "${intf.vm_name}-${intf.interface_idx}" => intf.network_name } }
2. 给network数据源配置for_each
现在local.vm_network_map是符合要求的map,直接用就行:
data "vsphere_network" "vm_networks" { for_each = local.vm_network_map name = each.value datacenter_id = data.vsphere_datacenter.dc.id }
三、优化:避免重复创建相同网络的数据源
如果多个虚拟机用同一个网络,上面的方法会生成多个重复的data资源,没必要。可以先提取所有唯一的网络名称:
locals { # 提取所有不重复的网络名称,先拍平再去重 unique_network_names = distinct(flatten([ for vm in var.virtual_machines : [for intf in vm.interfaces : intf.network_name] ])) # 转成map(用网络名本身当key,前提是你的网络在数据中心里名称唯一) unique_network_map = { for name in local.unique_network_names : name => name } }
然后数据源用这个map,就能做到一个网络只创建一个data资源:
data "vsphere_network" "vm_networks" { for_each = local.unique_network_map name = each.value datacenter_id = data.vsphere_datacenter.dc.id }
四、为啥你之前直接用flatten会报错?
因为flatten返回的是tuple,而for_each不接受tuple类型。必须把tuple转成map或者set(distinct处理后的list会被Terraform当成set)。比如你也可以直接这么写(前提是网络名唯一):
data "vsphere_network" "vm_networks" { for_each = distinct(flatten([ for vm in var.virtual_machines : [for intf in vm.interfaces : intf.network_name] ])) name = each.value datacenter_id = data.vsphere_datacenter.dc.id }
内容的提问来源于stack exchange,提问作者Roman Qwertoff
相关产品推荐
相关产品推荐

