从Terraform数据块提取子网生成locals列表失败求助
问题排查:Terraform构建Web应用子网访问限制时的属性错误
问题场景
尝试创建带有VNet访问限制的Web应用,需传入子网名称、子网ID及优先级。先通过以下数据块获取子网列表:
data "azurerm_virtual_network" "vnet" { name = var.np_vnet1 resource_group_name = var.np_vnet_rg } data "azurerm_subnet" "np-vnet1-subnets" { for_each = toset(data.azurerm_virtual_network.vnet.subnets) name = each.value virtual_network_name = data.azurerm_virtual_network.vnet.name resource_group_name = data.azurerm_virtual_network.vnet.resource_group_name }
接着在locals中构建格式,动态传入azurerm_windows_web_app资源:
locals { subnet_restrictions = [ for idx, subnet in [data.azurerm_subnet.np-vnet1-subnets] : { name = subnet.name virtual_network_subnet_id = subnet.id priority = idx + 100 } ] }
最终传入Web应用的ip_restrictions:
dynamic "ip_restriction" { for_each = local.subnet_restrictions content { name = ip_restriction.value["name"] virtual_network_subnet_id = ip_restriction.value["virtual_network_subnet_id"] priority = ip_restriction.value["priority"] action = "Allow" } }
但执行时持续报错,提示对象无name或id属性:
│ Error: Unsupported attribute │ │ on locals.tf line 29, in locals: │ 29: name = subnet.name │ │ This object does not have an attribute named "name". ╵ ╷ │ Error: Unsupported attribute │ │ on locals.tf line 30, in locals: │ 30: virtual_network_subnet_id = subnet.id │ │ This object does not have an attribute named "id".
错误根源
[data.azurerm_subnet.np-vnet1-subnets]的写法是核心问题:你把整个map类型的数据源对象包装成了一个单元素列表,循环中的subnet变量指向的是整个map,而非单个子网资源实例,因此无法直接调用name和id属性。
使用for_each创建的数据源azurerm_subnet.np-vnet1-subnets本质是一个键值对map,键为子网名称,值为对应的子网资源对象。
修正方案
方案1:遍历子网数据源的values集合
直接遍历数据源的values集合,用索引计算优先级:
locals { subnet_restrictions = [ for idx, subnet in values(data.azurerm_subnet.np-vnet1-subnets) : { name = subnet.name virtual_network_subnet_id = subnet.id priority = idx + 100 } ] }
方案2:保留键值对关联(可选)
如果需要保留子网名称与资源的关联,可将map转换为目标结构,后续动态块遍历map的values即可:
locals { subnet_restrictions = { for subnet_name, subnet in data.azurerm_subnet.np-vnet1-subnets : subnet_name => { name = subnet.name virtual_network_subnet_id = subnet.id priority = index(keys(data.azurerm_subnet.np-vnet1-subnets), subnet_name) + 100 } } } # 动态块调整为遍历map的values dynamic "ip_restriction" { for_each = local.subnet_restrictions content { name = ip_restriction.value.name virtual_network_subnet_id = ip_restriction.value.virtual_network_subnet_id priority = ip_restriction.value.priority action = "Allow" } }
额外优化:避免索引顺序问题(可选)
若担心子网名称排序导致优先级变化,可通过哈希值生成更稳定的优先级:
priority = tonumber(substr(sha1(subnet.name), 0, 3)) + 100
内容的提问来源于stack exchange,提问作者NickP
相关产品推荐
相关产品推荐

