Terraform Flatten序列问题:Traffic Manager端点按索引而非名称创建
问题:Terraform Azure Traffic Manager 端点按索引而非名称创建
当前Terraform Plan输出显示端点以["0"]、["1"]的索引形式创建,而非使用输入中定义的端点名称(如tfendpoint1、tfendpoint2)。需要调整flatten逻辑,确保端点资源按名称进行索引。
现有Plan输出
# module.infra.azurerm_traffic_manager_azure_endpoint.tm_azure_endpoint["0"] will be created + resource "azurerm_traffic_manager_azure_endpoint" "tm_azure_endpoint" { + enabled = true + geo_mappings = [ + "US", ] + id = (known after apply) + name = "0" + priority = 1 + profile_id = "/subscriptions/3f128ee2-eef5-4ede-ac7e-42cf4a4f8632/resourceGroups/rg-eastus-tmprofile/providers/Microsoft.Network/trafficManagerProfiles/traf-eastus-01" + target_resource_id = "/subscriptions/3f128ee2-eef5-4ede-ac7e-42cf4a4f8632/resourceGroups/rg-eastus-tmprofile/providers/Microsoft.Network/publicIPAddresses/pip-core-vng-eus-01" + weight = 1 } # module.infra.azurerm_traffic_manager_azure_endpoint.tm_azure_endpoint["1"] will be created + resource "azurerm_traffic_manager_azure_endpoint" "tm_azure_endpoint" { + enabled = true + geo_mappings = [ + "US", ] + id = (known after apply) + name = "1" + priority = 1 + profile_id = "/subscriptions/3f128ee2-eef5-4ede-ac7e-42cf4a4f8632/resourceGroups/rg-eastus-taf-eastus-01" + target_resource_id = (known after apply) + weight = 1 }
现有代码(MAIN)
locals { tm_profile = { for k, v in try(local.inputs.tm_profiles, {}) : k => merge( { existing = false traffic_view_enabled = false //optional feature. $2 per million data points processed. Data points are essentially queries into Traffic Manager. interval_in_seconds = 30 timeout_in_seconds = 10 tolerated_number_of_failures = 3 }, v, { tags = merge( local.tags, try(v.tags, {}) ) } ) } tmprofile_endpoints = flatten([ for tm_k, tm_v in try(local.inputs.tm_profiles, {}) : [ for tm_endpoints_k, tm_endpoints_v in try(tm_v.tm_endpoints, {}) : merge( tm_endpoints_v, { name = tm_endpoints_k profile_id = azurerm_traffic_manager_profile.traffic_manager_profile[tm_endpoints_v["tm_profile_name"]].id target_resource_id = azurerm_public_ip.pub_ips[tm_endpoints_v["pub_ip"]].id enabled = true protocol = tm_v.protocol } ) ] ]) } resource "azurerm_traffic_manager_profile" "traffic_manager_profile" { for_each = { for k, v in local.tm_profile : k => v if !v.existing } name = each.key resource_group_name = each.value.rg profile_status = each.value.profile_status traffic_routing_method = each.value.traffic_routing_method dns_config { relative_name = each.value.relative_name ttl = each.value.ttl } monitor_config { protocol = each.value.protocol port = each.value.port path = (each.value.protocol != "TCP") ? each.value.path : lookup(each.value, "path", null) expected_status_code_ranges = try(each.value.expected_status_code_ranges, "200") dynamic "custom_header" { for_each = (each.value.protocol == "HTTP" || each.value.protocol == "HTTPS") ? try(each.value.custom_headers, {}) : {} content { name = each.value.name value = each.value.value } } interval_in_seconds = each.value.interval_in_seconds timeout_in_seconds = each.value.timeout_in_seconds tolerated_number_of_failures = each.value.tolerated_number_of_failures } tags = each.value.tags depends_on = [ azurerm_resource_group.rgs ] } resource "azurerm_traffic_manager_azure_endpoint" "tm_azure_endpoint" { for_each = { for k, v in local.tmprofile_endpoints : k => v } name = each.key profile_id = each.value.profile_id target_resource_id = each.value.target_resource_id weight = each.value.weight dynamic "custom_header" { for_each = (each.value.protocol == "HTTP" || each.value.protocol == "HTTPS") ? try(each.value.custom_headers, {}) : {} content { name = each.value.name value = each.value.value } } enabled = each.value.enabled geo_mappings = each.value.geo_mappings priority = each.value.priority depends_on = [ azurerm_traffic_manager_profile.traffic_manager_profile ] } /* output "tmprofile_endpoints_out" { value = local.tmprofile_endpoints } */
示例输入(Sample Input)
"tm_profiles": { "traf-eastus-01": { "rg": "rg-eastus-tmprofile", "profile_status": "Enabled", "traffic_routing_method": "Performance", "relative_name": "azmech", "ttl": 3600, "protocol": "HTTPS", "port": 443, "path": "/", "expected_status_code_ranges": [ "200-201" ], "custom_header": { "name": "customheader", "value": null }, "tags": { "tm_profile": "tm_test" }, "tm_endpoints": { "tfendpoint1": { "tm_profile_name": "traf-eastus-01", "weight": "1", "custom_header": { "name": "customheader", "value": null }, "geo_mappings": [ "US" ], "priority": "1", "pub_ip": "pip-core-vng-eus-01" }, "tfendpoint2": { "tm_profile_name": "traf-eastus-01", "weight": "1", "custom_header": { "name": "customheader", "value": null }, "geo_mappings": [ "US" ], "priority": "1", "pub_ip": "pip-core-vng-wus-01" } } } }
解决方案
问题出在tmprofile_endpoints的flatten处理后得到的是列表,而非带键名的映射。当你用for k, v in local.tmprofile_endpoints时,k是列表的索引(0、1),而非端点名称。
修改后的tmprofile_endpoints局部变量
tmprofile_endpoints = { for tm_k, tm_v in try(local.inputs.tm_profiles, {}) : for ep_k, ep_v in try(tm_v.tm_endpoints, {}) : "${tm_k}-${ep_k}" => merge( ep_v, { name = ep_k profile_id = azurerm_traffic_manager_profile.traffic_manager_profile[ep_v["tm_profile_name"]].id target_resource_id = azurerm_public_ip.pub_ips[ep_v["pub_ip"]].id enabled = true protocol = tm_v.protocol } ) }
逻辑说明
- 使用嵌套
for循环直接构建映射,键名采用${tm_k}-${ep_k}(配置文件名-端点名称),确保全局唯一,避免不同配置文件下同名端点冲突 - 无需再用
flatten,直接得到以复合名称为键的映射结构
对应调整端点资源的for_each
因为tmprofile_endpoints已经是映射,可直接简化:
resource "azurerm_traffic_manager_azure_endpoint" "tm_azure_endpoint" { for_each = local.tmprofile_endpoints name = each.value.name profile_id = each.value.profile_id target_resource_id = each.value.target_resource_id weight = each.value.weight dynamic "custom_header" { for_each = (each.value.protocol == "HTTP" || each.value.protocol == "HTTPS") ? try(each.value.custom_headers, {}) : {} content { name = custom_header.value.name value = custom_header.value.value } } enabled = each.value.enabled geo_mappings = each.value.geo_mappings priority = each.value.priority depends_on = [ azurerm_traffic_manager_profile.traffic_manager_profile ] }
注意:动态块custom_header中需使用custom_header.value.name而非each.value.name,否则会引用外部each值导致错误。
修改后的Plan效果
端点资源会以["traf-eastus-01-tfendpoint1"]、["traf-eastus-01-tfendpoint2"]的形式创建,资源索引清晰对应输入中定义的端点名称。
内容的提问来源于stack exchange,提问作者Vegas588
相关产品推荐
相关产品推荐

