Reputation: 717
Requirements: I have a bunch of EC2s. Which I am grouping according to the Tags. in this example total number of group =4 and each group has 7 EC2 : 1 parent-6 Child. here i am sharing code of child whose naming matters.
working code:Here I am sharing the child EC2 code which is working perfectly fine with the input variables of map type named :ws_to_Child_Node_name_map_count. Now i want it to be scalable(number of parent-child) for which I am looking to use 'dynamically created map in locals' instead of using input variable. main.tf
resource "aws_instance" "ec2_instance_child" {
count = var.ec2_instance_child_count
tags = {
NodeName = "${lookup(var.ws_to_Child_Node_name_map_count, count.index+1, 99)}"
}
}
variable.tf
variable "ws_to_Child_Node_name_map_count" {
type = map
default = {
"1"="1"
"2"="2"
"3"="3"
"4"="4"
"5"="5"
"6"="6"
"7"="1"
"8"="2"
"9"="3"
"10"="4"
"11"="5"
"12"="6"
"13"="1"
"14"="2"
"15"="3"
"16"="4"
"17"="5"
"18"="6"
"19"="1"
"20"="2"
"21"="3"
"22"="4"
"23"="5"
"24"="6"
}
}
variable "ec2_instance_child_count" {
description = "Number of instances to run"
default = "24" #number of group *6
}
the map shown above I want to create dynamically using two variables, which in future i will not be constant.
variable "child_count" {
default = 6
}
variable "group_count" {
default = 4
}
Upvotes: 1
Views: 24177
Reputation: 74064
The mapping table you wrote here seems to be describing a variant of the modulo operation that starts counting at one rather than zero.
If that's your intent, you could potentially calculate this dynamically using an expression rather than producing a separate mapping table.
variable "child_count" {
default = 6
}
variable "group_count" {
default = 4
}
resource "aws_instance" "example" {
count = var.child_count * var.group_count
tags = {
# The % symbol is Terraform's modulo operator
NodeName = ((count.index - 1) % var.child_count) + 1
}
}
The - 1
and + 1
in the expression above are allowing for the fact that you are using one-based counting rather than zero-based counting. For zero-based, this would reduce to count.index % var.child_count
.
If you still want to make the mapping table in a local value for some reason, you can perform the above calculation inside a for
expression instead:
locals {
lookup_table = {
for n in range(1, (var.child_count * var.group_count) + 1) :
n => ((n - 1) % var.child_count) + 1
}
}
This uses the range
function to count from 1 up to your total count, and then produces a map with one element per element of that result where the value is the result of the same modulo calculation I showed in the resource
block above.
From Terraform 0.12 onwards it is never necessary to use null_resource
or null_data_source
as a hack to transform lists, because the for
expression syntax can now meet the same use-cases.
Upvotes: 5
Reputation: 1642
i can help you create a dynamic list of maps with terraform using a hack here's an example :
locals {
childs = 24
group = [1,2,3,4,5,6]
}
# Here's the hack! The null_resource has a map called triggers that we can set to arbitrary values.
# We can also use count to create a list of null_resources. By accessing the triggers map inside of
# that list, we get our list of maps! See the output variable below.
resource "null_resource" "res" {
count = local.childs+1
triggers = {
parent = "${count.index}"
child = "${element(local.group, count.index)}"
}
}
# And here's the result! We have a dynamic list of maps. I'm just outputting it here
output "map" {
value = "${null_resource.res.*.triggers}"
}
you can try it create a main.tf and run terraform init
terraform apply
the result should be like this :
map = [
{
"child" = "1"
"parent" = "0"
},
{
"child" = "2"
"parent" = "1"
},
{
"child" = "3"
"parent" = "2"
},
{
"child" = "4"
"parent" = "3"
},
{
"child" = "5"
"parent" = "4"
},
{
"child" = "6"
"parent" = "5"
},
{
"child" = "1"
"parent" = "6"
},
{
"child" = "2"
"parent" = "7"
},
{
"child" = "3"
"parent" = "8"
},
{
"child" = "4"
"parent" = "9"
},
{
"child" = "5"
"parent" = "10"
},
{
"child" = "6"
"parent" = "11"
},
{
"child" = "1"
"parent" = "12"
},
{
"child" = "2"
"parent" = "13"
},
{
"child" = "3"
"parent" = "14"
},
{
"child" = "4"
"parent" = "15"
},
{
"child" = "5"
"parent" = "16"
},
{
"child" = "6"
"parent" = "17"
},
{
"child" = "1"
"parent" = "18"
},
{
"child" = "2"
"parent" = "19"
},
{
"child" = "3"
"parent" = "20"
},
{
"child" = "4"
"parent" = "21"
},
{
"child" = "5"
"parent" = "22"
},
{
"child" = "6"
"parent" = "23"
},
{
"child" = "1"
"parent" = "24"
},
]
If you want to check every parent and every child (you can use locals) you can create a 2 loops like this :
locals {
childs = 24
group = 6
result = {
for j in range(1, local.childs + 1) : j => [
for i in range(1, local.group + 1) : {
child = i,
parent = j
}
]
}
}
your output will be grouped by parents like this :
"1" = [
{
"child" = 1
"parent" = 1
},
{
"child" = 2
"parent" = 1
},
{
"child" = 3
"parent" = 1
},
{
"child" = 4
"parent" = 1
},
{
"child" = 5
"parent" = 1
},
{
"child" = 6
"parent" = 1
},
]
"2" = [
{
"child" = 1
"parent" = 2
},
{
"child" = 2
"parent" = 2
},
{
"child" = 3
"parent" = 2
},
{
"child" = 4
"parent" = 2
},
{
"child" = 5
"parent" = 2
},
{
"child" = 6
"parent" = 2
},
]
Upvotes: 2