terraform:根据键过滤 map 列表

标签 terraform terraform-provider-aws terraform0.12+ hcl

我正在实现一个安全组模块,这样它将通过过滤 cidr 和 source_security_group_id 创建安全组规则来创建安全组规则。
当前模块配置。
安全组模块.tf

resource "aws_security_group" "this" {
  name                   = var.name
  description            = var.description
  vpc_id                 = var.vpc_id
  revoke_rules_on_delete = var.revoke_rules_on_delete
}

## CIDR Rule

resource "aws_security_group_rule" "cidr_rule" {
  count = length(var.security_group_rules)

  type              = var.security_group_rules[count.index].type
  from_port         = var.security_group_rules[count.index].from_port
  to_port           = var.security_group_rules[count.index].to_port
  protocol          = var.security_group_rules[count.index].protocol
  cidr_blocks       = var.security_group_rules[count.index].cidr_block
  description       = var.security_group_rules[count.index].description
  security_group_id = aws_security_group.this.id
}

## Source_security_group_id Rule

resource "aws_security_group_rule" "source_sg_id_rule" {
  count = length(var.security_group_rules)

  type              = var.security_group_rules[count.index].type
  from_port         = var.security_group_rules[count.index].from_port
  to_port           = var.security_group_rules[count.index].to_port
  protocol          = var.security_group_rules[count.index].protocol
  source_security_group_id = var.security_group_rules[count.index].source_security_group_id
  description       = var.security_group_rules[count.index].description
  security_group_id = aws_security_group.this.id
}
主文件
module "sample_sg" {
  source            = "./modules/aws_security_group"
  name              = "test-sg"
  vpc_id            = "vpc-xxxxxx"

  security_group_rules = [
    { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp", cidr_block = [var.vpc_cidr], description = "ssh" },
    { type = "ingress", from_port = 80, to_port = 80, protocol = "tcp", cidr_block = [var.vpc_cidr], description = "http" },
    { type = "ingress", from_port = 0, to_port = 0, protocol = "-1", source_sg_id = "sg-xxxx", description = "allow all" }
    { type = "egress",  from_port = 0, to_port = 0, protocol = "-1", source_sg_id = "sg-xxxx", description = "allow all" }
  ]
}
所以,这里的问题陈述是当我用上面的映射列表调用模块中的安全组规则时,它应该检查它是source_sg_id还是cidr。
然后过滤这些 map 并将其传递给模块中的相应资源。
前任:
module ""{
...

  security_group_rules = [
    { type = "ingress", from_port = 22, to_port = 22, protocol = "tcp", cidr_block = [var.vpc_cidr], description = "ssh" },
    { type = "ingress", from_port = 0, to_port = 65535, protocol = "-1", source_sg_id = "sg-xxxx", description = "allow all" }
  ]
}
应该查找这些规则并将第一个规则传递给 CIDR 规则,将第二个规则传递给 Source_security_group_id 规则。
我正在考虑使它如下
locals {

  sid_rules = some_function{var.security_group_rules, "source_security_group_id"}
  cidr_rules = some_function{var.security_group_rules, "cidr"}
}


resource "aws_security_group_rule" "cidr_rule" {
  count = count(local.cidr_rules)

  ....
  cidr_blocks       = local.cidr_rules[count.index].cidr_block
  ....
}


resource "aws_security_group_rule" "sid_rule" {
  count = count(local.sid_rules)

  ....
  source_security_group_id  = local.sid_rules[count.index].source_sg_id
  ....
}
所以,我正在寻找一种方法来根据 从列表中过滤 map 。关键
我尝试过查找,但在字符串列表的情况下没有帮助。

最佳答案

我想出了一个聪明的方法来做到这一点。
假设我试图只过滤猫的宠物kind = "cat"从宠物列表中。

variable "pets" {
  type = list(object({
    name = string
    kind = string
  }))
  default = [
    {
      name = "Fido"
      kind = "dog"
    },
    {
      name = "Max"
      kind = "dog"
    },
    {
      name = "Milo"
      kind = "cat"
    },
    {
      name = "Simba"
      kind = "cat"
    }
  ]
}
  • 先把宠物列表转成 map pets_map使用索引 tostring(i) 的宠物作为关键。
    这将在第 3 步中用于查找过滤后的宠物。
  • locals {
      pets_map = { for i, pet in var.pets : tostring(i) => pet }
    }
    
  • 接下来创建分别匹配条件 pet.kind == "cat" 的键的过滤列表
    通过循环 pets_map 中的键并将不匹配的相应键设置为
    空字符串。然后压缩从列表中删除空字符串的列表。
  • locals {
      cats_keys = compact([for i, pet in local.pets_map : pet.kind == "cat" ? i : ""])
    }
    
  • 循环过滤后的键 cats_keys并从 pets_map 中查找相应的宠物.现在轮到你
    有猫的过滤列表kind = "cat" .
  • locals {
      cats     = [for key in local.cats_keys : lookup(local.pets_map, key)]
    }
    
    您现在可以使用 local.cats 访问猫,这将为您提供以下 map 。
    {
      name = "Milo"
      kind = "cat"
    },
    {
      name = "Simba"
      kind = "cat"
    }
    
    下面是完整的例子。
    variable "pets" {
      type = list(object({
        name = string
        kind = string
      }))
      default = [
        {
          name = "Fido"
          kind = "dog"
        },
        {
          name = "Max"
          kind = "dog"
        },
        {
          name = "Milo"
          kind = "cat"
        },
        {
          name = "Simba"
          kind = "cat"
        }
      ]
    }
    
    locals {
      pets_map = { for i, pet in var.pets : tostring(i) => pet }
      cats_keys = compact([for i, pet in local.pets_map : pet.kind == "cat" ? i : ""])
      cats     = [for key in local.cats_keys : lookup(local.pets_map, key)]
    }
    

    关于terraform:根据键过滤 map 列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65956626/

    相关文章:

    Azure VMSS 通过 Terraform azapi 手动升级

    ssh - 如何使用 terraform 向 GCP 实例添加 ssh key ?

    azure - 创建 Neo4j vm Terraform Message="从 Marketplace 镜像创建虚拟机需要请求中的计划信息

    terraform aws_elasticsearch_domain - 如果 zone_awareness_enabled 为 false - 为什么要考虑而不是忽略 zone_awareness_config?

    terraform - 如何根据条件跳过 terraform 资源中的可选参数

    Terraform 提供者/模块中的变量共享

    terraform - user_data 中的命令不在 terraform 中执行

    unit-testing - Terratest - 使用模拟 AWS 服务

    amazon-ec2 - Terraform:AWS 目标组无法添加多个目标

    azure - terraform 显示返回 4 个 json 对象