Terraform peta multi-level

Aug 27 2020

Saya mendapatkan kesalahan pada "terraform plan" saat mencoba menggunakan peta multi-level (3+ level) dan sepertinya tidak dapat memastikan masalah yang sebenarnya. Kesalahan: "Nilai yang diberikan tidak valid untuk variabel" secgroups ": elemen" bastion ": atribut" direction "diperlukan." Apakah variable.tf saya benar seperti yang dipetakan ke secgroups.auto.tf? ports_min dan ports_max akan menjadi daftar semua port yang akan dibuka untuk nama grup keamanan.

Versi:

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

variable.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 (hanya cuplikan)

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

Jawaban

Marcin Aug 27 2020 at 08:00

Ada beberapa masalah dengan definisi Anda.

Dengan asumsi bahwa kenyang Anda secgroups.auto.tfvarsadalah:

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

Definisi yang sesuai harus:

variable "secgroups" {
  type = map(map(map(object({
        ports_min         = list(number)
        ports_max         = list(number)
        security_group_id = list(string)
      }))))
}

Tetapi objek dalam di atas akan menghilangkan semua atribut tambahan, seperti remote_ip_prefixkarena objek Anda tidak konsisten. Namun, karena ingress, egress, tcpdan udptampaknya konsisten, Anda mungkin bisa menggunakan berikut:

variable "secgroups" {
  type = map(object({
            ingress = object({tcp = map(any), udp = map(any)})
            egress =  object({tcp = map(any), udp = map(any)})
        }))
}

Sebagai sumber daya terakhir, jika tidak ada yang konsisten, Anda dapat menggunakan:

variable "secgroups" {
  type = map(map(map(map(any))))
}

Pembaruan: keluaran uji

output "test" {
  value = var.secgroups.ssh_from_bastion.ingress.tcp.ports_min
}