Terraform路由表模块输出routes返回tolist([])问题求助
Terraform Azure路由表模块输出异常排查与解决
问题背景
编写了一个接收路由列表的Azure路由表Terraform子模块,资源创建正常,但父模块输出路由名称时返回tolist([]);执行terraform destroy时能看到路由表中存在正确的路由名称。
原因分析
- 子模块输出引用错误:子模块
outputs.tf中尝试通过azurerm_route_table.this.route获取路由信息,但azurerm_route_table资源本身并不包含route属性——路由是通过独立的azurerm_route资源创建的,因此该输出实际返回空值。 - 父模块输出语法错误:父模块使用
[module.route_table[*].routes[*].name]的splat运算符,但module.route_table是单个实例而非列表,多余的[*]会导致输出结构异常,加上子模块的routes输出本身为空,最终返回tolist([])。 - 子模块变量校验逻辑缺陷:当输入的
routes为空列表时,变量校验中的var.routes[0]会触发索引越界错误,校验逻辑未处理空列表场景。
解决方法
1. 修正子模块输出(outputs.tf)
删除错误的路由输出,改为从独立的azurerm_route.routes资源中提取信息:
output "id" { value = azurerm_route_table.this.id description = "The Route Table configuration ID." } output "name" { value = azurerm_route_table.this.name description = "The name of the Route Table." } # 输出所有路由的完整配置 output "routes" { value = values(azurerm_route.routes) description = "Blocks containing configuration of each route." } # 单独输出路由名称列表(可选,方便父模块直接引用) output "route_names" { value = keys(azurerm_route.routes) description = "List of route names in the route table." }
说明:azurerm_route.routes是通过for_each创建的map类型资源,values()将其转换为路由对象列表,keys()直接提取所有路由名称。
2. 修正父模块输出(outputs.tf)
根据子模块的新输出调整父模块,直接引用路由名称列表:
output "id" { value = module.route_table.id description = "The Route Table configuration ID." } output "name" { value = module.route_table.name description = "The name of the Route Table." } output "routes" { value = module.route_table.route_names description = "List of route names in the route table." }
如果需要从完整路由配置中提取名称,也可以用如下写法:
output "routes" { value = [for route in module.route_table.routes : route.name] description = "List of route names in the route table." }
3. 修复子模块变量校验逻辑(variables.tf)
修改routes变量的校验条件,处理空列表场景,并修正正则表达式:
variable "routes" { description = "List of objects that represent the configuration of each added Route." type = list(object({ name = string address_prefix = string next_hop_type = string next_hop_in_ip_address = optional(string) })) default = [] validation { condition = length(var.routes) == 0 || alltrue([for r in var.routes : can(regex("^VirtualNetworkGateway$|^VnetLocal$|^Internet$|^VirtualAppliance$|^None$", r.next_hop_type))]) error_message = "Next Hop Type error: Must be one of the following: \"VirtualNetworkGateway\", \"VnetLocal\", \"Internet\", \"VirtualAppliance\", \"None\"." } }
说明:当路由列表为空时跳过校验,同时用alltrue遍历所有路由的next_hop_type,确保每个值都符合要求。
验证效果
执行terraform apply后,父模块的routes输出将显示正确的路由名称列表,例如:
routes = [ "firewall", "internet", "route2", ]
内容的提问来源于stack exchange,提问作者Scott
相关产品推荐
相关产品推荐

