You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform路由表模块输出routes返回tolist([])问题求助

Terraform Azure路由表模块输出异常排查与解决

问题背景

编写了一个接收路由列表的Azure路由表Terraform子模块,资源创建正常,但父模块输出路由名称时返回tolist([]);执行terraform destroy时能看到路由表中存在正确的路由名称。

原因分析

  1. 子模块输出引用错误:子模块outputs.tf中尝试通过azurerm_route_table.this.route获取路由信息,但azurerm_route_table资源本身并不包含route属性——路由是通过独立的azurerm_route资源创建的,因此该输出实际返回空值。
  2. 父模块输出语法错误:父模块使用[module.route_table[*].routes[*].name]的splat运算符,但module.route_table是单个实例而非列表,多余的[*]会导致输出结构异常,加上子模块的routes输出本身为空,最终返回tolist([])。
  3. 子模块变量校验逻辑缺陷:当输入的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 04:29:52