Terraform:如何基于匹配属性合并两个映射生成新对象?
Terraform:基于Location匹配合并两个映射生成新对象
目标
基于两个映射的相同location属性匹配创建新对象/映射,最终为多个分支/工作负载NSG部署azurerm_network_watcher_flow_log资源(例如8个分支NSG对应分属westeurope和eastus2的2个Network Watcher)。
背景说明
代码通过for_each遍历包含Azure多资源部署数据的变量var.spokes,其输出结构如下:
+ customerA = { + environment = "D" + location = "westeurope" + name = "customerA" } + customerB = { + environment = "D" + location = "westeurope" + name = "customerB" } + customerC = { + environment = "D" + location = "eastus2" + name = "customerC" }
需要将var.spokes与数据源data.azurerm_network_watcher.nw按location属性匹配,该数据源输出结构如下:
+ eastus2 = { + location = "eastus2" + name = "NetworkWatcher_eastus2" + resource_group_name = "NetworkWatcherRG" + tags = {} + timeouts = null } + westeurope = { + location = "westeurope" + name = "NetworkWatcher_westeurope" + resource_group_name = "NetworkWatcherRG" + tags = {} + timeouts = null }
前提/约束
- 最终对象/映射需保留
var.spokes的键(customerA、customerB等)作为主键; - 仅通过两个源映射共有的
location属性进行匹配。
预期输出
期望生成如下格式的新对象映射:
+ customerA = { + environment = "D" + location = "westeurope" + name = "customerA" + watcher_name = "NetworkWatcher_westeurope" + watcher_resource_group_name = "NetworkWatcherRG" } + customerB = { + environment = "D" + location = "westeurope" + name = "customerB" + watcher_name = "NetworkWatcher_westeurope" + watcher_resource_group_name = "NetworkWatcherRG" } + customerC = { + environment = "D" + location = "eastus2" + name = "customerC" + watcher_name = "NetworkWatcher_eastus2" + watcher_resource_group_name = "NetworkWatcherRG" }
已尝试的方法及问题
- 第一种方法生成含额外键的异常结果:
locals { spoke_nwatchers = { for k, v in var.spokes : k => { for i, n in values(data.azurerm_network_watcher.nw)[*] : i => { watcher_id = n.id, watcher_name = n.name, watcher_resource_group_name = n.resource_group_name, watcher_location = n.location environment = v.environment } if v.location == n.location } } } output "spoke_nwatchers" { value = local.spoke_nwatchers }
- 第二种方法得到包含单个元素的元组而非映射:
locals { spoke_nwatchers = { for k, v in var.spokes : k => [ for i, n in data.azurerm_network_watcher.nw : { watcher_id = n.id, watcher_name = n.name, watcher_resource_group_name = n.resource_group_name, watcher_location = n.location, environment = v.environment } if v.location == n.location ] } }
解决方案
利用data.azurerm_network_watcher.nw的键与location值一致的特性,直接通过v.location索引对应区域的Network Watcher,再用merge函数合并两个对象的属性,同时给Network Watcher的属性添加前缀避免冲突:
locals { spoke_nwatchers = { for k, v in var.spokes : k => merge( v, { watcher_name = data.azurerm_network_watcher.nw[v.location].name watcher_resource_group_name = data.azurerm_network_watcher.nw[v.location].resource_group_name } ) } } output "spoke_nwatchers" { value = local.spoke_nwatchers }
可选:添加存在性校验
如果需要过滤掉没有对应Network Watcher的分支(避免因location不匹配报错),可以添加if条件:
locals { spoke_nwatchers = { for k, v in var.spokes : k => merge( v, { watcher_name = data.azurerm_network_watcher.nw[v.location].name watcher_resource_group_name = data.azurerm_network_watcher.nw[v.location].resource_group_name } ) if contains(keys(data.azurerm_network_watcher.nw), v.location) } }
内容的提问来源于stack exchange,提问作者falken
相关产品推荐
相关产品推荐

