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

news2025/4/25 2:35:50

简介

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 = string
    subnets    = 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.networks

  cidr_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_key
        subnet_key  = subnet_key
        network_id  = aws_vpc.example[network_key].id
        cidr_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_id
  availability_zone = each.value.subnet_key
  cidr_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_key
        role_name = role.name
        policy_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_arn
  role_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_name
  virtual_gateway_name = var.virtual_gateway_name
  spec {
    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 函数用于将嵌套列表合并为单个一维列表。这对于简化复杂的数据结构以及更轻松地处理资源定义中的项目集合特别有用。通过展平列表,您可以确保数据采用更易于管理的格式,以便进行迭代等操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2342082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文精读】Reformer:高效Transformer如何突破长序列处理瓶颈?

目录 一、引言:当Transformer遇到长序列瓶颈二、核心技术解析:从暴力计算到智能优化1. 局部敏感哈希注意力(LSH Attention):用“聚类筛选”替代“全量计算”关键步骤:数学优化: 2. 可逆残差网络…

jmeter中监控服务器ServerAgent

插件下载: 将ServerAgent上传至需要监控的服务器,mac/liunx启动startAgent.sh(启动命令:./startAgent.sh) 在jmeter中添加permon监控组件 配置需要监控的服务器IP地址,添加需要监控的资源 注意&#xf…

网络结构及安全科普

文章目录 终端联网网络硬件基础网络协议示例:用户访问网页 OSI七层模型网络攻击(Hack)网络攻击的主要类别(一)按攻击目标分类(二)按攻击技术分类 网络安全防御 典型攻击案例相关名词介绍网络连接…

JVM虚拟机-JVM调优、内存泄漏排查、CPU飙高排查

一、JVM调优的参数在哪里设置 项目开发过程中有以下两种部署项目的方式: 项目部署在tomcat中,是一个war包;项目部署在SpringBoot中,是一个jar包。 (1)war包 catalina文件在Linux系统下的tomcat是以sh结尾,在windows系…

安全复健|windows常见取证工具

写在前面: 此博客仅用于记录个人学习内容,学识浅薄,若有错误观点欢迎评论区指出。欢迎各位前来交流。(部分材料来源网络,若有侵权,立即删除) 取证 01系统运行数据 使用工具:Live-F…

FPGA开发流程初识

FPGA 的开发流程可知,在 FPGA 开发的过程中会产生很多不同功能的文件,为了方便随时查找到对应文件,所以在开始开发设计之前,我们第一个需要考虑的问题是工程内部各种文件的管理。如 果不进行文件分类,而是将所有文件…

C# 类型、存储和变量(栈和堆)

本章内容 C#程序是一组类型声明 类型是一种模板 实例化类型 数据成员和函数成员 预定义类型 用户定义类型 栈和堆 值类型和引用类型 变量 静态类型和dynamic关键字 可空类型 栈和堆 程序运行时,它的数据必须存储在内存中。一个数据项需要多大的内存、存储在什么地方…

基于深度学习Yolo8的驾驶员疲劳与分心行为检测系统

基于深度学习Yolo8的驾驶员疲劳与分心行为检测系统 【包含内容】 【一】项目提供完整源代码及详细注释 【二】系统设计思路与实现说明 【三】疲劳检测模型与行为分析统计 【技术栈】 ①:系统环境:Windows/Mac/Linux ②:开发环境:P…

AOSP Android14 Launcher3——远程窗口动画关键类SurfaceControl详解

在 Launcher3 执行涉及其他应用窗口(即“远程窗口”)的动画时,例如“点击桌面图标启动应用”或“从应用上滑回到桌面”的过渡动画,SurfaceControl 扮演着至关重要的角色。它是实现这些跨进程、高性能、精确定制动画的核心技术。 …

Linux系统学习----概述与目录结构

linux 是一个开源、免费的操作系统,其稳定性、安全性、处理多并发已经得到业界的认可,目前很多企业级的项目 (c/c/php/python/java/go)都会部署到 Linux/unix 系统上。 一、虚拟机系统操作 1.网络连接的三种方式(桥接模式、nat模式、主机模…

虚拟列表技术深度解析:原理、实现与性能优化实战

虚拟列表技术深度解析:原理、实现与性能优化实战 引言 在当今数据驱动的互联网应用中,长列表渲染已成为前端开发的核心挑战。传统的一次性全量渲染方式在数据量超过千条时,往往导致页面卡顿、内存飙升等问题。虚拟列表(Virtual L…

服务器简介(含硬件外观接口介绍)

服务器(Server)是指提供资源、服务、数据或应用程序的计算机系统或设备。它通常比普通的个人计算机更强大、更可靠,能够长时间无间断运行,支持多个用户或客户端的请求。简单来说,服务器就是专门用来存储、管理和提供数…

c++下的onnx推理

参考代码:https://github.com/itsnine/yolov5-onnxruntime 参考链接:https://blog.csdn.net/magic_ll/article/details/125517798 1.下载onnx 官网:https://github.com/microsoft/onnxruntime/releases/tag/v1.21.0 2.下载代码 https://g…

TCP三次握手与四次挥手面试回答版本

面试官:说一下TCP三次握手的过程 参考面试回答: 在第一次握手的时候、客户端会随机生成初始化序号、放到TCP报文头部的序号字段中、同时把SYN标志设置为1 这样就表示SYN报文(这里是请求报文)。客户端将报文放入 TCP 报文首部的序…

0101基础知识-区块链-web3

文章目录 1 web3学习路线2 区块链简史2.1 区块链2.2 公共账本2.3 区块链的设计哲学2.3.1 去中心化2.3.2 共识2.3.2.1 上链2.3.2.2 共识算法 3 web3面向资产的互联网3.1 安全性和去中心化的权衡 4 智能合约4.1 以太坊智能合约4.2 去中心化应用 5 小结结语 1 web3学习路线 参考下…

工作纪实_63-Mac电脑使用brew安装软件

最近在接触kafka,想着在自己的电脑安装一套环境,docker也能行,但是还是想装一些原生的软件试试看,因此便想着整理一下brew的命令,这命令确实是方便,不需要下载tar包乱八七糟的东西,一键安装 bre…

Cadence学习笔记之---库元件制作、元件放置

目录 01 | 引 言 02 | 环境描述 03 | 工具介绍 04 | 无源器件的制作 05 | IC芯片制作 06 | 放置元件 07 | 结 语 01 | 引 言 在上一篇小记中,讲述使用Cadence创建原理图工程和元件库; 本篇小记主要讲述如何制作常用的库元件,如电阻、…

服务器如何修复SSL证书错误?

修复服务器上的SSL证书错误需要根据具体错误类型逐步排查和解决。以下是常见的步骤和解决方案: --- ### **1. 确认错误类型** 首先检查浏览器或工具(如OpenSSL)报错的具体信息,常见错误包括: - **证书过期**&#xf…

图解Mysql原理:深入理解事务的特性以及它的实现机制

前言 大家好,我是程序蛇玩编程。 Mysql中事务大家不陌生吧,事务就是要保证一组数据库操作,要么全部成功,要么全部失败。那它具有哪些特性,如何实现的呢?接着往下看。 正文 事务的特性: 事务的基本特性主要为四种…

Linux[指令与权限]

Linux指令与权限 Linux环境中,打包文件有多种 tar (打包/解包) 指令 tar -czvf 文件要打包到的位置 文件(打包并压缩到) tar -xzvf 文件(在当前目录下解压) tar选项 -c创建压缩文件 -z使用gzip属性压缩 -v展现压缩过程 -f后面使用新建文档名 -x不要新建,解压 -C 文件…