I have two lists in a terraform module...
cidr_blocks = ["1.2.3.4/32","5.6.7.8/32"]
and I have another list of settings for a network ACL
ingress_ports = [
{
from_port = 80
to_port = 80
protocol = "tcp"
},
{
from_port = 443
to_port = 443
protocol = "tcp"
},
{
from_port = 22
to_port = 22
protocol = "tcp"
}
]
and I want to join these lists together so I can then use the resulting list to create a network ACL.
result = [
{
cidr_block = "1.2.3.4/32"
from_port = 80
to_port = 80
protocol = "tcp"
},
{
cidr_block = "1.2.3.4/32"
from_port = 443
to_port = 443
protocol = "tcp"
},
{
cidr_block = "1.2.3.4/32"
from_port = 22
to_port = 22
protocol = "tcp"
},
{
cidr_block = "5.6.7.8/32"
from_port = 80
to_port = 80
protocol = "tcp"
},
{
cidr_block = "5.6.7.8/32"
from_port = 443
to_port = 443
protocol = "tcp"
},
{
cidr_block = "5.6.7.8/32"
from_port = 22
to_port = 22
protocol = "tcp"
}
]
Is this sort of thing possible in Terraform ?
In terraform 0.12, we can finally use setproduct which makes this endeavor a lot easier:
cronjobs = [
{
schedule_expression = "cron(5 0 * * ? *)"
command_and_arguments = ["app/aws-console.sh", "task1"]
description = "Hello World"
},
{
schedule_expression = "cron(0 5 1 * ? *)"
command_and_arguments = ["app/aws-console.sh", "task2"]
description = "Send Bills"
}
]
environments = ["dev", "stage"]
locals {
cronjobs_for_all_environments = setproduct(var.cronjobs, var.environments)
}
resource "aws_cloudwatch_event_rule" "cronjob" {
count = length(local.cronjobs_for_all_environments)
name = "cronjob-${local.cronjobs_for_all_environments[count.index][1]}"
description = "${local.cronjobs_for_all_environments[count.index][0].description} (${local.cronjobs_for_all_environments[count.index][1]})"
schedule_expression = local.cronjobs_for_all_environments[count.index][0].schedule_expression
}
Here is a solution I used Below is your test terraform script
provider "aws" {
region = "us-east-1"
}
variable "lista" {
default = ["1", "2", "3"]
}
variable "listb" {
default = ["A", "B", "C", "D"]
}
resource "aws_eip" "eip" {
count = "${length(var.lista) * length(var.listb)}"
tags {
Name = "test-eip ${count.index}. ${element(var.lista, ceil(count.index/length(var.listb)))}:${element(var.listb, count.index)}"
}
}
to test run terraform plan | grep tags.Name
below is the output
tags.Name: "0. 1:A"
tags.Name: "1. 1:B"
tags.Name: "2. 1:C"
tags.Name: "3. 1:D"
tags.Name: "4. 2:A"
tags.Name: "5. 2:B"
tags.Name: "6. 2:C"
tags.Name: "7. 2:D"
tags.Name: "8. 3:A"
tags.Name: "9. 3:B"
tags.Name: "10. 3:C"
tags.Name: "11. 3:D"
Here's what I came up with. I remembered that there is a way to use modulo and integer division to perform what I wanted to do. I did this for both ingress and egress but I will only show ingress. To aid in the flexibility of using this in a module, I create the Network ACL outside of the module and pass it in.
Example module on Github
Variables:
variable "acl-id" {}
variable "offset" {}
variable "ingress-rules" {
type = "list"
description = "The List of Ingress Rules. Each item in the list is a map. The Maps will be joined with the 'ingress-cidr'"
}
variable "ingress-cidr" {
type = "list"
description = "List of IPv4 CIDR ranges to apply to all ingress rules"
}
Locals: I created these for some clarity.
locals {
ingress-cidr-size = "${length( var.ingress-cidr )}"
ingress-rules-size = "${length( var.ingress-rules )}"
ingress-join-size = "${local.ingress-cidr-size * local.ingress-rules-size}"
ingress-joined-rules-cidrs = "${data.null_data_source.ingress-join.*.outputs}"
}
Data:
#Perform a cartesian like join of all of the CIDRs to apply to all of the rules
data "null_data_source" "ingress-join" {
count = "${local.ingress-join-size}"
inputs = {
rule-number = "${count.index + var.offset}"
cidr-block = "${ var.ingress-cidr[count.index / local.ingress-rules-size] }"
from-port = "${ lookup ( var.ingress-rules[count.index % local.ingress-rules-size], "from-port" ) }"
to-port = "${ lookup ( var.ingress-rules[count.index % local.ingress-rules-size], "to-port" ) }"
action = "${ lookup ( var.ingress-rules[count.index % local.ingress-rules-size], "action" ) }"
protocol = "${ lookup ( var.ingress-rules[count.index % local.ingress-rules-size], "protocol" ) }"
}
}
The Network ACL Rule configuration:
##########################
# Ingress - Maps of rules
##########################
# Takes a list of 'ingress-rules' where each list item is a Map with the following keys
# action: ether "allow" or "deny"
# from-port: a port number
# to-port: a port number
# protocol: A string like "tpc" or "-1"
# rule-number: A unique value to prevent collisions with other rules
# cidr-block: The CIDR that is applied to this rule
resource "aws_network_acl_rule" "ingress-rules-and-cidr-list" {
count = "${var.create ? local.ingress-join-size : 0}"
network_acl_id = "${var.acl-id}"
egress = false
rule_number = "${lookup( local.ingress-joined-rules-cidrs[count.index], "rule-number", "")}"
rule_action = "${lookup( local.ingress-joined-rules-cidrs[count.index], "action", "")}"
cidr_block = "${lookup(local.ingress-joined-rules-cidrs[count.index], "cidr-block", "")}"
from_port = "${lookup(local.ingress-joined-rules-cidrs[count.index], "from-port", "")}"
to_port = "${lookup(local.ingress-joined-rules-cidrs[count.index], "to-port", "")}"
protocol = "${lookup(local.ingress-joined-rules-cidrs[count.index], "protocol", "")}"
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With