【问题标题】:Terraform for_each if value exists in objectTerraform for_each 如果对象中存在值
【发布时间】:2020-11-01 00:18:47
【问题描述】:

我想从 .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 中列出的路由表。并非所有子网都有与之关联的路由表,因此它只需要运行 IF 列出的键/值 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".

我尝试了各种方法都没有成功,我在这里不知所措,希望能得到任何指导。

【问题讨论】:

    标签: terraform terraform0.12+


    【解决方案1】:

    根据您的情况,我猜测输入中的 vnet_spoke_object 如下所示:

    vnet_spoke_object = {
      specialsubnets = {
        subnetA = {
          cidr  = "..."
        }
        subnetB = {
          cidr  = "..."
          route = "..."
        }
      }
    }
    

    问题在于缺少的 route 条目不会解析为 null,它会导致恐慌或崩溃。您需要像这样编写您的输入(使用明确的 nulls):

    vnet_spoke_object = {
      specialsubnets = {
        subnetA = {
          cidr  = "..."
          route = null
        }
        subnetB = {
          cidr  = "..."
          route = "..."
        }
      }
    }
    

    lookup route 按名称并在您的地图生成器表达式中提供 null 默认值,如下所示:

    for_each                       = {
        for key, value in var.vnet_spoke_object.specialsubnets:
            key => value
            if lookup(value, "route", null) != null
    }
    

    【讨论】:

    • 谢谢。我的 .tfvars 中的 null 部分是修复:D
    • 您可以通过在变量上设置type constraint 来使这一点更明确,例如type = map(object({cidr = string, route = string})),然后Terraform 将报告.tfvars 文件中的值无效,如果它没有两个属性集,而不是在模块的实现中失败。
    猜你喜欢
    • 1970-01-01
    • 2021-03-09
    • 2021-06-16
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 2021-08-02
    • 2020-12-19
    相关资源
    最近更新 更多