Skip to content

Upgrade Procedures

Those guides describes the changes required to upgrade your Catalyst Center Terraform module version. Each upgrade procedure covers the changes necessary to move between two consecutive releases (subsequent versions).

After completing all the changes below, your data model will be compatible with Catalyst Center Terraform module version 0.5.0. This upgrade involves:

  1. Minimum Version Requirements (Required for all users):

    • Terraform >= 1.15.0
    • Provider CiscoDevNet/catalystcenter ~> 0.6.1
    • netascode/utils >= 2.0.0
  2. Wireless Controller type Requirement (Only if managing wireless controllers):

    • Add type: WirelessController to every non-embedded wireless controller
  3. RMA Device Replacement Workflow Rework (Only if using RMA / state: MARK_FOR_REPLACEMENT):

    • Migrate to the new inventory.devices[].rma block driven 3-step workflow
  4. Review New Features:

    • Write-only secrets, CLI template variable binding, per-site discovery, anycast additional IP pools, and Guest Anchor managed AP locations
Your SetupSections to Follow
All users (baseline)1, 4
Manages wireless controllers (standalone, guest anchor, or fabric WLC)+ 2
Uses RMA device replacement (state: MARK_FOR_REPLACEMENT)+ 3

Before starting the migration:

  1. Backup all state files
Terminal window
cp terraform.tfstate terraform.tfstate.backup.pre-migration
  1. Update configuration - Edit main.tf:
terraform {
required_version = ">= 1.15.0"
required_providers {
catalystcenter = {
source = "CiscoDevNet/catalystcenter"
version = "~> 0.6.1"
}
utils = {
source = "netascode/utils"
version = ">= 2.0.0"
}
}
}
module "catalyst_center" {
source = "netascode/nac-catalystcenter/catalystcenter"
version = "0.5.0"
# ... rest of configuration
}
  1. Initialize
Terminal window
terraform init -upgrade

1. Minimum Version Requirements (Breaking Change)

Section titled “1. Minimum Version Requirements (Breaking Change)”

Module 0.5.0 raises the minimum tool and provider requirements. These are enforced at terraform init / terraform plan time:

ComponentMinimum0.4.6Reason
Terraform>= 1.15.0>= 1.9.0Write-only (ephemeral) secret support
CiscoDevNet/catalystcenter~> 0.6.1~> 0.5.25Write-only secret attributes and new resources
netascode/utils>= 2.0.0>= 1.0.0Major upgrade of the YAML/model helper provider

2. Wireless Controller type Requirement (Breaking Change)

Section titled “2. Wireless Controller type Requirement (Breaking Change)”

Every non-embedded wireless controller must now declare type: WirelessController. This applies to a standalone WLC, a Guest Anchor WLC, and a fabric device carrying the WIRELESS_CONTROLLER_NODE role. Controller provisioning is now keyed on this attribute instead of on the presence of managed AP locations.

A device that defines primary_managed_ap_locations, secondary_managed_ap_locations, anchor_managed_ap_locations, or carries the WIRELESS_CONTROLLER_NODE role but omits type is rejected at plan time.

A wireless controller that defines *_managed_ap_locations (or carries WIRELESS_CONTROLLER_NODE) but has no type fails at terraform plan:

❌ The following devices look like wireless controllers but are missing type: WirelessController:
• C9800-KRK-WLC1 (roles: WIRELESS_CONTROLLER_NODE)
catalyst_center:
inventory:
devices:
- name: C9800-KRK-WLC1
state: PROVISION
device_role: ACCESS
fabric_roles:
- WIRELESS_CONTROLLER_NODE
site: Global/Poland/Krakow/Bld A
fabric_site: Global/Poland/Krakow
primary_managed_ap_locations:
- Global/Poland/Krakow/Bld A
catalyst_center:
inventory:
devices:
- name: C9800-KRK-WLC1
state: PROVISION
device_role: ACCESS
type: WirelessController # <-- add this
fabric_roles:
- WIRELESS_CONTROLLER_NODE
site: Global/Poland/Krakow/Bld A
fabric_site: Global/Poland/Krakow
primary_managed_ap_locations:
- Global/Poland/Krakow/Bld A

3. RMA Device Replacement Workflow Rework (Breaking Change)

Section titled “3. RMA Device Replacement Workflow Rework (Breaking Change)”

The Return Material Authorization (RMA) device replacement workflow (introduced in 0.4.2) has been reworked into a 3-step process driven by a new inventory.devices[].rma block. The device state now stays PROVISION throughout a replacement, so the state: MARK_FOR_REPLACEMENT value has been removed.

Migrate any device using state: MARK_FOR_REPLACEMENT to state: PROVISION plus the corresponding rma block.

catalyst_center:
inventory:
devices:
- name: EDGE_1
serial_number: FDO12345678
state: MARK_FOR_REPLACEMENT

Step 1 - mark the faulty device for replacement (state remains PROVISION):

catalyst_center:
inventory:
devices:
- name: EDGE_1
serial_number: FDO12345678
state: PROVISION
rma:
action: MARK_FOR_REPLACEMENT

Step 2 - trigger the replacement with the new serial number:

catalyst_center:
inventory:
devices:
- name: EDGE_1
serial_number: FDO12345678
state: PROVISION
rma:
action: REPLACE
replacement_serial_number: FDO87654321

Step 3 - once the replacement completes, update serial_number to the replacement device’s serial number and remove the rma block. After a successful replacement the old (faulty) serial no longer exists in Catalyst Center inventory, so leaving it stale would misidentify the device — and break serial-based resolution for access points and any future replacement:

catalyst_center:
inventory:
devices:
- name: EDGE_1
serial_number: FDO87654321 # was FDO12345678 (faulty); now the replacement serial
state: PROVISION

After completing all applicable sections:

Terminal window
terraform plan

Expected results:

  • A device that only added type: WirelessController (Section 2) shows no change for that controller.
  • Adding _version keys to secrets migrates them to write-only attributes; expect an in-place update on the affected credential/secret resources, not a destroy/create.

The Wireless Controller type and RMA requirements are enforced by plan-time validation (precondition checks), so a misconfiguration fails terraform plan with an error rather than producing a destroy/create:

  • Plan rejected for a wireless controller? → Add type: WirelessController (Section 2)
  • Invalid state: MARK_FOR_REPLACEMENT? → Use state: PROVISION with an rma block (Section 3)
SymptomCauseFix
init fails on provider/version constraintsMinimum requirements not metUpdate Terraform, provider and utils versions (Section 1)
Plan-time precondition failure for a WLCMissing type: WirelessControllerAdd type: WirelessController (Section 2)
Invalid state: MARK_FOR_REPLACEMENTRMA state removedUse state: PROVISION with an rma block (Section 3)

If anything goes wrong:

Terminal window
cp terraform.tfstate.backup.pre-migration terraform.tfstate

4. New Features in 0.5.0 (No Migration Required)

Section titled “4. New Features in 0.5.0 (No Migration Required)”

The following features are available in version 0.5.0. No migration is required for existing configurations, but you may want to leverage these new capabilities.

  • Write-only secrets: Declaring a <secret>_version key routes the secret through the provider’s write-only attribute pair, so the plaintext value is never persisted to Terraform state. A secret without a version keeps the existing behavior. Requires Terraform >= 1.15.0 and provider ~> 0.6.1.
catalyst_center:
network_settings:
device_credentials:
cli_credentials:
- name: CLI_CRED
username: admin
password: <secret>
password_version: 1 # bump to rotate; value not stored in state

*_version keys are available across device credentials, ISE/AAA servers, RADIUS key-wrap keys, SSID passphrases, AP profile passwords, and the ISIS domain password.

  • CLI template variable binding: Bind a template variable to a source via binding.
catalyst_center:
templates:
projects:
- name: Project_1
dayn_templates:
- name: Template_1
variables:
- name: interface
data_type: STRING
binding: "source.interface"
  • Per-site discovery: inventory.discovery[].create_per_site creates a discovery job defined in site data even in per-site mode (manage_global_settings = false with a non-empty managed_sites).
discovery:
- name: SITE_DISCOVERY
type: CDP
create_per_site: true
ip_address_list: "10.1.1.1"
global_credential_list:
- CLI_CRED
  • Guest Anchor managed AP locations: Assign anchor-managed AP locations to a Guest Anchor WLC via the wireless-controller provisioning path.
- name: ANCHOR_WLC
type: WirelessController
state: PROVISION
anchor_managed_ap_locations:
- Global/Site1/Building1
  • Anycast gateway additional IP pools: Attach up to 4 secondary IP pools (requires Catalyst Center 3.2.x).
anycast_gateways:
- ip_pool_name: PRIMARY_POOL
additional_ip_pools:
- SECONDARY_POOL_1
- SECONDARY_POOL_2

After completing all the changes below, your data model will be compatible with Catalyst Center Terraform module version 0.4.6. This range spans the 0.4.1 through 0.4.6 patch releases and involves:

  1. LAN Automation Data Model Restructure (Only if using lan_automation; introduced in 0.4.5):

    • The flat lan_automation list is split into lan_automation.devices[] and lan_automation.links[]
  2. IP Pool Reservation type Enum Values (Only if using management/service reservations; introduced in 0.4.4):

    • Capitalize management → Management and service → Service
  3. Data Model Changes (Review and update as needed):

    • Removed template attributes and tightened validation
  4. Review New Features:

    • RMA workflow, feature templates (CleanAir / RRM FRA), AP profiles, power profiles, anchor groups, pre-auth ACLs, wireless site/policy tags, VN anchoring, fabric-zone inheritance, inventory tags, stacked switches, planned access points, external authentication, and more
Your SetupSections to Follow
All users (baseline)3, 4
Uses lan_automation+ 1
Uses IP pool reservations of type management/service+ 2

Before starting the migration:

  1. Backup all state files
Terminal window
cp terraform.tfstate terraform.tfstate.backup.pre-migration
  1. Update configuration - Edit main.tf:
terraform {
required_version = ">= 1.9.0"
required_providers {
catalystcenter = {
source = "CiscoDevNet/catalystcenter"
version = "~> 0.5.25"
}
}
}
module "catalyst_center" {
source = "netascode/nac-catalystcenter/catalystcenter"
version = "0.4.6"
# ... rest of configuration
}
  1. Initialize
Terminal window
terraform init -upgrade

1. LAN Automation Data Model Restructure (Breaking Change - 0.4.5)

Section titled “1. LAN Automation Data Model Restructure (Breaking Change - 0.4.5)”

catalyst_center.lan_automation is no longer a flat list keyed by a type attribute. It is now an object with two keys:

  • lan_automation.devices[] - device discovery sessions (the former type: devices entries, with type removed)
  • lan_automation.links[] - DAY-N link operations, using action: ADD_LINK or action: DELETE_LINK (the former type: link entries, with type and status removed)
catalyst_center:
lan_automation:
- name: LAN_AUTO_1
type: devices
status: START
discovered_device_site_name_hierarchy: Global/Site1
primary_device_management_ip_address: 10.1.1.1
primary_device_interface_names:
- TenGigabitEthernet1/0/1
ip_pools:
- name: LAN_POOL
role: PRINCIPAL_IP_ADDRESS_POOL
discovery_level: 2
catalyst_center:
lan_automation:
devices:
- name: LAN_AUTO_1 # 'type: devices' removed
status: START
discovered_device_site_name_hierarchy: Global/Site1
primary_device_management_ip_address: 10.1.1.1
primary_device_interface_names:
- TenGigabitEthernet1/0/1
ip_pools:
- name: LAN_POOL
role: PRINCIPAL_IP_ADDRESS_POOL
discovery_level: 2
links:
- name: LAN_LINK_1 # 'type: link' / 'status' removed
action: ADD_LINK # or DELETE_LINK
primary_device_management_ip_address: 10.1.1.1
primary_device_interface_name: TenGigabitEthernet1/0/2
secondary_device_management_ip_address: 10.1.1.2
secondary_device_interface_name: TenGigabitEthernet1/0/2
ip_pool_name: LAN_POOL

2. IP Pool Reservation type Enum Values (Breaking Change - 0.4.4)

Section titled “2. IP Pool Reservation type Enum Values (Breaking Change - 0.4.4)”

The type enum values for IP pool reservations management and service have been capitalized to Management and Service.

catalyst_center:
network_settings:
ip_pools:
- name: POOL_1
ip_address_space: IPv4
ip_pools_reservations:
- name: RESERVATION_MGMT
type: management # lowercase
- name: RESERVATION_SVC
type: service # lowercase
catalyst_center:
network_settings:
ip_pools:
- name: POOL_1
ip_address_space: IPv4
ip_pools_reservations:
- name: RESERVATION_MGMT
type: Management # Capitalized
- name: RESERVATION_SVC
type: Service # Capitalized
0.4.00.4.6
managementManagement
serviceService

The following schema changes are non-blocking for most users, but review your data model if you use these attributes:

  • Template attributes removed: templates.projects[].*_templates[].version and management_device_ips are no longer part of the template schema. Remove them if present.
  • Fabric multicast: fabric.fabric_sites[].multicast.virtual_networks[].ipv6_ssm_ranges has been removed; only ipv4_ssm_ranges is retained.
  • Fabric border devices (now optional, 0.4.2): import_external_routes, default_exit, and local_autonomous_system_number are now optional, and border_priority maximum has been raised from 9 to 10. No change is required to existing configurations.

After completing all applicable sections:

Terminal window
terraform plan

Expected results:

  • LAN Automation and IP pool reservation edits (Sections 1-2) are data-model reshapes; expect in-place updates rather than destroy/create for the affected resources.

If you see unexpected destroy/create operations:

  • Validation error mentioning lan_automation? → Verify the devices[] / links[] restructure (Section 1)
  • Validation error on a reservation type? → Verify capitalization (Section 2)
SymptomCauseFix
Schema/validation error on lan_automationFlat list no longer supportedRestructure into devices[] / links[] (Section 1)
Invalid enum value for reservation typeLowercase management/serviceCapitalize to Management/Service (Section 2)

If anything goes wrong:

Terminal window
cp terraform.tfstate.backup.pre-migration terraform.tfstate

4. New Features in 0.4.x (No Migration Required)

Section titled “4. New Features in 0.4.x (No Migration Required)”

The following features were added across the 0.4.1-0.4.6 releases. No migration is required for existing configurations, but you may want to leverage these new capabilities.

  • RMA device replacement (0.4.2): Return Material Authorization workflow to replace a faulty provisioned device.
- name: EDGE_1
serial_number: FDO12345678
state: MARK_FOR_REPLACEMENT
  • Inventory tags (0.4.3): Define device tags decoupled from templates under inventory.tags.
catalyst_center:
inventory:
tags:
- name: DATACENTER
description: Data center switches
devices:
- name: EDGE_1
tags:
- DATACENTER
  • Stacked switch provisioning (0.4.3): Provision switch stacks via PnP.
- name: STACK_1
state: PNP
serial_number: FDO111
stack:
top_of_stack_serial_number: FDO111
cabling_scheme: "1A"
  • Port channels (0.4.3): Bundle physical interfaces on fabric edge nodes via inventory.devices[].port_channels.
  • SWIM image by name (0.4.3): Specify the PnP claim image by image_name (resolved to image_id).
- name: EDGE_1
state: PNP
image_name: cat9k_iosxe.17.12.03.SPA.bin
  • Update device management IP (0.4.2): The management IP is updated when device_ip differs from the current Catalyst Center value.
  • Config cleanup control (0.4.2): clean_up_config controls whether provisioned-device configuration is cleaned up on delete (settable per-device or via defaults).
  • Feature templates (CleanAir & RRM FRA) (0.4.4): Define under feature_templates.wireless and associate with wireless profiles via network_profiles.wireless[].feature_templates.
catalyst_center:
feature_templates:
wireless:
cleanair:
- name: CleanAir_5GHz
radio_band: 5GHz
enable: true
device_reporting: true
rrm_fra:
- name: FRA_24_5
radio_band: 2.4GHz_5GHz
fra_status: true
fra_sensitivity: MEDIUM
network_profiles:
wireless:
- name: WirelessProfile_1
feature_templates:
- CleanAir_5GHz
- FRA_24_5
  • AP profiles (0.4.2): Manage Access Point profiles (management access, aWIPS, rogue detection, mesh, power profiles, client limits) under wireless.ap_profiles.
catalyst_center:
wireless:
ap_profiles:
- name: CAMPUS_AP
ssh_enabled: true
awips_enabled: true
rogue_detection: true
power_profile: NIGHT_SAVER
  • Power profiles (0.4.2): Define AP power-saving profiles under wireless.power_profiles.
catalyst_center:
wireless:
power_profiles:
- name: NIGHT_SAVER
description: Reduced power overnight
rules:
- interface_type: RADIO
interface_id: 5GHZ
parameter_type: STATE
parameter_value: DISABLE
  • Anchor groups (0.4.2): Define wireless mobility anchor groups under wireless.anchor_groups, and reference them from SSIDs via anchor_group_name.
catalyst_center:
wireless:
anchor_groups:
- name: GUEST_ANCHORS
mobility_anchors:
- device_name: WLC_ANCHOR
ip_address: 10.1.1.9
anchor_priority: PRIMARY
managed_anchor_wlc: true
  • Pre-Auth ACLs (0.4.6): Control traffic allowed before full authentication under wireless.security_settings.pre_auth_acls, referenced from Guest (CWA/EWA) and Enterprise-Posturing SSIDs.
catalyst_center:
wireless:
security_settings:
pre_auth_acls:
- name: GUEST_PREAUTH
ipv6_enabled: false
rules:
- protocol: UDP
source_address: 0.0.0.0
destination_address: 0.0.0.0
destination_ports: "53"
  • Wireless profile site tags & policy tags (0.4.2 / 0.4.3): Attach AP profiles and control active AP zones per site.
catalyst_center:
network_profiles:
wireless:
- name: WirelessProfile_1
site_tags:
- name: ST_Building1
ap_profile_name: CAMPUS_AP
sites:
- Global/Site1/Building1
policy_tags:
- name: PT_Building1
ap_zones:
- Zone1
sites:
- Global/Site1/Building1
ssid_details:
- name: Guest_SSID
anchor_group_name: GUEST_ANCHORS # anchor group tunneling
- name: Corp_SSID
vlan_group_name: VLAN_GRP_1 # WLC VLAN group load-balancing
  • New SSID attributes (0.4.6): radius_profiling (enables RADIUS client profiling; requires an AAA/PSN server) and policy_profile_name (WLAN policy profile name). Both require Catalyst Center 3.1.3+.
  • VN anchoring (0.4.3 / 0.4.6): Anchor an L3 virtual network to a site via anchor_site; anchored anycast gateways are deployed on remote fabric sites (Multi-Site Remote Border).
catalyst_center:
fabric:
l3_virtual_networks:
- name: Campus
anchor_site: Global/Site1
  • Fabric zone inheritance (0.4.1 / 0.4.4): Fabric zones now accept anycast_gateways and l2_virtual_networks (by name), in addition to l3_virtual_networks.
catalyst_center:
fabric:
fabric_sites:
- name: Global/Site1
fabric_zones:
- name: Zone1
l3_virtual_networks:
- Campus
l2_virtual_networks:
- L2_VN_1
anycast_gateways:
- AG_POOL_1
  • Wireless multicast & replication mode (0.4.2 / 0.4.3): Set replication_mode and enable per-site wireless multicast.
multicast:
replication_mode: NATIVE_MULTICAST # or HEADEND_REPLICATION
wireless_multicast_enabled: true
virtual_networks:
- name: Campus
ip_pool_name: MCAST_POOL
  • Per-site transit creation (0.4.6): fabric.transits[].create_per_site creates an IP_BASED_TRANSIT defined in site data even in per-site mode.
catalyst_center:
fabric:
transits:
- name: IP_TRANSIT_1
type: IP_BASED_TRANSIT
create_per_site: true
  • Floor plan images & planned access points (0.4.3): Upload floor images (image_path) and place virtual AP markers for Day-0 RF planning.
catalyst_center:
sites:
floors:
- name: Floor1
parent_name: Global/Site1/Building1
image_path: ./floor_plans/floor1.png
planned_access_points:
- name: PLANNED_AP_1
ap_type: AP4800
position_x: 10.0
position_y: 20.0
radios:
- band: "5"
channel: 36
tx_power: 8
  • External authentication (0.4.4): Enable external user login and configure the AAA attribute used for role mapping.
catalyst_center:
system_settings:
external_authentication:
enabled: true
aaa_attribute: Cisco-AVPair

After completing all the changes below, your data model will be compatible with Catalyst Center Terraform module version 0.4.0. This upgrade involves:

  1. Terraform State Fixes (Required for all users with templates):

    • Fix params schema change in template deployments
    • Fix comments hash change in template versions
  2. Bulk API Migration (Only if use_bulk_api = true):

  3. Multi-State Considerations (Only if using multiple state files):

    • Follow specific migration order (GLOBAL first, then site states)
  4. Data Model Updates (Review and update as needed):

    • Update IP pool type enum values (capitalization change)
    • Rename associated_l3_virtual_network to associated_l3_virtual_network_name in L2 VNs
    • Rename dot11be_profile to dot11be_profile_name in wireless profiles
    • Remove deprecated discovery SNMP attributes (use device credentials instead)
    • Remove description from SNMPv2 credentials
  5. Review New Features:

    • Extended site hierarchy (up to 10 levels)
    • 802.11be (WiFi 7) profiles
    • Border device SDA transit attributes
    • LLDP discovery level
Your SetupSections to Follow
Single state, use_bulk_api = false1, 2, 5
Single state, use_bulk_api = true1, 2, 3, 5
Multi-state, use_bulk_api = false1, 2, 4, 5
Multi-state, use_bulk_api = true1, 2, 3, 4, 5

Before starting the migration:

  1. Backup all state files
Terminal window
cp terraform.tfstate terraform.tfstate.backup.pre-migration
  1. Update configuration - Edit main.tf:
terraform {
required_providers {
catalystcenter = {
source = "CiscoDevNet/catalystcenter"
version = "0.5.2"
}
}
}
module "catalyst_center" {
source = "netascode/nac-catalystcenter/catalystcenter"
version = "0.4.0"
# ... rest of configuration
}
  1. Initialize
Terminal window
terraform init -upgrade

1. Template Deployment params Schema Change (Breaking Change)

Section titled “1. Template Deployment params Schema Change (Breaking Change)”

The params attribute in catalystcenter_deploy_template changed from map(string) to map(list(string)). After terraform init -upgrade, you may see:

Error: Unable to Read Previously Saved State for UpgradeResourceState
with module.catalyst_center.catalystcenter_deploy_template.regular_template_deploy["..."],
AttributeName("target_info")...AttributeName("params").ElementKeyString("interface"):
invalid JSON, expected "[", got "GigabitEthernet1/0/3"
  1. Open terraform.tfstate
  2. Search for "type": "catalystcenter_deploy_template"
  3. Convert string values to arrays in the params object:

Before:

"params": {
"interface": "GigabitEthernet1/0/3",
"vlan_id": "100"
}

After:

"params": {
"interface": ["GigabitEthernet1/0/3"],
"vlan_id": ["100"]
}

Save as fix_params.py:

#!/usr/bin/env python3
"""Fix params schema: convert string values to arrays"""
import json, shutil
from datetime import datetime
STATE_FILE = "terraform.tfstate"
BACKUP_FILE = f"terraform.tfstate.backup.params.{datetime.now().strftime('%Y%m%d_%H%M%S')}"
def fix_state():
print(f"Creating backup: {BACKUP_FILE}")
shutil.copy(STATE_FILE, BACKUP_FILE)
with open(STATE_FILE, 'r') as f:
state = json.load(f)
fixed = 0
for resource in state.get('resources', []):
if resource.get('type') == 'catalystcenter_deploy_template':
for instance in resource.get('instances', []):
for target in instance.get('attributes', {}).get('target_info', []):
params = target.get('params')
if params:
for key, value in params.items():
if isinstance(value, str):
params[key] = [value]
print(f" Fixed: {key}: \"{value}\" -> [\"{value}\"]")
fixed += 1
with open(STATE_FILE, 'w') as f:
json.dump(state, f, indent=2)
print(f"\nFixed {fixed} params. Backup: {BACKUP_FILE}")
if __name__ == '__main__':
fix_state()

Run: python3 fix_params.py

2. Template Version comments Hash Change (Breaking Change)

Section titled “2. Template Version comments Hash Change (Breaking Change)”

After fixing params (or if no params issue), terraform plan may show template versions being replaced:

# module.catalyst_center.catalystcenter_template_version.regular_commit_version["ACL_Block"] must be replaced
-/+ resource "catalystcenter_template_version" "regular_commit_version" {
~ comments = "5438fad09e3629ac8a8526fe5f14ff42" -> "b70f511ffef5100fd8dbb8255b5a06ad" # forces replacement
}

The module changed how the comments MD5 hash is calculated. Since comments forces replacement, Terraform wants to destroy and recreate template versions.

  1. Run terraform plan and note the new hash values
  2. Open terraform.tfstate
  3. Search for "type": "catalystcenter_template_version"
  4. Update comments to match plan output:

Before:

"attributes": {
"comments": "5438fad09e3629ac8a8526fe5f14ff42",
...
}

After:

"attributes": {
"comments": "b70f511ffef5100fd8dbb8255b5a06ad",
...
}

Save as fix_comments.py:

#!/usr/bin/env python3
"""Fix template version comments hash"""
import json, shutil
from datetime import datetime
STATE_FILE = "terraform.tfstate"
BACKUP_FILE = f"terraform.tfstate.backup.comments.{datetime.now().strftime('%Y%m%d_%H%M%S')}"
# UPDATE THESE VALUES from your terraform plan output!
# Run: terraform plan | grep -B2 -A2 "comments"
NEW_COMMENTS = {
"ACL_Block": "b70f511ffef5100fd8dbb8255b5a06ad",
"PNP_Template": "499c50145f21844124f99481e741ac2c",
# Add your templates here...
}
def fix_comments():
print(f"Creating backup: {BACKUP_FILE}")
shutil.copy(STATE_FILE, BACKUP_FILE)
with open(STATE_FILE, 'r') as f:
state = json.load(f)
fixed = 0
for resource in state.get('resources', []):
if resource.get('type') == 'catalystcenter_template_version':
for instance in resource.get('instances', []):
key = instance.get('index_key')
if key in NEW_COMMENTS:
old = instance['attributes'].get('comments', '')
new = NEW_COMMENTS[key]
if old != new:
instance['attributes']['comments'] = new
print(f" [{key}]: {old} -> {new}")
fixed += 1
with open(STATE_FILE, 'w') as f:
json.dump(state, f, indent=2)
print(f"\nFixed {fixed} comments. Backup: {BACKUP_FILE}")
if __name__ == '__main__':
fix_comments()

Usage:

Terminal window
# 1. Get new hash values
terraform plan | grep -B2 -A2 "comments"
# 2. Update NEW_COMMENTS dict in script
# 3. Run
python3 fix_comments.py

3. Bulk API Site Migration (Only if use_bulk_api = true)

Section titled “3. Bulk API Site Migration (Only if use_bulk_api = true)”

When upgrading with use_bulk_api = true, Terraform switches from individual resources to bulk resources:

Individual (Destroyed)Bulk (Created)
catalystcenter_area.area_0["Global/Poland"]catalystcenter_areas.bulk_areas[0]
catalystcenter_building.building["..."]catalystcenter_buildings.bulk_buildings[0]
catalystcenter_floor.floor["..."]catalystcenter_floors.bulk_floors[0]

Problem: A direct apply would destroy and recreate sites, potentially failing if fabric/devices are provisioned.

Solution: Migrate state without destroying resources.

Terminal window
# List resources to migrate
terraform state list | grep -E "catalystcenter_area\.|catalystcenter_building\.|catalystcenter_floor\."
# Get details (record the id values)
terraform state show 'module.catalyst_center.catalystcenter_area.area_0["Global/Poland"]'
Step 3.2: Remove Individual Resources from State
Section titled “Step 3.2: Remove Individual Resources from State”
Terminal window
# Remove areas
terraform state rm 'module.catalyst_center.catalystcenter_area.area_0["Global/Poland"]'
terraform state rm 'module.catalyst_center.catalystcenter_area.area_1["Global/Poland/Krakow"]'
# ... repeat for all areas
# Remove buildings
terraform state rm 'module.catalyst_center.catalystcenter_building.building["Global/Poland/Krakow/Bld A"]'
# ... repeat for all buildings
# Remove floors
terraform state rm 'module.catalyst_center.catalystcenter_floor.floor["Global/Poland/Krakow/Bld A/FLOOR_1"]'
# ... repeat for all floors

Use targeted terraform apply to create the bulk resources in the Terraform state. This approach reads the existing site hierarchy directly from Catalyst Center and populates the state accordingly, avoiding import ID conflicts in multi-state environments:

Terminal window
terraform apply -target 'module.catalyst_center.catalystcenter_areas.bulk_areas[0]' -auto-approve
terraform apply -target 'module.catalyst_center.catalystcenter_buildings.bulk_buildings[0]' -auto-approve
terraform apply -target 'module.catalyst_center.catalystcenter_floors.bulk_floors[0]' -auto-approve
Terminal window
terraform plan

This script automates Step 3.2 (removing individual site resources from state) by generating and executing terraform state rm commands for all area, building, and floor resources. After running the script, proceed with the targeted apply commands from Step 3.3.

Save as migrate_to_bulk.py:

#!/usr/bin/env python3
"""Remove individual site resources from state for bulk migration"""
import subprocess, shutil, sys
from datetime import datetime
STATE_FILE = "terraform.tfstate"
BACKUP_FILE = f"terraform.tfstate.backup.bulk.{datetime.now().strftime('%Y%m%d_%H%M%S')}"
def get_resources_to_remove():
result = subprocess.run(
["terraform", "state", "list"],
capture_output=True, text=True, check=True
)
resources = []
for line in result.stdout.strip().split('\n'):
if any(rt in line for rt in [
'catalystcenter_area.area_',
'catalystcenter_building.building',
'catalystcenter_floor.floor'
]):
resources.append(line)
return resources
def migrate_state():
print(f"Creating backup: {BACKUP_FILE}")
shutil.copy(STATE_FILE, BACKUP_FILE)
resources = get_resources_to_remove()
if not resources:
print("No individual site resources found in state.")
sys.exit(0)
print(f"Found {len(resources)} individual site resource(s) to remove from state:\n")
for r in resources:
print(f" {r}")
print(f"\nRemoving resources from state...")
for r in resources:
result = subprocess.run(
["terraform", "state", "rm", r],
capture_output=True, text=True
)
if result.returncode == 0:
print(f" Removed: {r}")
else:
print(f" FAILED: {r} - {result.stderr.strip()}")
print(f"\nState removal complete. Backup: {BACKUP_FILE}")
print("\nNext steps - run the following commands to create bulk resources in state:")
print(" terraform apply -target 'module.catalyst_center.catalystcenter_areas.bulk_areas[0]' -auto-approve")
print(" terraform apply -target 'module.catalyst_center.catalystcenter_buildings.bulk_buildings[0]' -auto-approve")
print(" terraform apply -target 'module.catalyst_center.catalystcenter_floors.bulk_floors[0]' -auto-approve")
print(" terraform plan")
if __name__ == '__main__':
migrate_state()

Run:

Terminal window
python3 migrate_to_bulk.py
terraform apply -target 'module.catalyst_center.catalystcenter_areas.bulk_areas[0]' -auto-approve
terraform apply -target 'module.catalyst_center.catalystcenter_buildings.bulk_buildings[0]' -auto-approve
terraform apply -target 'module.catalyst_center.catalystcenter_floors.bulk_floors[0]' -auto-approve
terraform plan

4. Multi-State Migration Order (Only if using multiple state files)

Section titled “4. Multi-State Migration Order (Only if using multiple state files)”

Multi-state setups require specific migration order: GLOBAL state first, then site states.

  1. Templates are in GLOBAL; site states reference them via deploy_template
  2. Parent sites must exist before child sites
  3. L3 VNs are global; site states create l3_vn_to_fabric_site mappings
Terminal window
cd terraform_multistate_global/
# Backup
cp terraform.tfstate terraform.tfstate.backup
# Upgrade
terraform init -upgrade
terraform plan

GLOBAL typically needs:

  • comments fix (template versions)
  • Bulk area migration (if use_bulk_api = true)
Terminal window
# Apply fixes as needed (see Sections 1, 2, and 3)
python3 fix_comments.py
# For bulk API: migrate parent areas only
# ... (see Section 3)
# Verify and apply
terraform plan # Should show: 1 add, 0 destroy
terraform apply
Phase 2: Site States (Can be parallel after GLOBAL)
Section titled “Phase 2: Site States (Can be parallel after GLOBAL)”
Terminal window
cd terraform_multistate_site_a/
cp terraform.tfstate terraform.tfstate.backup
terraform init -upgrade
terraform plan
# Site states typically need:
# - params fix (deploy_template)
# - Bulk migration (if use_bulk_api = true)
python3 fix_params.py
python3 migrate_to_bulk.py # if bulk API
terraform plan # Should show: 1 add, 0 destroy
terraform apply

When using bulk API with multi-state, after terraform import, the bulk resource may contain ALL areas under Global, including areas from other states.

Solution: Filter the bulk resource to only include managed areas:

#!/usr/bin/env python3
"""Fix bulk_areas to only include sites managed by this state"""
import json, shutil
from datetime import datetime
STATE_FILE = "terraform.tfstate"
BACKUP_FILE = f"terraform.tfstate.backup.filter.{datetime.now().strftime('%Y%m%d_%H%M%S')}"
# UPDATE: Sites managed by THIS state only
MANAGED_AREAS = ["Global/Poland"] # For GLOBAL state
# MANAGED_AREAS = ["Global/Poland/Krakow"] # For SITE_A state
def fix_bulk():
shutil.copy(STATE_FILE, BACKUP_FILE)
with open(STATE_FILE, 'r') as f:
state = json.load(f)
for resource in state.get('resources', []):
if resource.get('type') == 'catalystcenter_areas':
for inst in resource.get('instances', []):
areas = inst.get('attributes', {}).get('areas', {})
filtered = {k: v for k, v in areas.items() if k in MANAGED_AREAS}
inst['attributes']['areas'] = filtered
print(f"Filtered: {list(areas.keys())} -> {list(filtered.keys())}")
state['serial'] += 1
with open(STATE_FILE, 'w') as f:
json.dump(state, f, indent=2)
if __name__ == '__main__':
fix_bulk()
5.1 IP Pool Type Enum Values (Capitalization Change)
Section titled “5.1 IP Pool Type Enum Values (Capitalization Change)”

The type enum values for IP pools and IP pool reservations have been updated to use capitalized values.

catalyst_center:
network_settings:
ip_pools:
- name: POOL_1
ip_address_space: IPv4
type: generic # lowercase
ip_pools_reservations:
- name: RESERVATION_1
type: generic # lowercase
catalyst_center:
network_settings:
ip_pools:
- name: POOL_1
ip_address_space: IPv4
type: Generic # Capitalized
ip_pools_reservations:
- name: RESERVATION_1
type: Generic # Capitalized
0.3.00.4.0
genericGeneric
tunnelTunnel

The associated_l3_virtual_network attribute has been renamed to associated_l3_virtual_network_name for clarity.

catalyst_center:
fabric:
fabric_sites:
- name: Global/Site1
l2_virtual_networks:
- name: L2_VN_1
vlan_name: VLAN_100
vlan_id: 100
associated_l3_virtual_network: Campus # Old attribute name
catalyst_center:
fabric:
fabric_sites:
- name: Global/Site1
l2_virtual_networks:
- name: L2_VN_1
vlan_name: VLAN_100
vlan_id: 100
associated_l3_virtual_network_name: Campus # New attribute name
5.3 Wireless Network Profile SSID Attribute Rename
Section titled “5.3 Wireless Network Profile SSID Attribute Rename”

The dot11be_profile attribute has been renamed to dot11be_profile_name for consistency.

catalyst_center:
network_profiles:
wireless:
- name: WirelessProfile_1
ssid_details:
- name: SSID_1
enable_fabric: true
dot11be_profile: "WiFi7_Profile" # Old attribute name
catalyst_center:
network_profiles:
wireless:
- name: WirelessProfile_1
ssid_details:
- name: SSID_1
enable_fabric: true
dot11be_profile_name: "WiFi7_Profile" # New attribute name

The following SNMP-related attributes have been removed from the discovery configuration. SNMP credentials should now be configured using the device credentials under network_settings.device_credentials.

Removed AttributeAlternative
snmp_versionUse snmpv2_read_credentials, snmpv2_write_credentials, or snmpv3_credentials
snmp_user_nameUse snmpv3_credentials.username
snmp_rw_community_descRemoved (not needed)
snmp_ro_community_descRemoved (not needed)
snmp_ro_communityUse snmpv2_read_credentials.read_community
snmp_rw_communityUse snmpv2_write_credentials.write_community
snmp_priv_protocolUse snmpv3_credentials.privacy_type
snmp_priv_passphraseUse snmpv3_credentials.privacy_password
snmp_modeUse snmpv3_credentials.snmp_mode
snmp_auth_protocolUse snmpv3_credentials.auth_type
snmp_auth_passphraseUse snmpv3_credentials.auth_password
https_read_credentialUse global_credential_list with credential name
http_write_credentialUse global_credential_list with credential name
catalyst_center:
inventory:
discovery:
- name: DISCOVERY_1
type: Single
ip_address_list: "10.1.1.1"
snmp_version: v3
snmp_user_name: snmp_user
snmp_mode: AuthPriv
snmp_auth_protocol: SHA
snmp_auth_passphrase: auth_pass
snmp_priv_protocol: AES128
snmp_priv_passphrase: priv_pass
catalyst_center:
network_settings:
device_credentials:
snmpv3_credentials:
- name: SNMPV3_CRED
username: snmp_user
snmp_mode: AUTHPRIV
auth_type: SHA
auth_password: auth_pass
privacy_type: AES128
privacy_password: priv_pass
inventory:
discovery:
- name: DISCOVERY_1
type: Single
ip_address_list: "10.1.1.1"
global_credential_list:
- SNMPV3_CRED
5.5 SNMPv2 Credential Description Attribute Removed
Section titled “5.5 SNMPv2 Credential Description Attribute Removed”

The description attribute has been removed from SNMPv2 read and write credentials.

catalyst_center:
network_settings:
device_credentials:
snmpv2_read_credentials:
- name: SNMPV2_READ
description: "Read-only community" # Removed in 0.4.0
read_community: public
snmpv2_write_credentials:
- name: SNMPV2_WRITE
description: "Read-write community" # Removed in 0.4.0
write_community: private
catalyst_center:
network_settings:
device_credentials:
snmpv2_read_credentials:
- name: SNMPV2_READ
read_community: public
snmpv2_write_credentials:
- name: SNMPV2_WRITE
write_community: private
5.6 Template Variable Value Type Enhancement
Section titled “5.6 Template Variable Value Type Enhancement”

Template variables now support both single string values and list values. This is a non-breaking change - existing single string values continue to work.

catalyst_center:
inventory:
devices:
- name: DEVICE_1
dayn_templates:
regular:
- name: TEMPLATE_1
variables:
- name: interface
value: "GigabitEthernet1/0/1"
catalyst_center:
inventory:
devices:
- name: DEVICE_1
dayn_templates:
regular:
- name: TEMPLATE_1
variables:
- name: interface
value: "GigabitEthernet1/0/1" # Single value still works
- name: vlans
value: # List values now supported
- "100"
- "200"
- "300"

After completing all applicable sections:

Terminal window
terraform plan

Expected results:

SetupExpected Plan
Non-bulk API1 to add, 0 to destroy (managed_sites_validation)
Bulk API1 to add, ~4 to change, 0 to destroy

If you still see destroy/create operations:

  • Template versions being replaced? → Verify comments fix (Section 2)
  • Areas/buildings/floors being replaced? → See bulk migration (Section 3)
  • State read errors? → Verify params fix (Section 1)
SymptomCauseFix
”Error decoding… missing expected [“params schema changeRun fix_params.py (Section 1)
template_version must be replacedcomments hash changeRun fix_comments.py (Section 2)
Large destroy/create count after params/comments fixBulk migration neededSee Section 3
Site state fails after GLOBAL migrationWrong orderApply GLOBAL first (Section 4)

If anything goes wrong:

Terminal window
cp terraform.tfstate.backup.pre-migration terraform.tfstate

6. New Features in 0.4.0 (No Migration Required)

Section titled “6. New Features in 0.4.0 (No Migration Required)”

The following new features are available in version 0.4.0. No migration is required for existing configurations, but you may want to leverage these new capabilities:

  • Extended Site Hierarchy: Support for up to 10 area levels
catalyst_center:
sites:
areas:
- name: Level1
parent_name: Global
- name: Level2
parent_name: Global/Level1
# ... up to Global/area/area/area/area/area/area/area/area/area/area
  • Floor Units of Measure: New units_of_measure attribute for floor dimensions
catalyst_center:
sites:
floors:
- name: Floor1
parent_name: Global/Area/Building
height: 3.0
length: 30.0
width: 20.0
units_of_measure: meters # or 'feet'
  • LLDP Discovery Level: New lldp_level attribute for LLDP-based network discovery
catalyst_center:
inventory:
discovery:
- name: LLDP_Discovery
type: LLDP
lldp_level: 3
ip_address_list: "10.10.30.1"
global_credential_list:
- CLI_CRED
- SNMPV3_CRED
  • 802.11be (WiFi 7) Profiles: New dot11be_profiles for WiFi 7 support with OFDMA and MU-MIMO settings
catalyst_center:
wireless:
dot11be_profiles:
- name: "WiFi7_HighPerf"
ofdma_down_link: true
ofdma_up_link: true
mu_mimo_down_link: true
mu_mimo_up_link: true
ofdma_multi_ru: true
  • Associate WiFi 7 Profiles with SSIDs: Use dot11be_profile_name in wireless network profiles
catalyst_center:
network_profiles:
wireless:
- name: WirelessProfile_1
ssid_details:
- name: SSID_1
enable_fabric: true
dot11be_profile_name: "WiFi7_HighPerf"
  • New SSID Attributes: Additional wireless SSID configuration options
catalyst_center:
wireless:
ssids:
- name: SSID_1
auth_type: WPA3_PERSONAL
wlan_type: Enterprise
web_passthrough: true # Allows guests to bypass certain login requirements (Guest SSID)
wlan_band_select: true # Allowed only when band options contain at least 2.4 GHz and 5 GHz
  • SDA Transit Affinity IDs: New attributes for SDA transit load balancing
catalyst_center:
fabric:
border_devices:
- name: BORDER_1
border_types:
- LAYER_3
sda_transit: SDA_Transit_1
affinity_id_prime: 1
affinity_id_decider: 100
connected_to_internet: true
multicast_over_transit: true
New AttributeTypeDescription
affinity_id_primeint (0-2147483647)Primary affinity ID for transit load balancing
affinity_id_deciderint (0-2147483647)Decider affinity ID for transit selection
multicast_over_transitboolEnable multicast over SDA transit
  • device_discovery_validation: Validates device presence in Catalyst Center inventory during plan phase, improving error handling for devices not found
  • managed_sites validation: Ensures all sites specified in managed_sites variable exist in YAML configuration with precondition check
  • bulk_site_provisioning validation: Verifies site hierarchy format and existence in YAML configuration
  • use_bulk_api: Enable bulk API operations for areas, buildings, and floors using new map-based provider resources for faster execution

After completing all the changes below, your data model will be compatible with Catalyst Center Terraform module version 0.3.0. Make sure to:

  1. Handle the Terraform state changes for Provision Device resources (resource renamed)
  2. Update RF Profile schema for radio type C (6GHz) properties
  3. Update Discovery snmp_mode enum values
  4. Review new optional features available in this version

1. Provision Device Resource Rename (Breaking Change)

Section titled “1. Provision Device Resource Rename (Breaking Change)”

The Terraform resource catalystcenter_fabric_provision_device has been renamed to catalystcenter_provision_device. This is a breaking change that requires manual Terraform state management. When upgrading, Terraform will show errors like:

Error: no schema available for module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["DEVICE_NAME"] while reading state

Execute the following command to find all provision device resources in your state:

Terminal window
terraform state list | grep catalystcenter_fabric_provision_device

Example output:

module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["BR10"]
module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["EDGE01"]
module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["FIAB"]
module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["Transit-CP-1"]
Step 2: Run Terraform Plan to Get Device and Site IDs
Section titled “Step 2: Run Terraform Plan to Get Device and Site IDs”

Run terraform plan to see the planned creation of new resources. Note the network_device_id and site_id values for each device:

Terminal window
terraform plan

Example output:

# module.catalyst_center.catalystcenter_provision_device.provision_device["BR10"] will be created
+ resource "catalystcenter_provision_device" "provision_device" {
+ id = (known after apply)
+ network_device_id = "e7869917-cf34-44ed-998a-e72ef9866eeb"
+ reprovision = false
+ site_id = "d3fa2852-cbca-4387-93c9-f1e47b6f7340"
}

Save the site_id and network_device_id values for each device for the import step.

Remove all identified resources from the Terraform state:

Terminal window
terraform state rm 'module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["BR10"]'
terraform state rm 'module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["EDGE01"]'
terraform state rm 'module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["FIAB"]'
terraform state rm 'module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["Transit-CP-1"]'

Import each device using the new resource name with the site_id and network_device_id values from Step 2:

Terminal window
terraform import 'module.catalyst_center.catalystcenter_provision_device.provision_device["BR10"]' "<site_id>,<network_device_id>"

Example:

Terminal window
terraform import 'module.catalyst_center.catalystcenter_provision_device.provision_device["BR10"]' "d3fa2852-cbca-4387-93c9-f1e47b6f7340,e7869917-cf34-44ed-998a-e72ef9866eeb"
terraform import 'module.catalyst_center.catalystcenter_provision_device.provision_device["EDGE01"]' "d3fa2852-cbca-4387-93c9-f1e47b6f7340,7ef492ca-b008-479a-9de4-7e40438c7d10"
terraform import 'module.catalyst_center.catalystcenter_provision_device.provision_device["FIAB"]' "944b4c7e-e9ed-4ec3-8d1f-e8d065a8c4b3,28a9f0f0-2834-4f12-8409-26d34a7f5bbb"
terraform import 'module.catalyst_center.catalystcenter_provision_device.provision_device["Transit-CP-1"]' "944b4c7e-e9ed-4ec3-8d1f-e8d065a8c4b3,e9272b6f-6ef0-487c-92dd-bce5c21747d7"

The import format is: "<site_id>,<network_device_id>"

Run terraform plan to verify the state is correct. You should see only in-place updates for other resources (like adding parent_id to areas/buildings/floors), not recreations of provision devices.

Terminal window
terraform plan
terraform apply

2. RF Profile Radio Type C (6GHz) Schema Changes

Section titled “2. RF Profile Radio Type C (6GHz) Schema Changes”

The RF Profile schema for radio type C (6GHz) has been significantly enhanced with new properties. The enable_radio_type_c attribute is now required (previously optional).

catalyst_center:
wireless:
rf_profiles:
- name: CUSTOM_RF_PROFILE
enable_radio_type_a: true
enable_radio_type_b: true
enable_radio_type_c: false # Was optional
enable_custom: true
catalyst_center:
wireless:
rf_profiles:
- name: CUSTOM_RF_PROFILE
enable_radio_type_a: true
enable_radio_type_b: true
enable_radio_type_c: true # Now required
# enable_custom removed in 0.3.0
radio_type_c_properties:
parent_profile: CUSTOM
enable_standard_power_service: true
psc_enforcing_enabled: true
discovery_frames_6ghz: Broadcast Probe Response
broadcast_probe_response_interval: 20
min_dbs_width: 20
max_dbs_width: 320
preamble_puncture: true
multi_bssid_properties:
dot11ax_parameters:
ofdma_down_link: true
ofdma_up_link: true
mu_mimo_up_link: true
mu_mimo_down_link: true
dot11be_parameters:
ofdma_down_link: true
ofdma_up_link: true
mu_mimo_up_link: true
mu_mimo_down_link: true
ofdma_multi_ru: true
target_wake_time: true
twt_broadcast_support: true
fra_properties_c:
client_reset_count: 5
client_utilization_threshold: 50
PropertyTypeDescription
enable_standard_power_serviceboolEnable standard power service
psc_enforcing_enabledboolEnable PSC enforcing
discovery_frames_6ghzenumNone, Broadcast Probe Response, FILS Discovery
broadcast_probe_response_intervalint (5-25)Broadcast probe response interval
min_dbs_widthenum20, 40, 80, 160, 320
max_dbs_widthenum20, 40, 80, 160, 320
preamble_punctureboolEnable preamble puncture
multi_bssid_propertiesobjectMulti-BSSID configuration
fra_properties_cobjectFRA properties for 6GHz

The snmp_mode enum values in discovery configurations have been updated to use different casing.

catalyst_center:
inventory:
discovery:
- name: Discovery_1
snmp_mode: AUTHPRIV
catalyst_center:
inventory:
discovery:
- name: Discovery_1
snmp_mode: AuthPriv
0.2.00.3.0
AUTHPRIVAuthPriv
AUTHNOPRIVAuthNoPriv
NOAUTHNOPRIVNoAuthNoPriv

4. New Features in 0.3.0 (No Migration Required)

Section titled “4. New Features in 0.3.0 (No Migration Required)”

The following new features are available in version 0.3.0. No migration is required for existing configurations, but you may want to leverage these new capabilities:

catalyst_center:
fabric:
fabric_sites:
- name: Global/Site1
multicast:
virtual_networks:
- name: Campus
ip_pool_name: CampusVN-IPPool
multicast_rps:
- name: RP1
rp_location: FABRIC
is_default_v4_rp: true
fabric_rps:
- Border-Device-1.example.com
- Border-Device-2.example.com
catalyst_center:
fabric:
extranet_policies:
- name: Shared_Services
provider_virtual_network: Shared
subscriber_virtual_networks:
- Campus
- Guest
fabric_sites:
- Global/Site1
  • Access Point Provisioning: Provision access points with RF profiles
catalyst_center:
inventory:
devices:
- name: AP_FLOOR1
type: AccessPoint
rf_profile: BASIC_PROFILE_1
state: PROVISION
site: Global/Site1/Building1/Floor1
  • Embedded Wireless Controller Node: New fabric role
catalyst_center:
inventory:
devices:
- name: SWITCH_EWLC
fabric_roles:
- EDGE_NODE
- EMBEDDED_WIRELESS_CONTROLLER_NODE
enable_wireless: true
enable_rolling_ap_upgrade: true
ap_reboot_percentage: 15
catalyst_center:
inventory:
devices:
- name: EDGE01
port_assignments:
- interfaces_range: GigabitEthernet1/0/1-1/0/10
interface_description: User Access Ports
connected_device_type: USER_DEVICE
data_vlan_name: Campus_Data
  • Group-Based Policy Enforcement: For EXTENDED_NODE pool types
catalyst_center:
fabric:
fabric_sites:
- name: Global/Site1
anycast_gateways:
- ip_pool_name: ExtendedNode-IPPool
pool_type: EXTENDED_NODE
group_based_policy_enforcement_enabled: true
  • TCP MSS Adjustment: Configure TCP MSS for anycast gateways
catalyst_center:
fabric:
fabric_sites:
- name: Global/Site1
anycast_gateways:
- ip_pool_name: Campus-IPPool
tcp_mss_adjustment: 1360
  • Reconfigure Flag: Apply pending fabric configuration events
catalyst_center:
fabric:
fabric_sites:
- name: Global/Site1
reconfigure: true
catalyst_center:
system_settings:
authentication_and_policy_servers:
ise:
ip_address: 10.1.1.100
shared_secret: SecretKey123
username: admin
password: AdminPass
fqdn: ise.example.com
retries: 3
timeout: 5
protocols:
radius:
authentication_port: 1812
accounting_port: 1813
  • use_bulk_api: Enable bulk API operations for faster execution
  • bulk_site_provisioning: Site path for bulk device provisioning. When set with use_bulk_api=true, provisions all devices from this site and all child sites in a single bulk operation. Example: ‘Global/Poland’ will provision all devices under Poland hierarchy.

After completing all the above changes, your data model will be compatible with Catalyst Center Terraform module version 0.2.0. Make sure to:

  1. Update all deploy_state references to redeploy_template with appropriate values
  2. Replace name with ip_pool_name in Anycast Gateway configurations
  3. Handle the Terraform state changes for network profile assignments
  4. Handle the Terraform state changes for Fabric L3 Handoff IP Transit resources
  5. Update LAN Automation attribute names and IP pool structure
  6. Change hostname to fqdn_name in device inventory
  7. Update discovery configuration attribute names

In version 0.1.1, template deployment was controlled by the deploy_state attribute with two options:

  • DEPLOY - never redeploy template
  • REDEPLOY - always redeploy template regardless of content changes

In version 0.2.0, this has been replaced with redeploy_template offering more granular control:

  • NEVER - never redeploy template
  • ALWAYS - always redeploy template regardless of content changes
  • ON_CHANGE - redeploy template only when there is a content template change
inventory:
devices:
- name: DEVICE_1
dayn_templates:
regular:
- name: TEMP1
deploy_state: DEPLOY
inventory:
devices:
- name: DEVICE_1
dayn_templates:
regular:
- name: TEMP1
redeploy_template: NEVER

The redeploy_template parameter can be configured at multiple levels with the following precedence (highest to lowest):

  1. Device-specific template level:
catalyst_center:
inventory:
devices:
- name: DEVICE_1
dayn_templates:
regular:
- name: TEMP1
redeploy_template: NEVER
  1. Device-wide template level:
catalyst_center:
inventory:
devices:
- name: DEVICE_1
dayn_templates:
redeploy_template: NEVER
regular:
- name: TEMP1
  1. Global template level:
catalyst_center:
templates:
projects:
- name: Project_DayN
description: Project_DayN
dayn_templates:
- name: TEMPLATE_1
redeploy_template: ALWAYS
  1. Default level:
defaults:
catalyst_center:
templates:
redeploy_template: NEVER
redeploy_templateTemplate Content ChangeTemplate Redeployed
ALWAYSYesYes
ALWAYSNoYes
NEVERYesNo
NEVERNoNo
ON_CHANGEYesYes
ON_CHANGENoNo

2. Anycast Gateway Attribute Name Replacement

Section titled “2. Anycast Gateway Attribute Name Replacement”

The name attribute in Anycast Gateway configuration has been replaced with ip_pool_name to better reflect its purpose as a reference to IP pool reservations.

catalyst_center:
fabric:
fabric_sites:
- name: Global/AREA
anycast_gateways:
- name: IPPool_1
catalyst_center:
fabric:
fabric_sites:
- name: Global/AREA
anycast_gateways:
- ip_pool_name: IPPool_1

3. Network Profile Assignment Resource Change

Section titled “3. Network Profile Assignment Resource Change”

The Terraform resource catalystcenter_associate_site_to_network_profile has been replaced with catalystcenter_network_profile_for_site_assignments. This requires manual Terraform state management.

Execute the following command to find all network profile association resources:

Terminal window
terraform state list | grep catalystcenter_associate_site_to_network_profile

Example output:

module.catalyst_center.catalystcenter_associate_site_to_network_profile.site_to_network_profile["Global/Poland/Krakow#_#Krk_switchingProfile"]
module.catalyst_center.catalystcenter_associate_site_to_network_profile.site_to_wireless_network_profile["Global/Poland/Krakow#_#C9800_KRK_Profile"]

Remove the identified resources from the Terraform state:

Terminal window
terraform state rm 'module.catalyst_center.catalystcenter_associate_site_to_network_profile.site_to_network_profile["Global/Poland/Krakow#_#Krk_switchingProfile"]'
terraform state rm 'module.catalyst_center.catalystcenter_associate_site_to_network_profile.site_to_wireless_network_profile["Global/Poland/Krakow#_#C9800_KRK_Profile"]'

Execute terraform apply to create the new network profile assignment resources:

Terminal window
terraform apply

Expected output:

# module.catalyst_center.catalystcenter_network_profile_for_sites_assignments.site_to_network_profile["Krk_switchingProfile"] will be created
+ resource "catalystcenter_network_profile_for_sites_assignments" "site_to_network_profile" {
+ id = (known after apply)
+ items = [
+ {
+ id = "a8fbb587-887c-42be-aaad-395abd685ebf"
},
]
+ network_profile_id = "076013fa-322f-48cb-b278-8bde227ebed7"
}
# module.catalyst_center.catalystcenter_network_profile_for_sites_assignments.site_to_wireless_network_profile["C9800_KRK_Profile"] will be created
+ resource "catalystcenter_network_profile_for_sites_assignments" "site_to_wireless_network_profile" {
+ id = (known after apply)
+ items = [
+ {
+ id = "a8fbb587-887c-42be-aaad-395abd685ebf"
},
]
+ network_profile_id = "5304325b-0aac-4be9-90ea-90c5654033f7"
}

4. Fabric L3 Handoff IP Transit Resource Change

Section titled “4. Fabric L3 Handoff IP Transit Resource Change”

The Terraform resource catalystcenter_fabric_l3_handoff_ip_transit has been replaced with catalystcenter_fabric_l3_handoff_ip_transits (note the plural form). This change consolidates multiple IP transit handoffs under a single resource per network device, requiring manual Terraform state management.

Execute the following command to find all L3 handoff IP transit resources:

Terminal window
terraform state list | grep catalystcenter_fabric_l3_handoff_ip_transit

Example output:

module.catalyst_center.catalystcenter_fabric_l3_handoff_ip_transit.l3_handoff_ip_transit["Campus/GigabitEthernet1/0/3/BGP65002/BR10.cisco.eu"]

Run command to get the network_device_id and fabric_id values needed for the import step:

Terminal window
terraform state show 'module.catalyst_center.catalystcenter_fabric_l3_handoff_ip_transit.l3_handoff_ip_transit["Campus/GigabitEthernet1/0/3/BGP65002/BR10.cisco.eu"]'

Example output:

# module.catalyst_center.catalystcenter_fabric_l3_handoff_ip_transit.l3_handoff_ip_transit["Campus/GigabitEthernet1/0/3/BGP65002/BR10.cisco.eu"]:
resource "catalystcenter_fabric_l3_handoff_ip_transit" "l3_handoff_ip_transit" {
fabric_id = "aca2f40c-40a2-4bc2-9690-f59d758fd600"
id = "fbe1ad74-7df9-46a2-8746-8875f9cbbed4"
interface_name = "GigabitEthernet1/0/3"
local_ip_address = "172.16.100.1/24"
network_device_id = "8fbd4920-25d2-4b73-be25-2421c61e9605"
remote_ip_address = "172.16.100.2/24"
transit_network_id = "fc09acc4-dd6d-48f0-a446-6afe7d0867f4"
virtual_network_name = "Campus"
vlan_id = 100
}

Save the network_device_id and fabric_id values for the import step:

  • network_device_id: 8fbd4920-25d2-4b73-be25-2421c61e9605
  • fabric_id: aca2f40c-40a2-4bc2-9690-f59d758fd600

Remove the identified resources from the Terraform state:

Terminal window
terraform state rm 'module.catalyst_center.catalystcenter_fabric_l3_handoff_ip_transit.l3_handoff_ip_transit["Campus/GigabitEthernet1/0/3/BGP65002/BR10.cisco.eu"]'

Import the new consolidated resource using the network device ID and fabric ID copied from Step 2:

Terminal window
terraform import 'module.catalyst_center.catalystcenter_fabric_l3_handoff_ip_transits.l3_handoff_ip_transits["BR10.cisco.eu"]' "8fbd4920-25d2-4b73-be25-2421c61e9605,aca2f40c-40a2-4bc2-9690-f59d758fd600"

The import format is: "<network_device_id>,<fabric_id>"

Several attributes in the LAN Automation data model have been updated for consistency and clarity.

0.1.10.2.0
peer_device_management_ip_addresssecondary_device_management_ip_address
redistribute_isis_to_bgpadvertise_lan_automation_routes_into_bgp

(0.2.0) Data Model:

catalyst_center:
lan_automation:
- name: Automate_Edge_Switches
secondary_device_management_ip_address: 198.18.130.11
advertise_lan_automation_routes_into_bgp: true

The ip_pools structure has been modified to use name and role instead of ip_pool_name and ip_pool_role.

catalyst_center:
lan_automation:
- name: Automate_Edge_Switches
ip_pools:
- ip_pool_name: MainPool
ip_pool_role: MAIN_POOL
catalyst_center:
lan_automation:
- name: Automate_Edge_Switches
ip_pools:
- name: MainPool
role: PRINCIPAL_IP_ADDRESS_POOL

Additionally the ip_pool_role values have been updated as follows:

0.1.10.2.0
MAIN_POOLPRINCIPAL_IP_ADDRESS_POOL
PHYSICAL_LINK_POOLLINK_OVERLAPPING_IP_POOL

The hostname attribute in device inventory has been replaced with fqdn_name to support fully qualified domain names.

catalyst_center:
inventory:
devices:
- name: DEVICE_1
hostname: DEVICE_1
catalyst_center:
inventory:
devices:
- name: DEVICE_1
fqdn_name: DEVICE_1.example.com

The attribute preferred_ip_method has been renamed to preferred_mgmt_ip_method in discovery configurations:

catalyst_center:
inventory:
discovery:
- name: Discovery_1
preferred_ip_method: UseLoopBack
catalyst_center:
inventory:
discovery:
- name: Discovery_1
preferred_mgmt_ip_method: UseLoopBack

After completing all the above changes, your data model will be compatible with Catalyst Center Terraform module version 0.1.1. Make sure to:

  1. Update authentication template number_of_hosts enum value from ‘Limited’ to ‘Single’
  2. Add L3 Virtual Networks structure at fabric level if using global L3 VNs
  3. Update device inventory managed AP locations structure
  4. Add new discovery configuration attributes if using advanced SNMP settings
  5. Remove deprecated RF profile attributes
  6. Update anycast gateway configurations with new optional attributes
  7. Remove deprecated border device attributes
  8. Handle the Terraform state changes for fabric provision device resource consolidation

1. Authentication Template Enum Value Update

Section titled “1. Authentication Template Enum Value Update”

The number_of_hosts attribute enum value has been updated for consistency.

catalyst_center:
authentication_templates:
- name: AUTH_TEMPLATE_1
number_of_hosts: Limited
catalyst_center:
authentication_templates:
- name: AUTH_TEMPLATE_1
number_of_hosts: Single

2. Fabric L3 Virtual Networks Structure Enhancement

Section titled “2. Fabric L3 Virtual Networks Structure Enhancement”

L3 Virtual Networks can now be defined at the global fabric level in addition to fabric site level, enabling better organization and reuse.

catalyst_center:
fabric:
l3_virtual_networks:
- name: GLOBAL_L3_VN_1
- name: GLOBAL_L3_VN_2
fabric_sites:
- name: Global/AREA
l3_virtual_networks:
- GLOBAL_L3_VN_1
- GLOBAL_L3_VN_2

3. Device Inventory Managed AP Locations Enhancement

Section titled “3. Device Inventory Managed AP Locations Enhancement”

The managed_ap_locations attribute has been split into primary_managed_ap_locations and secondary_managed_ap_locations for better AP management control.

catalyst_center:
inventory:
devices:
- name: WLC_DEVICE_1
managed_ap_locations:
- Global/Area1/Building1/Floor1
- Global/Area1/Building1/Floor2
catalyst_center:
inventory:
devices:
- name: WLC_DEVICE_1
primary_managed_ap_locations:
- Global/Area1/Building1/Floor1
secondary_managed_ap_locations:
- Global/Area1/Building1/Floor2

New SNMP-related attributes have been added to discovery configurations for enhanced device discovery capabilities.

catalyst_center:
inventory:
discovery:
- name: DISCOVERY_1
cdp_level: 16
enable_password_list:
- enable_password_1
ip_filter_list:
- 192.168.1.0/24
netconf_port: "830"
retry: 3
user_name_list:
- admin
snmp_version: v3
snmp_user_name: snmp_user
snmp_rw_community_desc: "RW Community"
snmp_ro_community_desc: "RO Community"
snmp_ro_community: public
snmp_rw_community: private
snmp_priv_protocol: AES128
snmp_priv_passphrase: priv_pass
snmp_mode: AUTHPRIV
snmp_auth_protocol: SHA
snmp_auth_passphrase: auth_pass

Deprecated RF profile attributes channel_width and enable_brown_field have been removed from the schema.

Remove these attributes from your RF profile configurations:

  • channel_width
  • enable_brown_field

New optional attributes have been added to anycast gateway configurations for enhanced functionality.

catalyst_center:
fabric:
fabric_sites:
- name: Global/AREA
anycast_gateways:
- name: ANYCAST_GW_1
intra_subnet_routing_enabled: true
multiple_ip_to_mac_addresses: false
supplicant_based_extended_node_onboarding: true

The deprecated external_domain_routing_protocol_name attribute has been removed from border device configurations.

Remove the external_domain_routing_protocol_name attribute from your border device configurations.

8. Fabric Provision Device Resource Consolidation

Section titled “8. Fabric Provision Device Resource Consolidation”

Multiple device-specific provision resources have been consolidated into a single catalystcenter_fabric_provision_device resource. The following resources are now unified:

  • catalystcenter_fabric_provision_device.border_device
  • catalystcenter_fabric_provision_device.edge_device
  • catalystcenter_fabric_provision_device.non_fabric_device

All devices now use the single catalystcenter_fabric_provision_device.provision_device resource.

Execute the following command to find all fabric provision device resources:

Terminal window
terraform state list | grep catalystcenter_fabric_provision_device

Example output:

module.catalyst_center.catalystcenter_fabric_provision_device.border_device["BR10.cisco.eu"]
module.catalyst_center.catalystcenter_fabric_provision_device.edge_device["EDGE01.cisco.eu"]
module.catalyst_center.catalystcenter_fabric_provision_device.non_fabric_device["PNP_DEVICE.cisco.eu"]

Remove the identified resources from the Terraform state:

Terminal window
terraform state rm 'module.catalyst_center.catalystcenter_fabric_provision_device.border_device["BR10.cisco.eu"]'
terraform state rm 'module.catalyst_center.catalystcenter_fabric_provision_device.edge_device["EDGE01.cisco.eu"]'
terraform state rm 'module.catalyst_center.catalystcenter_fabric_provision_device.non_fabric_device["PNP_DEVICE.cisco.eu"]'

Import the new consolidated resources using the site ID and network device ID:

Terminal window
terraform import 'module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["BR10.cisco.eu"]' "662ed0df-861f-4753-9008-df85fe9a584e,e7869917-cf34-44ed-998a-e72ef9866eeb"
terraform import 'module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["EDGE01.cisco.eu"]' "662ed0df-861f-4753-9008-df85fe9a584e,7ef492ca-b008-479a-9de4-7e40438c7d10"
terraform import 'module.catalyst_center.catalystcenter_fabric_provision_device.provision_device["PNP_DEVICE.cisco.eu"]' "c2c12299-f7cc-4058-9d99-ffe57de50062,ce8d33e4-6d7b-4f2a-8ed6-0d95603305be"

The import format is: "<site_id>,<network_device_id>"