terraform - Terraform for_each 如果对象中存在值
问题描述
我想从 .tfvars 文件动态创建一些子网和路由表,然后将每个子网链接到关联的路由表(如果指定)。
这是我的 .tfvars 文件:
vnet_spoke_object = {
specialsubnets = {
Subnet_1 = {
name = "test1"
cidr = ["10.0.0.0/28"]
route = "route1"
}
Subnet_2 = {
name = "test2"
cidr = ["10.0.0.16/28"]
route = "route2"
}
Subnet_3 = {
name = "test3"
cidr = ["10.0.0.32/28"]
}
}
}
route_table = {
route1 = {
name = "route1"
disable_bgp_route_propagation = true
route_entries = {
re1 = {
name = "rt-rfc-10-28"
prefix = "10.0.0.0/28"
next_hop_type = "VirtualAppliance"
next_hop_in_ip_address = "10.0.0.10"
}
}
}
route2 = {
name = "route2"
disable_bgp_route_propagation = true
route_entries = {
re1 = {
name = "rt-rfc-10-28"
prefix = "10.0.0.16/28"
next_hop_type = "VirtualAppliance"
next_hop_in_ip_address = "10.0.0.10"
}
}
}
}
...这是我的构建脚本:
provider "azurerm" {
version = "2.18.0"
features{}
}
variable "ARM_LOCATION" {
default = "uksouth"
}
variable "ARM_SUBSCRIPTION_ID" {
default = "asdf-b31e023c78b8"
}
variable "vnet_spoke_object" {}
variable "route_table" {}
module "names" {
source = "./nbs-azure-naming-standard"
env = "dev"
location = var.ARM_LOCATION
subId = var.ARM_SUBSCRIPTION_ID
}
resource "azurerm_resource_group" "test" {
name = "${module.names.standard["resource-group"]}-vnet"
location = var.ARM_LOCATION
}
resource "azurerm_virtual_network" "test" {
name = "${module.names.standard["virtual-network"]}-test"
location = var.ARM_LOCATION
resource_group_name = azurerm_resource_group.test.name
address_space = ["10.0.0.0/16"]
}
resource "azurerm_subnet" "test" {
for_each = var.vnet_spoke_object.specialsubnets
name = "${module.names.standard["subnet"]}-${each.value.name}"
resource_group_name = azurerm_resource_group.test.name
virtual_network_name = azurerm_virtual_network.test.name
address_prefixes = each.value.cidr
}
resource "azurerm_route_table" "test" {
for_each = var.route_table
name = "${module.names.standard["route-table"]}-${each.value.name}"
location = var.ARM_LOCATION
resource_group_name = azurerm_resource_group.test.name
disable_bgp_route_propagation = each.value.disable_bgp_route_propagation
dynamic "route" {
for_each = each.value.route_entries
content {
name = route.value.name
address_prefix = route.value.prefix
next_hop_type = route.value.next_hop_type
next_hop_in_ip_address = contains(keys(route.value), "next_hop_in_ip_address") ? route.value.next_hop_in_ip_address: null
}
}
}
该部分在创建 vnet/subnet/route 资源时工作正常,但我面临的问题是将每个子网动态链接到 .tfvars 中列出的路由表。并非所有子网都有与之关联的路由表,因此它只需要在列出键/值时运行route
。
resource "azurerm_subnet_route_table_association" "test" {
for_each = {
for key, value in var.vnet_spoke_object.specialsubnets:
key => value
if value.route != null
}
lifecycle {
ignore_changes = [
subnet_id
]
}
subnet_id = azurerm_subnet.test[each.key].id
route_table_id = azurerm_route_table.test[each.key].id
}
我在上面的代码中遇到的错误是:
Error: Unsupported attribute
on main.tf line 65, in resource "azurerm_subnet_route_table_association" "test":
65: if value.route != null
This object does not have an attribute named "route".
我尝试了各种方法都没有成功,我在这里不知所措,并希望得到任何可能的指导。
解决方案
根据您的情况,我猜测输入中的vnet_spoke_object如下所示:
vnet_spoke_object = {
specialsubnets = {
subnetA = {
cidr = "..."
}
subnetB = {
cidr = "..."
route = "..."
}
}
}
这样做的问题是缺少的路由条目不会解析为null,它会导致恐慌或崩溃。您需要像这样编写输入(使用显式null s):
vnet_spoke_object = {
specialsubnets = {
subnetA = {
cidr = "..."
route = null
}
subnetB = {
cidr = "..."
route = "..."
}
}
}
或按名称查找 路线并在您的地图生成器表达式中提供null默认值,如下所示:
for_each = {
for key, value in var.vnet_spoke_object.specialsubnets:
key => value
if lookup(value, "route", null) != null
}
推荐阅读
- javascript - 在渲染和重新渲染时获取 graphql 查询结果但懒惰
- java - 仅使用 java 中键对象的引用的缓存(而不是 hashCode 或 equals)
- javascript - React Native 中的文本位置
- rest - 在 PostMan 中工作时(显然)相同的 GET 可能在soapUI 中失败的可能原因
- javascript - 按特定键对对象数组进行分组
- java - 配置 IntelliJ 以使用与 Spotless 相同的 Java 格式化程序
- powerbi - 使用 DAX 在 Power BI 中创建多个累积折线图
- python - 为什么将(用户定义的)类实例绑定到类属性会更改数据类型?
- highcharts - Highcharts 线条颜色基于除值以外的其他数据
- azure - 如何在 Azure 数据仓库中对大型数据集执行数据工厂转换