当前位置: 首页 > news >正文

如何使用flatten函数在Terraform 中迭代嵌套map

简介

flatten 接受一个列表,并用列表内容的扁平序列替换列表中的任何元素。

> flatten([["a", "b"], [], ["c"]])
["a", "b", "c"]
> flatten([[["a", "b"], []], ["c"]])
["a", "b", "c"]

间接嵌套列表(例如map中的列表)不会被展平。 

扁平化 for_each 的嵌套结构


资源 for_each 和动态块语言功能都需要一个集合值,该值每次重复都包含一个元素。

有时,您的输入数据结构本身并不适合用于 for_each 参数,而 flatten 函数在将嵌套数据结构简化为扁平结构时非常有用。

案例1

声明变量

例如,考虑一个声明如下变量的模块:

variable "networks" {type = map(object({cidr_block = stringsubnets    = map(object({ cidr_block = string }))}))default = {"private" = {cidr_block = "10.1.0.0/16"subnets = {"db1" = {cidr_block = "10.1.0.1/16"}"db2" = {cidr_block = "10.1.0.2/16"}}},"public" = {cidr_block = "10.1.1.0/16"subnets = {"webserver" = {cidr_block = "10.1.1.1/16"}"email_server" = {cidr_block = "10.1.1.2/16"}}}"dmz" = {cidr_block = "10.1.2.0/16"subnets = {"firewall" = {cidr_block = "10.1.2.1/16"}}}}
}

 以上是对自然形成树的对象(例如顶级网络及其子网)进行建模的合理方法。顶级网络的重复可以直接使用此变量,因为它已经是结果实例与映射元素一一匹配的形式:

resource "aws_vpc" "example" {for_each = var.networkscidr_block = each.value.cidr_block
}

展平network_subnets

但是,为了用单个资源块声明所有子网,我们必须首先展平结构以生成一个集合,其中每个顶级元素代表一个子网: 

locals {# flatten ensures that this local value is a flat list of objects, rather# than a list of lists of objects.network_subnets = flatten([for network_key, network in var.networks : [for subnet_key, subnet in network.subnets : {network_key = network_keysubnet_key  = subnet_keynetwork_id  = aws_vpc.example[network_key].idcidr_block  = subnet.cidr_block}]])
}resource "aws_subnet" "example" {# local.network_subnets is a list, so we must now project it into a map# where each key is unique. We'll combine the network and subnet keys to# produce a single unique key per instance.for_each = tomap({for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet})vpc_id            = each.value.network_idavailability_zone = each.value.subnet_keycidr_block        = each.value.cidr_block
}

 上述结果是每个子网对象有一个子网实例,同时保留子网与其包含的网络之间的关联。

运行terraform plan

  # aws_vpc.example["public"] will be created+ resource "aws_vpc" "example" {+ arn                                  = (known after apply)+ cidr_block                           = "10.2.0.0/16"+ default_network_acl_id               = (known after apply)+ default_route_table_id               = (known after apply)+ default_security_group_id            = (known after apply)+ dhcp_options_id                      = (known after apply)+ enable_dns_hostnames                 = (known after apply)+ enable_dns_support                   = true+ enable_network_address_usage_metrics = (known after apply)+ id                                   = (known after apply)+ instance_tenancy                     = "default"+ ipv6_association_id                  = (known after apply)+ ipv6_cidr_block                      = (known after apply)+ ipv6_cidr_block_network_border_group = (known after apply)+ main_route_table_id                  = (known after apply)+ owner_id                             = (known after apply)+ tags_all                             = (known after apply)}Plan: 8 to add, 0 to change, 0 to destroy.

terraform将创建5个子网和3个vpc。

  • private vpc 和子网db1 、db2 
  • public vpc 和子网 webserver 、email_server
  • dmz vpc和firewall 子网

 案例2

我们将通过一个将策略附加到角色的简单示例,探索如何在 Terraform 中迭代嵌套映射。

设置嵌套映射


首先,我们需要创建一个变量来保存嵌套映射:

variable "role_map" {default = {"role_1" = {"name" : "Role 1""policies" : ["policy_arn_1", "policy_arn_2", "policy_arn_3"],},"role_2" = {"name" : "Role 2""policies" : ["policy_arn_2", "policy_arn_4", "policy_arn_6"],}}
}

如您所见,每个角色都包含许多策略,这在循环遍历映射时会造成麻烦。

嵌套映射


为了将其转换为可迭代的格式,我们需要展平此映射:

locals {role_policies = flatten([for role_key, role in var.role_map : [for p, policy in role.policies : {role_key  = role_keyrole_name = role.namepolicy_arn  = policy}]])
}

测试Flattened map


我们可以使用 terraform console 命令来确认其是否按预期运行。

在控制台中,运行 local.role_policies。您现在应该会看到以下输出:

ninjamac@ip-192-168-1-2 nested_for_each % terraform console
> local.role_policies
[{"policy_arn" = "policy_arn_1""role_key" = "role_1""role_name" = "Role 1"},{"policy_arn" = "policy_arn_2""role_key" = "role_1""role_name" = "Role 1"},{"policy_arn" = "policy_arn_3""role_key" = "role_1""role_name" = "Role 1"},{"policy_arn" = "policy_arn_2""role_key" = "role_2""role_name" = "Role 2"},{"policy_arn" = "policy_arn_4""role_key" = "role_2""role_name" = "Role 2"},{"policy_arn" = "policy_arn_6""role_key" = "role_2""role_name" = "Role 2"},
]

现在,这是理想的格式。每个策略都已展平,但仍引用其应附加到的原始角色。

迭代展平后的 Map


现在,我们可以循环遍历展平后的 local.role_policies 了:

resource "example_terraform_resource_attach_policy" "example" {for_each = { for p, policy in local.role_policies : p => policy }policy_arn = each.value.policy_arnrole_key = each.value.role_key
}

这将创建具有正确 policy_arn 的所有 6 个策略,并为其分配正确的 role_key。 

案例3:

模块:

locals {nestedlist = flatten([for k, v in var.route : [for n, s in v : [{key = k,name = n,svc_url = s}]]])
}
resource "aws_appmesh_gateway_route" "gateway_route" {for_each             = { for o in local.nestedlist : o.name => o }name                 = trimprefix(each.value.name, "/")mesh_name            = var.mesh_namevirtual_gateway_name = var.virtual_gateway_namespec {http_route {action {target {virtual_service {virtual_service_name = each.value.svc_url}}}match {prefix = each.value.name}}}
}

 变量:

virtual_gateway_name = "backend"
mesh_name = "development"
route = {"region" = {"/north" = "north.dev.svc.cluster.local""/south" = "south.dev.svc.cluster.local""/east"  = "east.dev.svc.cluster.local""/west"  = "west.dev.svc.cluster.local"}"direction" = {"/up" = "up.dev.svc.cluster.local""/down" = "down.dev.svc.cluster.local""/right" = "right.dev.svc.cluster.local""/left" = "left.dev.svc.cluster.local"}
}

该示例使用 flatten 函数以递归方式展平列表和嵌套列表,以获取前缀名称和服务 URL。这样,Terraform 模块现已重构,可以创建多组虚拟网关路由。将来,我可以通过将其添加到路由列表中来添加更多虚拟网关路由。

如输出所示,将创建八个资源

输出:


# aws_appmesh_gateway_route.gateway_route["/west"] will be created+ resource "aws_appmesh_gateway_route" "gateway_route" {+ arn                  = (known after apply)+ created_date         = (known after apply)+ id                   = (known after apply)+ last_updated_date    = (known after apply)+ mesh_name            = "development"+ mesh_owner           = (known after apply)+ name                 = "west"+ resource_owner       = (known after apply)+ tags_all             = (known after apply)+ virtual_gateway_name = "backend"
+ spec {
+ http_route {+ action {+ target {+ virtual_service {+ virtual_service_name = "west.dev.svc.cluster.local"}}}
+ match {+ prefix = "/west"}}}}
Plan: 8 to add, 0 to change, 0 to destroy.

总结

Terraform 中的 flatten 函数用于将嵌套列表合并为单个一维列表。这对于简化复杂的数据结构以及更轻松地处理资源定义中的项目集合特别有用。通过展平列表,您可以确保数据采用更易于管理的格式,以便进行迭代等操作。

相关文章:

  • 演讲比赛流程管理项目c++
  • 网络互连与互联网4
  • python基础知识点(3)
  • Lambda 表达式的语法结构
  • 20250419将405的机芯由4LANE的LVDS OUT配置为8LANE的步骤
  • 怎么查看LLM Transformer 架构进行并行计算和设备映射
  • Python基础总结(七)之条件语句
  • 多线程和线程同步
  • Pandas取代Excel?
  • 交换排序——快速排序
  • opencv 图像的旋转
  • mysql的函数(第一期)
  • 简单线段树的讲解(一点点的心得体会)
  • 动态规划算法:状态压缩
  • 【python编程从入门到到实践】第二章 变量和简单的数据类型
  • Nginx 文件上传大小限制及 `client_max_body_size` 最大值详解
  • Linux 系统盘制作 | 引导加载器(GRUB 为例)| mount
  • 二叉树进阶 - 二叉搜索树
  • PDF转excel+json ,vue3+SpringBoot在线演示+附带源码
  • 宇树机器狗go2—slam建图(1)点云格式
  • 湖南新宁一矿厂排水管破裂,尾砂及积水泄漏至河流,当地回应
  • 空调+零食助顶级赛马备战,上海环球马术冠军赛即将焕新登场
  • 韩国检方结束对尹锡悦私宅的扣押搜查
  • 经营业绩持续稳中向好,国铁集团2024年度和2025年一季度财务决算公布
  • 孙磊已任中国常驻联合国副代表、特命全权大使
  • 新型算法助力听障人士听得更清晰