简体   繁体   中英

Terraform - Dynamic block to loop through list of objects

I'm trying to have this Terraform configured so that all someone needs to do to add a new SG ingress rule is to add a block to the .tfvars file, and the new ingress rule will be added to the single SG.

I have a .tfvars file that looks like this:

rules = [
  {
    protocol = "tcp"
    port = 22
    cidr = ["10.0.0.0/8"],
  },
  {
    protocol = "tcp"
    port = 80
    cidr = ["10.0.0.0/8"]
  },
  {
    protocol = "tcp"
    port = 443
    cidr = ["10.0.0.0/8"]
  },
  {
    protocol = "icmp"
    port = -1
    cidr = ["10.0.0.0/8"]
  }
]

And my Terraform is:

variable "rules" {
  type = list(object({
    protocol = string
    port = number
    cidr = list(string)
  }))
  description = "Specify the protocol, port range, and CIDRs."
}


resource "aws_security_group" "this" {
...

dynamic "ingress" {
  for_each = { for rule in var.rules : rule.id => rule }

  content {
    from_port   = var.rules.port
    to_port     = var.rules.port
    protocol    = var.rules.protocol
    cidr_blocks = var.rules.cidr
  }
}

...

I've tried to loop through the above, and also with using for_each = var.rules but I just get the following error (occurs for each of the below):

protocol     = var.rules.protocol
from_port    = var.rules.port
to_port      = var.rules.port
cidr_blocks  = var.rules.cidr
-----------------------------
var.rules is list of object with 4 elements. 
This value does not have any attributes.`

I'm a bit stuck and not sure what else to try, so does anyone have any ideas?

There are a couple of issues here. The first is in your for_each meta-argument value for expression lambda, you are attempting to access a non-existent object key of id . Also, you can easily just use a list(object) here instead of a map(object) like you are trying to do in your transformation, and then your input variable can be used directly. We can discard those and fix the value accordingly:

for_each = var.rules

The second issue is that your temporary lambda iterator variable in a dynamic block is the name of the block itself. In this case, your block is named ingress . Therefore, we need to access values from its object keys:

content {
  from_port   = ingress.value.port
  to_port     = ingress.value.port
  protocol    = ingress.value.protocol
  cidr_blocks = ingress.value.cidr
}

Combining these fixes, we arrive at:

dynamic "ingress" {
  for_each = var.rules

  content {
    from_port   = ingress.value.port
    to_port     = ingress.value.port
    protocol    = ingress.value.protocol
    cidr_blocks = ingress.value.cidr
  }
}

main.tf :

  dynamic nodes {
    for_each = var.rke_nodes
    content {
      address           = nodes.value.public_ip
      internal_address  = nodes.value.private_ip
      hostname_override = nodes.value.hostname
      user              = nodes.value.user
      role              = nodes.value.roles
      ssh_key           = nodes.value.ssh_key
    }
  }

variable.tf :

variable "rke_nodes" {
  type = list(object({
    public_ip = string
    private_ip = string
    hostname = string
    roles = list(string)
    user = string
    ssh_key = string
  }))
  description = "Node info to install RKE cluster"
}

Getting the below error :

│ Error: Invalid dynamic for_each value
│
│   on .terraform/modules/rke-cluster/main.tf line 6, in resource "rke_cluster" "rancher_cluster":
│    6:     for_each = var.rke_nodes
│     ├────────────────
│     │ var.rke_nodes has a sensitive value
│
│ Cannot use a list of object value in for_each. An iterable collection is required.
╵

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM