Я работаю над сценариями для создания иерархии сайтов в Cisco DNA/Catalyst Center. Я использовал существующий репозиторий, который я изменил. У меня есть структура, которая выглядит так:
├── main.tf
├── variables.tf
├── modules
│ └── site_settings
│ └── site.tf
│ └── variables.tf
├── Site-1
│ └── site-1.tfvars
В ./main.tf у меня есть:
provider "dnacenter" {
username = var.dnac_username
password = var.dnac_password
base_url = var.dnac_url
debug = "true"
ssl_verify = "false"
}
module "site_settings" {
# Using m0_general_settings module to configure general settings
source = "../modules/site_settings"
global_name = var.global_name
region_name = var.region_name
country_name = var.country_name
city_name = var.city_name
site_name = var.site_name
buildings = var.buildings
building_name = var.building_name
}
В ./modules/site_settings/site.tf есть:
resource "dnacenter_area" "site" {
depends_on = [ dnacenter_area.city ]
provider = dnacenter
parameters {
site {
area {
name = var.site_name
parent_name = "${var.parent_name}/${var.global_name}/${var.country_name}/${var.city_name}"
}
}
type = "area"
}
}
resource "dnacenter_building" "building" {
depends_on = [ dnacenter_area.site ]
for_each = { for building in var.buildings : building.name => building }
provider = dnacenter
parameters {
site {
building {
name = "${each.value.name}"
parent_name = "${var.global_name}/${var.region_name}/${var.country_name}/${var.city_name}/${each.value.parent_name}"
latitude = "${each.value.latitude}"
longitude = "${each.value.longitude}"
}
}
type = "building"
}
}
resource "dnacenter_floor" "floor" {
depends_on = [ dnacenter_building.building ]
for_each = { for floor in var.floors : floor.name => floor }
provider = dnacenter
parameters {
site {
floor {
name = "${each.value.name}"
parent_name = "${var.global_name}/${var.region_name}/${var.country_name}/${var.city_name}/${each.value.parent_name}/${each.value.parent_building_name}"
}
}
type = "floor"
}
}
Это значения переменных в ./site-1.tfvars:
dnac_username = "Cisco"
dnac_password = "Cisco123"
dnac_url = "https://my-dna-lab.test.net"
site_name = "Site-1"
buildings = [
{
building_name = "B01"
parent_site_name = "Site-1"
latitude = "xx.xxxx"
longitude = "xx.xxxx"
},
{
building_name = "B02"
parent_site_name = "Site-1"
latitude = "xx.xxxx"
longitude = "xx.xxxx"
},
]
floors = [
{
name = "F02"
parent_name = "Site-1"
parent_building_name = "B01"
},
{
name = "F03"
parent_name = "Site-1"
parent_building_name = "B01"
},
{
name = "F04"
parent_name = "Site-1"
parent_building_name = "B01"
},
{
name = "F03"
parent_name = "Site-1"
parent_building_name = "B02"
},
]
Это переменные, определенные в ./variables.tf.
variable "dnac_username" {
sensitive = true
}
variable "dnac_password" {
sensitive = true
}
variable "dnac_url" {
type = string
}
variable "site_name" {
type = string
}
variable "global_name" {}
variable "buildings" {
description = "List of buildings"
type = list(object({
name = string
parent_name = string
latitude = number
longitude = number
}))
}
variable "floors" {
description = "List of Floors"
type = list(object({
name = string
parent_name = string
parent_building_name = string
}))
}
А вот переменные в ./modules/site_settings/variables.tf:
variable "region_name" {
type = string
}
variable "country_name" {
type = string
}
variable "city_name" {
type = string
}
variable "site_name" {
type = string
}
variable "global_name" {}
variable "ip_pools" {}
variable "floors" {}
variable "buildings" {}
Когда я пытаюсь запустить команду плана, я получаю сообщение об ошибке из-за повторяющихся значений, поскольку у меня одно и то же имя этажа, которое находится в двух разных зданиях.
Error: Duplicate object key
│
│ on modules/site_settings/site.tf line 90, in resource "dnacenter_floor" "floor":
│ 90: for_each = { for floor in var.floors : floor.name => floor }
│ ├────────────────
│ │ floor.name is "F03"
│
│ Two different items produced the key "F03" in this 'for' expression. If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key.
Как я могу заставить это работать и создать полы, как показано ниже? Могу ли я каким-то образом ссылаться на здание в этажах для цикла или ссылаться на этаж по идентификатору (который еще не известен)?
# module.site_settings.dnacenter_building.building["B01"] will be created
+ resource "dnacenter_building" "building" {
+ id = (known after apply)
+ item = (known after apply)
+ last_updated = (known after apply)
+ parameters {
+ type = "building"
+ site {
+ building {
+ address = (known after apply)
+ country = (known after apply)
+ latitude = xx.xxxx
+ longitude = xx.xxxx
+ name = "B01"
+ parent_name = "Global/EMEA/Spain/Madrid/Site-1"
}
}
}
}
# module.site_settings.dnacenter_building.building["B02"] will be created
+ resource "dnacenter_building" "building" {
+ id = (known after apply)
+ item = (known after apply)
+ last_updated = (known after apply)
+ parameters {
+ type = "building"
+ site {
+ building {
+ address = (known after apply)
+ country = (known after apply)
+ latitude = xx.xxxx
+ longitude = xx.xxxx
+ name = "B02"
+ parent_name = "Global/EMEA/Spain/Madrid/Site-1"
}
}
}
}
# module.site_settings.dnacenter_floor.floor["F02"] will be created
+ resource "dnacenter_floor" "floor" {
+ id = (known after apply)
+ item = (known after apply)
+ last_updated = (known after apply)
+ parameters {
+ type = "floor"
+ site {
+ floor {
+ floor_number = (known after apply)
+ height = (known after apply)
+ length = (known after apply)
+ name = "F02"
+ parent_name = "Global/EMEA/Spain/Madrid/Site-1/B01"
+ rf_model = (known after apply)
+ width = (known after apply)
}
}
}
}
# module.site_settings.dnacenter_floor.floor["F03"] will be created
+ resource "dnacenter_floor" "floor" {
+ id = (known after apply)
+ item = (known after apply)
+ last_updated = (known after apply)
+ parameters {
+ type = "floor"
+ site {
+ floor {
+ floor_number = (known after apply)
+ height = (known after apply)
+ length = (known after apply)
+ name = "F03"
+ parent_name = "Global/EMEA/Spain/Madrid/Site-1/B01"
+ rf_model = (known after apply)
+ width = (known after apply)
}
}
}
}
# module.site_settings.dnacenter_floor.floor["F03"] will be created
+ resource "dnacenter_floor" "floor" {
+ id = (known after apply)
+ item = (known after apply)
+ last_updated = (known after apply)
+ parameters {
+ type = "floor"
+ site {
+ floor {
+ floor_number = (known after apply)
+ height = (known after apply)
+ length = (known after apply)
** + name = "F03"
+ parent_name = "Global/EMEA/Spain/Madrid/Site-1/B02"**
+ rf_model = (known after apply)
+ width = (known after apply)
}
}
}
}
Вы имеете в виду значение ключа «имя»? Потому что у нас есть внешний инструмент для наших сайтов/офисов, и мы получаем оттуда данные о сайтах/зданиях/этажах и хотим, чтобы они оставались одинаковыми как в инструменте Office, так и в DNA Center. Это означает, что в каждом здании может быть этаж с названием F01, F02, F03 и т. д.
как сказал Марко, ключи на карте должны быть уникальными. Если вы думаете о том, как работает карта, то ее цель состоит в том, чтобы иметь возможность использовать ключ для поиска значения на карте. Если бы ключ существовал более одного раза, карта не знала бы, какое значение возвращать. По этой причине все имена ключей должны быть уникальными. Мы можем упростить вашу проблему, используя локальную переменную и вывод.
Учитывая, что вы не используете сам ключ в ресурсе, кроме как для формирования уникального имени ресурса, вы можете использовать комбинацию этажа и здания.
locals {
floors = [
{
name = "F02"
parent_name = "Site-1"
parent_building_name = "B01"
},
{
name = "F03"
parent_name = "Site-1"
parent_building_name = "B01"
},
{
name = "F04"
parent_name = "Site-1"
parent_building_name = "B01"
},
{
name = "F03"
parent_name = "Site-1"
parent_building_name = "B02"
},
]
floors_map = { for floor in local.floors : "${floor.name}-${floor.parent_building_name}" => floor }
}
output "floors" {
value = local.floors_map
}
ВЫХОД
Outputs:
floors = {
"F02-B01" = {
"name" = "F02"
"parent_building_name" = "B01"
"parent_name" = "Site-1"
}
"F03-B01" = {
"name" = "F03"
"parent_building_name" = "B01"
"parent_name" = "Site-1"
}
"F03-B02" = {
"name" = "F03"
"parent_building_name" = "B02"
"parent_name" = "Site-1"
}
"F04-B01" = {
"name" = "F04"
"parent_building_name" = "B01"
"parent_name" = "Site-1"
}
}
Большое спасибо, это сработает, но как мне совместить это с циклом в имеющемся у меня блоке ресурсов? Или как мне использовать переменные for_each внутри локальных переменных? Извините, но я совсем новичок в Терраформе....
Вы можете использовать его точно так же, как и вы, поскольку в вашем цикле вы фактически не ссылаетесь на ключи на карте, используя each.key
, вы всегда ссылаетесь на значения на карте только с помощью таких вещей, как each.value.name
и т. д., так что это должно просто работать
Это изменит имя ресурса terraofrm в файле состояния, если вы уже создали какие-либо ресурсы, поэтому всегда запускайте план для проверки изменений.
Ключи должны быть уникальными, поэтому должно работать что-то вроде
F03-building1
иF03-building2
.