Terraform 多层地图
Terraform multi-level maps
我在尝试使用多级地图(3 级以上)时遇到有关“terraform plan”的错误,而且我似乎无法指出确切的问题。错误:“给定值对变量“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
variables.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.tf变量(只是一个片段)
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
}
}
}
})
}
您的定义有几个问题。
假设您的完整 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
}
我在尝试使用多级地图(3 级以上)时遇到有关“terraform plan”的错误,而且我似乎无法指出确切的问题。错误:“给定值对变量“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
variables.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.tf变量(只是一个片段)
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
}
}
}
})
}
您的定义有几个问题。
假设您的完整 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
}