Is there a way to loop through a range or list for a variable in terraform.
Below is what I would like to accomplish but I am not sure how to do it.
module "vlan_list" {
depends_on = [module.vlan_pools]
source = "../modules/add_vlans"
vlan_list = {
for i in range(1,100): {
"access" = {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = i
to = i
}
}
}
}
Let me add more information to it because unfortunately that didn't work. I get:
Error: Invalid value for module argument
on pools_vlan.tf line 34, in module "vlan_list":
34: vlan_list = {
35: for i in range(1, 100):
36: "access" => {
37: vlan_pool = module.vlan_pools.vlan_pool["access"]
38: from = i
39: to = i
40: }...
41: }
The given value is not suitable for child module variable "vlan_list" defined
at ../modules/add_vlans/variables.tf:5,1-21: element "access": object
required.
So I have created a module with the following
resource "aci_ranges" "add_vlan" {
for_each = local.vlan_list
alloc_mode = each.value["alloc_mode"]
annotation = each.value["annotation"]
name_alias = each.value["name_alias"]
vlan_pool_dn = each.value["vlan_pool"]
role = each.value["role"]
from = "vlan-${each.value["from"]}"
to = "vlan-${each.value["to"]}"
}
From Here I have defined a variables file to make it so users don't have to enter every variable... they can accept defaults
terraform {
experiments = [module_variable_optional_attrs]
}
variable "vlan_list" {
description = "Add VLANs to VLAN Pools"
type = map(object({
alloc_mode = optional(string)
annotation = optional(string)
from = optional(number)
name_alias = optional(string)
role = optional(string)
to = optional(number)
vlan_pool = optional(string)
}))
}
locals {
vlan_list = {
for k, v in var.vlan_list : k => {
alloc_mode = coalesce(v.alloc_mode, "static")
annotation = (v.annotation != null ? v.annotation : "")
from = (v.from != null ? v.from : 1)
name_alias = (v.name_alias != null ? v.name_alias : "")
role = coalesce(v.role, "external")
to = coalesce(v.to, 1)
vlan_pool = (v.vlan_pool != null ? v.vlan_pool : "")
}
}
}
So what I shared above is what someone would enter to consume the module... Here is a more complete example that I would like to do:
module "vlan_list" {
depends_on = [module.vlan_pools]
source = "../modules/add_vlans"
vlan_list = {
for i in range(1, 100):
"access" => {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = i
to = i
}...
for i in ranges([1000-1200], [1300-1400]):
"vmm_dynamic" => {
alloc_mode = "dynamic"
vlan_pool = module.vlan_pools.vlan_pool["vmm_dynamic"]
from = i
to = i
}...
for i in list[4, 100, 101]:
"l3out" => {
vlan_pool = module.vlan_pools.vlan_pool["l3out"]
from = i
to = i
}...
}
}
I know the second range on the vmm_dynamic key is not correct at all... I am just trying to show what I would like to be able to do if possible.
When the resource creates the entries, from the API, if I do it in a range as shown below; if someone needed to change the range for the first pool (in example) to 1-50,52-99, it would delete the entry and re-create it. whereas if they are creating the entry with each entry being created individually it wouldn't delete all of the individual entries, optimally.
I can do the following and it works fine... but being able to add the VLANs individually from a loop would be preferable.
module "vlan_list" {
depends_on = [module.vlan_pools]
source = "../modules/add_vlans"
vlan_list = {
"access" = {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = 1
to = 99
},
"vmm_dynamic" = {
alloc_mode = "dynamic"
vlan_pool = module.vlan_pools.vlan_pool["vmm_dynamic"]
from = 1000
to = 1199
},
"l3out_1" = {
vlan_pool = module.vlan_pools.vlan_pool["l3out"]
from = 4
to = 4
},
"l3out_2" = {
vlan_pool = module.vlan_pools.vlan_pool["l3out"]
from = 100
to = 101
},
}
}
Thanks in advance for help on this.
Just as one more point of reference... This is how I had previously accomplished this with Python, but I am trying to move this to native Terraform
def vlan_list_full(vlan_list):
full_vlan_list = []
if re.search(r',', str(vlan_list)):
vlist = vlan_list.split(',')
for v in vlist:
if re.fullmatch('^\\d{1,4}\\-\\d{1,4}$', v):
a,b = v.split('-')
a = int(a)
b = int(b)
vrange = range(a,b+1)
for vl in vrange:
full_vlan_list.append(vl)
elif re.fullmatch('^\\d{1,4}$', v):
full_vlan_list.append(v)
elif re.search('\\-', str(vlan_list)):
a,b = vlan_list.split('-')
a = int(a)
b = int(b)
vrange = range(a,b+1)
for v in vrange:
full_vlan_list.append(v)
else:
full_vlan_list.append(vlan_list)
return full_vlan_list
def vlan_pool
for z in range(1, 3):
vgroup = 'VLAN_Grp%s' % (z)
vgrp = 'VGRP%s_Allocation' % (z)
templateVars['Allocation_Mode'] = templateVars[vgrp]
if re.search(r'\d+', str(templateVars[vgroup])):
vlan_list = vlan_list_full(templateVars[vgroup])
for v in vlan_list:
vlan = str(v)
if re.fullmatch(r'\d+', vlan):
templateVars['VLAN_ID'] = int(vlan)
# Add VLAN to VLAN Pool File
create_tf_file('a+', dest_dir, dest_file, template, **templateVars)
I can't seem to find any examples of how to do this without Python.
If you want to create a map with a single key of access
and a list of values, then you can use ellipsis operator (...
). Also your syntax is incorrect. Thus, the following should be used in this case:
vlan_list = {
for i in range(1, 100):
"access" => {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = i
to = i
}...
}
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