Home > Enterprise >  How to list all items in a list in Terraform and what's the for loop equivalent here?
How to list all items in a list in Terraform and what's the for loop equivalent here?

Time:11-16

I am kind of new to Terraform and could you help me with the lists in terraform.

This is my code

variable  "ip_bitbucket" {
  type = "list"
}
ip_bitbucket = ["34.199.54.113/32","34.232.25.90/32","34.232.119.183/32","34.236.25.177/32","35.171.175.212/32","52.54.90.98/32","52.202.195.162/32","52.203.14.55/32","52.204.96.37/32","34.218.156.209/32","34.218.168.212/32","52.41.219.63/32","35.155.178.254/32","35.160.177.10/32","34.216.18.129/32","3.216.235.48/32","34.231.96.243/32","44.199.3.254/32","174.129.205.191/32","44.199.127.226/32","44.199.45.64/32","3.221.151.112/32","52.205.184.192/32","52.72.137.240/32"]

and need to access the list as below

resource "aws_security_group_rule "server_rule" {
  type              = "ingress"
  from_port         = 443
  to_port           = 22
  protocol          = "tcp"
 # for each = var.ip_bitbucket
  cidr_blocks       = 
  security_group_id = data.aws_security_group.server_sg.id
}

How do i access the variable ip_bitbucket in cidr block?

I was trying with count and element but not getting clear idea

CodePudding user response:

You can use toset built-in function [1] for that:

resource "aws_security_group_rule "server_rule" {
  for_each          = toset(var.ip_bitbucket)
  type              = "ingress"
  from_port         = 443
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = each.value
  security_group_id = data.aws_security_group.server_sg.id
}

[1] https://developer.hashicorp.com/terraform/language/functions/toset

CodePudding user response:

The for_each argument requires either a map value (with any element type) or a set of strings. Your input variable is currently declared as being a list, and so it isn't directly compatible with for_each.

It seems like the order of the elements in ip_bitbucket has no significance and so I think the best answer would be to change the type constraint of that variable to be set(string), which is a more accurate description of how you will use that value:

variable  "ip_bitbucket" {
  type = set(string)
}

However, you can specify more than one CIDR block in a single security group rule so you may not actually need for_each at all here:

resource "aws_security_group_rule" "server_rule" {
  type              = "ingress"
  from_port         = 443
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = var.ip_bitbucket
  security_group_id = data.aws_security_group.server_sg.id
}

The above will declare a single rule which applies to all of the given CIDR ranges.

If you do still want to use for_each then you can use var.ip_bitbucket as the for_each value once you've changed its type constraint as described above:

resource "aws_security_group_rule" "server_rule" {
  for_each = var.ip_bitbucket

  type              = "ingress"
  from_port         = 443
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = [each.value]
  security_group_id = data.aws_security_group.server_sg.id
}

Noice that each.value needs to be in brackets here because each.value is just a single element from var.ip_bitbucket, and so it's a single string. cidr_blocks expects a set of strings.

If some other part of your module that you've not shown here does rely on the specific ordering of the elements in var.ip_bitbucket then you could leave it declared as a list and then convert it to a set inside the for_each argument. However, I would recommend this only if you really do need to preserve the order of these elements, because users or future maintainers of your module may assume that the ordering is important if you declare it as a list.

variable  "ip_bitbucket" {
  type = list(string)
}

resource "aws_security_group_rule" "server_rule" {
  for_each = toset(var.ip_bitbucket)

  type              = "ingress"
  from_port         = 443
  to_port           = 22
  protocol          = "tcp"
  cidr_blocks       = [each.value]
  security_group_id = data.aws_security_group.server_sg.id
}

This is the same as the previous example except that the conversion from list to set happens explicitly with the toset function, rather than automatically as Terraform prepares the value of var.ip_bitbucket.

  • Related