#terraform
#терраформирование
Вопрос:
Есть ли способ перебирать диапазон или список для переменной в terraform.
Ниже приведено то, чего я хотел бы достичь, но я не уверен, как это сделать.
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
}
}
}
}
Позвольте мне добавить к нему больше информации, потому что, к сожалению, это не сработало. Я получаю:
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.
Итак, я создал модуль со следующим
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"]}"
}
Отсюда я определил файл переменных, чтобы пользователям не приходилось вводить каждую переменную… они могут принимать значения по умолчанию
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 : "")
}
}
}
Итак, то, чем я поделился выше, — это то, что кто-то мог бы ввести, чтобы использовать модуль… Вот более полный пример, который я хотел бы сделать:
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
},
}
}
Заранее спасибо за помощь в этом вопросе.
Просто как еще одна точка отсчета… Вот как я ранее добивался этого с помощью Python, но я пытаюсь перенести это на родной 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}
Кажется, я не могу найти ни одного примера того, как это сделать без Python.
Ответ №1:
Если вы хотите создать карту с одним ключом access
и списком значений, вы можете использовать оператор многоточия ( ...
). Также ваш синтаксис неверен. Таким образом, в этом случае следует использовать следующее:
vlan_list = {
for i in range(1, 100):
"access" => {
vlan_pool = module.vlan_pools.vlan_pool["access"]
from = i
to = i
}...
}
Комментарии:
1. Мне очень жаль, что я только что вернулся к этому вопросу почти год спустя. Я перешел к другим проектам. Спасибо вам за мысли
Ответ №2:
Вот как я недавно выполнил то, о чем просил выше. На то, чтобы разобраться в этом, ушло около года, но именно так я смог этого добиться.
# Map of Object input Variables is as shown below
variable "vlan_pools" {
default = {
"default" = {
alias = ""
allocation_mode = "dynamic"
description = ""
encap_blocks = {
"default" = {
allocation_mode = "inherit"
description = ""
role = "external"
vlan_range = "**REQUIRED**"
}
}
}
}
description = <<-EOT
key - name of the VLAN Pool
* alias: A changeable name for a given object. While the name of an object, once created, cannot be changed, the alias is a field that can be changed.
* allocation_mode: The allocation mode. The values can be:
- dynamic (default): Managed internally by the APIC to allocate VLANs for endpoint groups (EPGs). A vCenter Domain can associate only to a dynamic pool.
- static: One or more EPGs are associated with a domain, and that domain is associated with a static range of VLANs. You must configure statically deployed EPGs within that range of VLANs.
When you create VLAN ranges, you can also assign the allocation mode to be inherited from the parent.
* description: Description to add to the Object. The description can be up to 128 alphanumeric characters.
* encap_blocks:
- allocation_mode: The allocation mode. The values can be:
* dynamic: Managed internally by the APIC to allocate VLANs for endpoint groups (EPGs). A vCenter Domain can associate only to a dynamic pool.
* inherit (default): The inherited mode from the parent device.
* static: One or more EPGs are associated with a domain, and that domain is associated with a static range of VLANs. You must configure statically deployed EPGs within that range of VLANs.
- description: Description to add to the Object. The description can be up to 128 alphanumeric characters.
- role: Role of the VLAN range. The options are:
* external (Default): Used for allocating VLANs for each EPG assigned to the domain. The VLANs are used when packets are sent to or from leafs.
* Internal: Used for private VLAN allocations in the internal vSwitch by the Cisco ACI Virtual Edge (AVE). The VLANs are not seen outside the ESX host or on the wire.
- vlan_range: single vlan; i.e. 1. range of vlans; i.e. 1-5. Or List of Vlans; i.e. 1-5,10-15
EOT
type = map(object(
{
alias = optional(string)
allocation_mode = optional(string)
description = optional(string)
encap_blocks = map(object(
{
allocation_mode = optional(string)
description = optional(string)
role = optional(string)
vlan_range = string
}
))
}
))
}
# Which I then run some conditional modifications in locals to format the variables.
locals {
#__________________________________________________________
#
# VLAN Pools Variables
#__________________________________________________________
# This first loop is to handle optional attributes and return
# default values if the user doesn't enter a value.
vlan_pools = {
for k, v in var.vlan_pools : k => {
alias = v.alias != null ? v.alias : ""
allocation_mode = v.allocation_mode != null ? v.allocation_mode : "dynamic"
description = v.description != null ? v.description : ""
encap_blocks = v.encap_blocks != null ? v.encap_blocks : {}
}
}
# Loop 1 is to determine if the encap_blocks are:
# A Single number 1
# A Range of numbers 1-5
# A List of numbers 1-5,10-15
# And then to return these values as a list
vlan_ranges_loop_1 = flatten([
for key, value in local.vlan_pools : [
for k, v in value.encap_blocks : {
allocation_mode = v.allocation_mode != null ? v.allocation_mode : "inherit"
description = v.description != null ? v.description : ""
key1 = key
key2 = k
role = v.role != null ? v.role : "external"
vlan_split = length(regexall("-", v.vlan_range)) > 0 ? tolist(split(",", v.vlan_range)) : length(
regexall(",", v.vlan_range)) > 0 ? tolist(split(",", v.vlan_range)
) : [v.vlan_range]
vlan_range = v.vlan_range
}
]
])
# Loop 2 takes a list that contains a "-" or a "," and expands those values
# into a full list. So [1-5] becomes [1, 2, 3, 4, 5]
vlan_ranges_loop_2 = {
for k, v in local.vlan_ranges_loop_1 : "${v.key1}_${v.key2}" => {
allocation_mode = v.allocation_mode
description = v.description
key1 = v.key1
key2 = v.key2
role = v.role
vlan_list = length(regexall("(,|-)", jsonencode(v.vlan_range))) > 0 ? flatten([
for s in v.vlan_split : length(regexall("-", s)) > 0 ? [for v in range(tonumber(
element(split("-", s), 0)), (tonumber(element(split("-", s), 1)) 1)
) : tonumber(v)] : [s]
]) : v.vlan_split
}
}
# Loop 3 will take the vlan_list created in Loop 2 and expand this
# out to a map of objects per vlan.
vlan_ranges_loop_3 = flatten([
for k, v in local.vlan_ranges_loop_2 : [
for s in v.vlan_list : {
allocation_mode = v.allocation_mode
description = v.description
key1 = v.key1
role = v.role
vlan = s
}
]
])
# And lastly loop3's list is converted back to a map of objects
vlan_ranges = { for k, v in local.vlan_ranges_loop_3 : "${v.key1}_${v.vlan}" => v }
# End of Local Loops
}
# And lastly these values are consumed by the resources with for_each loops.
resource "aci_vlan_pool" "vlan_pools" {
for_each = local.vlan_pools
alloc_mode = each.value.allocation_mode
description = each.value.description
name = each.key
name_alias = each.value.alias
}
resource "aci_ranges" "vlans" {
depends_on = [
aci_vlan_pool.vlan_pools
]
for_each = local.vlan_ranges
description = each.value.description
alloc_mode = each.value.allocation_mode
from = "vlan-${each.value.vlan}"
to = "vlan-${each.value.vlan}"
role = each.value.role
vlan_pool_dn = aci_vlan_pool.vlan_pools[each.value.key1].id
}
Я уверен, что кто-то с большим опытом мог бы сделать это с меньшим количеством шагов в местных жителях, но это сработало, по крайней мере, для меня.
, 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}Кажется, я не могу найти ни одного примера того, как это сделать без Python.
Ответ №1:
Если вы хотите создать карту с одним ключом access
и списком значений, вы можете использовать оператор многоточия ( ...
). Также ваш синтаксис неверен. Таким образом, в этом случае следует использовать следующее:
Комментарии:
1. Мне очень жаль, что я только что вернулся к этому вопросу почти год спустя. Я перешел к другим проектам. Спасибо вам за мысли
Ответ №2:
Вот как я недавно выполнил то, о чем просил выше. На то, чтобы разобраться в этом, ушло около года, но именно так я смог этого добиться.
Я уверен, что кто-то с большим опытом мог бы сделать это с меньшим количеством шагов в местных жителях, но это сработало, по крайней мере, для меня.
, 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)
Кажется, я не могу найти ни одного примера того, как это сделать без Python.
Ответ №1:
Если вы хотите создать карту с одним ключом access
и списком значений, вы можете использовать оператор многоточия ( ...
). Также ваш синтаксис неверен. Таким образом, в этом случае следует использовать следующее:
Комментарии:
1. Мне очень жаль, что я только что вернулся к этому вопросу почти год спустя. Я перешел к другим проектам. Спасибо вам за мысли
Ответ №2:
Вот как я недавно выполнил то, о чем просил выше. На то, чтобы разобраться в этом, ушло около года, но именно так я смог этого добиться.
Я уверен, что кто-то с большим опытом мог бы сделать это с меньшим количеством шагов в местных жителях, но это сработало, по крайней мере, для меня.