Mapas multinivel de Terraform
Recibo errores en el "plan de terraformación" cuando trato de usar un mapa de varios niveles (más de 3 niveles) y parece que no puedo identificar el problema exacto. El error: "El valor dado no es válido para la variable "secgroups": elemento "bastion": se requiere el atributo "direction". ¿Mi variables.tf es correcto según lo asignado a secgroups.auto.tf? ports_min y ports_max serán una lista completa de puertos para abrir para el nombre del grupo de seguridad.
Versiones:
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.tfvars (solo un fragmento)
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"]
}
}
},
Principal.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
}
}
}
})
}
Respuestas
Hay varios problemas con sus definiciones.
Suponiendo que su total secgroups.auto.tfvarses:
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"]
}
}
}
}
La definición correspondiente debe ser:
variable "secgroups" {
type = map(map(map(object({
ports_min = list(number)
ports_max = list(number)
security_group_id = list(string)
}))))
}
Pero el objeto interno anterior eliminará todos los atributos adicionales, como remote_ip_prefixporque sus objetos son inconsistentes. Sin embargo , dado que ingress, y parecen ser consistentes, probablemente podría usar lo siguiente:egresstcpudp
variable "secgroups" {
type = map(object({
ingress = object({tcp = map(any), udp = map(any)})
egress = object({tcp = map(any), udp = map(any)})
}))
}
Como último recurso, si nada es consistente, puede usar:
variable "secgroups" {
type = map(map(map(map(any))))
}
Actualización: salida de prueba
output "test" {
value = var.secgroups.ssh_from_bastion.ingress.tcp.ports_min
}