Terraform 从具有公共值的映射中获取第一个唯一键
我有一个部署定义,其中我有一个CIDR块到区域的映射。CIDR当然需要是唯一的,但值可以重复。在本例中,我将CIDR块转到三个不同的区域,Terraform 从具有公共值的映射中获取第一个唯一键,terraform,Terraform,我有一个部署定义,其中我有一个CIDR块到区域的映射。CIDR当然需要是唯一的,但值可以重复。在本例中,我将CIDR块转到三个不同的区域,us-west-1,us-west-2,以及us-east-1 cidr_region_map = { "10.0.0.0/24" = "us-west-1", "10.0.1.0/24" = "us-east-1", "10.0.3.0/24"
us-west-1
,us-west-2
,以及us-east-1
cidr_region_map = {
"10.0.0.0/24" = "us-west-1",
"10.0.1.0/24" = "us-east-1",
"10.0.3.0/24" = "us-east-1",
"10.0.4.0/24" = "us-west-1",
"10.0.5.0/24" = "us-west-2",
"10.0.6.0/24" = "us-east-1",
}
我需要得到一个数组,在这里我可以从这张地图中为每个区域挑选出第一个CIDR。这意味着我最终会得到这样一个列表:
[
“10.0.1.0/24”,//us-east-1
“10.0.0.0/24”//us-west-1
“10.0.5.0/24”//us-west-2
]
此列表中应忽略来自我们已经考虑的地区的任何其他CIDR。任何人都可以快速复制/粘贴的解决方案 操场。tf
locals {
cidr_region_map = {
"10.0.0.0/24" = "us-west-1",
"10.0.1.0/24" = "us-east-1",
"10.0.3.0/24" = "us-east-1",
"10.0.4.0/24" = "us-west-1",
"10.0.5.0/24" = "us-west-2",
"10.0.6.0/24" = "us-east-1",
}
group_by = values(
zipmap(
reverse(values(local.cidr_region_map)),
reverse(keys(local.cidr_region_map))
)
)
}
output "test_out_2" {
value = local.group_by
}
输出
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
test_out_2 = [
"10.0.1.0/24",
"10.0.0.0/24",
"10.0.5.0/24",
]
工作原理 为了简单起见,我将解释这个魔法如何与“变量”一起工作,以更好地可视化正在发生的事情
keys(map) = CIDR: ["10.0.0.0/24", "10.0.1.0/24", "10.0.3.0/24", "10.0.4.0/24", "10.0.5.0/24", "10.0.6.0/24"]
values(map) = VALS: ["us-west-1", "us-east-1", "us-east-1", "us-west-1", "us-west-2", "us-east-1"]
地图在地形中的工作方式是它们只能有一把钥匙。如果尝试将现有密钥添加到映射,它将替换旧密钥。例如,如果你这样做
{
“us-east-1”=“10.0.3.0/24”//将删除此选项
“美国东部-1”=“10.0.1.0/24”
}
首先,我们要反转原始的键/值列表,这样列表中的键/值越低,优先级就越低,因为第一个键/值将稍后添加到映射中,以便覆盖原始值
r_CIDR = reverse(CIDR) = ["10.0.6.0/24", "10.0.5.0/24", "10.0.4.0/24", "10.0.3.0/24", "10.0.1.0/24", "10.0.0.0/24"]
r_VALS = reverse(VALS) = ["us-east-1", "us-west-2", "us-west-1", "us-east-1", "us-east-1", "us-west-1"]
现在我们已经反转了这些值,我们使用zipmap
来创建一个新的映射
zipmap(r_VALS,, r_CIDR) = {
"us-east-1" = "10.0.6.0/24" // this will be dropped
"us-west-2" = "10.0.5.0/24"
"us-west-1" = "10.0.4.0/24" // this will be dropped
"us-east-1" = "10.0.3.0/24" // this will be dropped
"us-east-1" = "10.0.1.0/24"
"us-west-1" = "10.0.0.0/24"
}
在内部删除所有重复的键之后,您将得到以下映射
zipmap(r_VALS,, r_CIDR) = {
"us-west-2" = "10.0.5.0/24"
"us-east-1" = "10.0.1.0/24"
"us-west-1" = "10.0.0.0/24"
}
最后,您获取该映射的值,剩下的是唯一的值
values(zipmap) = ["10.0.1.0/24", "10.0.0.0/24", "10.0.5.0/24"]
这个问题似乎更容易用反转贴图来解决,这样值就是键,键就是值。我们可以使用
for
表达式来实现这一点,使用..
修饰符来激活,以允许每个区域可能存在多个CIDR范围:
locals {
cidr_region_map = {
"10.0.0.0/24" = "us-west-1",
"10.0.1.0/24" = "us-east-1",
"10.0.3.0/24" = "us-east-1",
"10.0.4.0/24" = "us-west-1",
"10.0.5.0/24" = "us-west-2",
"10.0.6.0/24" = "us-east-1",
}
region_cidr_map = {
for cidr, region in local.cidr_region_map : region => cidr...
}
}
这将生成字符串列表的映射,如下所示:
{
us-west-1 = {
"10.0.0.0/24",
"10.0.4.0/24",
}
us-east-1 = {
"10.0.1.0/24",
"10.0.3.0/24",
"10.0.6.0/24",
}
us-west-2 = {
"10.0.6.0/24",
}
}
因为for表达式只有在键至少有一个值的情况下才会包含一个键,所以我们可以假设所有列表都至少有一个元素,因此对于第一个元素,我们可以使用[0]
正常访问它:
这将产生以下内容,我认为符合您的要求:
{
us-west-1 = "10.0.0.0/24"
us-east-1 = "10.0.1.0/24"
us-west-2 = "10.0.6.0/24"
}
(如果您只需要CIDR块本身,而不关心每个块属于哪个区域,则可以在此地图上使用值
。)
请注意,它从每个区域中选择哪个CIDR块将由Terraform在表达式的中对地图的遍历顺序决定,该顺序是按键的词法顺序。由于原始地图上有CIDR块作为键,因此决定顺序的是CIDR块的词法顺序,而这恰好与直观的数字顺序相匹配,其中每个地址都有相同的位数,但如果使用例如10.0.10.0/24
和10.0.2.0/24
,则情况并非如此,因为10.0.10.0/24
在词汇上是“在”10.0.2.0/24
之前”,即使在数字上不是这样
{
us-west-1 = "10.0.0.0/24"
us-east-1 = "10.0.1.0/24"
us-west-2 = "10.0.6.0/24"
}