I am working on a scripts for creating a site hierarchy in Cisco DNA/Catalyst Center. I used an existing repo, that I’ve modified. I have structure that looks like this:
├── main.tf
├── variables.tf
├── modules
│ └── site_settings
│ └── site.tf
│ └── variables.tf
├── Site-1
│ └── site-1.tfvars
In ./main.tf I have:
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
}
The ./modules/site_settings/site.tf has:
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"
}
}
These are the varialbe values in ./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"
},
]
These are the variables defined in ./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
}))
}
And here are the vars in ./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" {}
When I try to run the plan command, I get an error for duplicate values, since I have the same Floor name, which is in two different 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.
How can I make this work, and create the floors as below? Can I somehow reference also the building in the floors for loop, or refence floor by ID (which is still not known)?
# 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)
}
}
}
}