terraform:根据键过滤地图列表

Arv*_*vin 11 terraform hcl terraform-provider-aws terraform0.12+

我正在实现一个安全组模块,以便它将通过获取和过滤 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
}
Run Code Online (Sandbox Code Playgroud)

主.tf

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" }
  ]
}
Run Code Online (Sandbox Code Playgroud)

因此,这里的问题陈述是当我使用上面的映射列表调用模块中的安全组规则时,它应该检查它是 source_sg_id 还是 cidr。

然后过滤这些映射并将其传递给模块中的相应资源。

前任:

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" }
  ]
}
Run Code Online (Sandbox Code Playgroud)

应查找这些规则并将第一个规则传递给 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
  ....
}
Run Code Online (Sandbox Code Playgroud)

所以,我正在寻找一种根据键从列表中过滤地图的方法

我尝试过查找,但对于字符串列表没有帮助。

Jam*_*ser 9

我想出了一个聪明的方法来做到这一点。

假设我试图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"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)
  1. pets_map首先使用索引tostring(i)作为键将宠物列表转换为宠物地图。这将在步骤 3 中用于查找过滤后的宠物。
locals {
  pets_map = { for i, pet in var.pets : tostring(i) => pet }
}
Run Code Online (Sandbox Code Playgroud)
  1. 接下来,通过循环遍历 中的键并将不匹配的相应键设置为空pet.kind == "cat" 字符串,创建分别与条件匹配的键的过滤列表。pets_map然后压缩列表,从列表中删除空字符串。
locals {
  cats_keys = compact([for i, pet in local.pets_map : pet.kind == "cat" ? i : ""])
}
Run Code Online (Sandbox Code Playgroud)
  1. 循环过滤后的键cats_keys并从 中查找相应的宠物pets_map。现在您已过滤出猫类宠物列表kind = "cat"
locals {
  cats     = [for key in local.cats_keys : lookup(local.pets_map, key)]
}
Run Code Online (Sandbox Code Playgroud)

您现在可以使用 访问猫local.cats,这将为您提供以下地图。

{
  name = "Milo"
  kind = "cat"
},
{
  name = "Simba"
  kind = "cat"
}
Run Code Online (Sandbox Code Playgroud)

下面是完整的示例。

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)]
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*ego 2

考虑创建另一个模块来处理规则,并在该模块内设置安全组资源。

module "security_groups" {
  count             = length(var.security_group_rules)
  source_sg_id_rule = var.security_group_rules[count.index].source_sg_id_rule
}
Run Code Online (Sandbox Code Playgroud)

然后,在新模块中,使用 count 语句作为测试来创建可选项目:

resource "aws_security_group_rule" "source_sg_id_rule" {
    count = length(var.source_sg_id_rule) == 0 ? 0 : 1

    type              = var.type
    from_port         = var.from_port
    to_port           = var.to_port
    protocol          = var.protocol
    source_security_group_id = var.source_security_group_id
    description       = var.description
    security_group_id = var.security_group_id
}
Run Code Online (Sandbox Code Playgroud)

这会将资源创建为由一个或零个项目组成的数组,并删除任何为零的列表。