Terraformマルチレベルマップ
Aug 27 2020
マルチレベルマップ(3レベル以上)を使用しようとすると、「テラフォームプラン」でエラーが発生し、正確な問題に指を置くことができないようです。エラー:「指定された値は変数「secgroups」には無効です:要素「bastion」:属性「direction」が必要です。」私のvariables.tfはsecgroups.auto.tfにマップされているように正しいですか?ports_minとports_maxは、セキュリティグループ名用に開くポートの包括的なリストになります。
バージョン:
Terraform v0.13.0
+ provider registry.terraform.io/hashicorp/local v1.4.0
+ provider registry.terraform.io/hashicorp/null v2.1.2
+ provider registry.terraform.io/hashicorp/tls v2.2.0
+ provider registry.terraform.io/terraform-providers/openstack v1.26.0
変数.tf
variable "secgroups" {
type = map(object({
direction = (map(object({
protocols = (map(object({
name = string
description = string
ports_min = list(number)
ports_max = list(number)
remote_ip_prefix = list(string)
remote_group_id = list(string)
security_group_id = list(string)
})))
})))
}))
}
secgroups.auto.tfvars(単なるスニペット)
ssh_from_bastion = {
ingress = {
tcp = {
ports_min = [22]
ports_max = [22]
remote_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
},
udp = {
ports_min = [0]
ports_max = [0]
remote_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
}
},
egress = {
tcp = {
ports_min = [0]
ports_max = [0]
remote_ip_prefix = ["0.0.0.0/0"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
},
udp = {
ports_min = [0]
ports_max = [0]
remote_ip_prefix = ["0.0.0.0/0"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
}
}
},
Main.tf
locals {
security_groups = flatten({
for secgroup_name,direction in var.secgroups : {
name = each.secgroup_name
description = "Security group for ${each.secgroup_name}"
for protocol,config in each.direction : {
direction = each.direction
protocol = each.protocol
for config_value in config : {
ports_min = each.config_value.ports_min
ports_max = each.config_value.ports_max
remote_ip_prefix = each.config_value.remote_ip_prefix
security_group_id = each.config_value.security_group_id
}
}
}
})
}
回答
Marcin Aug 27 2020 at 08:00
定義にはいくつかの問題があります。
あなたのフルsecgroups.auto.tfvarsが次のとおりであると仮定します:
secgroups = {
ssh_from_bastion = {
ingress = {
tcp = {
ports_min = [22]
ports_max = [22]
remote_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
},
udp = {
ports_min = [0]
ports_max = [0]
remote_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
}
},
egress = {
tcp = {
ports_min = [0]
ports_max = [0]
remote_ip_prefix = ["0.0.0.0/0"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
},
udp = {
ports_min = [0]
ports_max = [0]
remote_ip_prefix = ["0.0.0.0/0"]
security_group_id = ["openstack_networking_secgroup_v2.bastion.id"]
}
}
}
}
対応する定義は次のとおりです。
variable "secgroups" {
type = map(map(map(object({
ports_min = list(number)
ports_max = list(number)
security_group_id = list(string)
}))))
}
ただし、上記の内部オブジェクトはremote_ip_prefix、オブジェクトに一貫性がないなどの理由で、すべての余分な属性を削除します。しかし、以来ingress、egress、tcpとudp一貫しているように見える、あなたはおそらく次のように使用できます。
variable "secgroups" {
type = map(object({
ingress = object({tcp = map(any), udp = map(any)})
egress = object({tcp = map(any), udp = map(any)})
}))
}
最後のリソースとして、一貫性のあるものがない場合は、次を使用できます。
variable "secgroups" {
type = map(map(map(map(any))))
}
更新:テスト出力
output "test" {
value = var.secgroups.ssh_from_bastion.ingress.tcp.ports_min
}