terraform:基于键的地图过滤列表



我正在实现一个安全组模块,这样它将通过使用&过滤cidr &Source_security_group_id创建安全组规则。

当前模块配置。

securty_group_module.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
}

main.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" }
]
}

所以,这里的问题陈述是当我用上面的映射列表调用模块中的安全组规则时,它应该检查它是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" }
]
}

这些规则应该查阅&将第一个传递给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
....
}

所以,我正在寻找一种方法来过滤映射列表基于

我试过查找,但在字符串列表的情况下没有帮助。

我想到了一个聪明的方法。

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

您现在可以使用local.cats访问这些猫,这将为您提供以下映射:

{
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)]
}

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

module "security_groups" {
count             = length(var.security_group_rules)
source_sg_id_rule = var.security_group_rules[count.index].source_sg_id_rule
}

然后,在新模块中,使用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
}

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

感谢您的回复@dan-monego

我用单个模块本身来排序。

下面是模块文件

aws_sg_module.tf


# Security group
##########################
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
tags = merge(
{
"Name" = format("%s", var.name)
},
local.default_tags,
var.additional_tags
)
}
resource "aws_security_group_rule" "cidr" {
count = var.create ? length(var.cidr_sg_rules) : 0
type              = var.cidr_sg_rules[count.index].type
from_port         = var.cidr_sg_rules[count.index].from
to_port           = var.cidr_sg_rules[count.index].to
protocol          = var.cidr_sg_rules[count.index].protocol
cidr_blocks       = var.cidr_sg_rules[count.index].cidr
description       = var.cidr_sg_rules[count.index].description
security_group_id = local.this_sg_id
}
resource "aws_security_group_rule" "source_sg" {
count = var.create ? length(var.source_sg_rules) : 0
type                     = var.source_sg_rules[count.index].type
from_port                = var.source_sg_rules[count.index].from
to_port                  = var.source_sg_rules[count.index].to
protocol                 = var.source_sg_rules[count.index].protocol
source_security_group_id = var.source_sg_rules[count.index].source_sg_id
description              = var.source_sg_rules[count.index].description
security_group_id        = local.this_sg_id
}
resource "aws_security_group_rule" "self" {
count = var.create ? length(var.self_sg_rules) : 0
self              = true
type              = var.source_sg_rules[count.index].type
from_port         = var.source_sg_rules[count.index].from
to_port           = var.source_sg_rules[count.index].to
protocol          = var.source_sg_rules[count.index].protocol
description       = var.source_sg_rules[count.index].description
security_group_id = local.this_sg_id
}

使用下面的模块块调用。

security_groups.tf

module "stack_sg" {
source            = "./modules/aws_security_group"
name                = "stack-sg"
vpc_id = module.network.vpc_id
cidr_sg_rules = [
{ type = "ingress", from = 80, to = 80, protocol = "tcp",  cidr = [module.network.vpc_cidr], description = "http" },
{ type = "egress", from = 0, to = 65535, protocol = "-1",  cidr = ["0.0.0.0/0"], description = "allow all " }
]
source_sg_rules = [
{ type = "ingress", from = 0, to = 65535, protocol = "tcp", source_sg_id = module.alb_sg.sg_id, description = "alb" }
]
}

给定:

[{foo: "...", baz: "..."}, ...]

如果你想要这个列表中某个元素的baz,使用:

element([
for o in [{"foo"="kick","baz"="5"},{"foo"="bar","baz"="100"}] : 
o if o.foo == "bar"
],0).baz

为了使用特定键值过滤映射列表。您可以使用下面的简单语句:

假设:

  • key是映射的键,你正在过滤
  • val是键
  • 的值。
  • list是地图的原始列表
element([ 
for element in list) : env 
if element.key == "val" 
], 0)

上面语句的结果将是一个map。

相关内容

  • 没有找到相关文章

最新更新