Skip to content

Bulk API Terraform Limitations

Terraform Update-in-Place Dependency Behavior with “use_bulk_api” flag in Cisco Catalyst Center

Section titled “Terraform Update-in-Place Dependency Behavior with “use_bulk_api” flag in Cisco Catalyst Center”

Applies to: Catalyst Center Provider >= 0.5.2, NAC Module >= 0.4.0 with use_bulk_api = true

This document describes Terraform’s update-in-place behavior when managing hierarchical site structures in Cisco Catalyst Center using the bulk API.

This behavior is most commonly observed when a user attempts to partially remove hierarchical site entries managed via bulk resources in a single Terraform apply


When use_bulk_api = true, the Cisco Catalyst Center module manages sites using bulk resources:

  • catalystcenter_areas.bulk_areas
  • catalystcenter_buildings.bulk_buildings
  • catalystcenter_floors.bulk_floors

Each resource contains a map of all items at that hierarchy level. Removing an item from the configuration triggers an update-in-place operation on the parent resource, not an explicit destroy.


Terraform treats update-in-place operations with the same dependency ordering as CREATE, not DESTROY.

Operation TypeExecution Order
CreateAreas → Buildings → Floors
Update in placeAreas → Buildings → Floors
DestroyFloors → Buildings → Areas (reversed)

When removing site hierarchy elements, Terraform sees “update the Areas list” and processes it before Buildings and Floors, even though Catalyst Center requires children to be deleted first.


The module defines explicit depends_on relationships that enforce creation order:

# Areas have no site dependencies (created first)
resource "catalystcenter_areas" "bulk_areas" {
...
...
depends_on = [catalystcenter_discovery.discovery, ...]
}
# Buildings depend on Areas
resource "catalystcenter_buildings" "bulk_buildings" {
...
...
depends_on = [catalystcenter_areas.bulk_areas, ...] # <-- Buildings wait for Areas
}
# Floors depend on Buildings
resource "catalystcenter_floors" "bulk_floors" {
...
...
depends_on = [catalystcenter_building.building, catalystcenter_buildings.bulk_buildings, ...] # <-- Floors wait for Buildings
}

Key point: The depends_on relationships form a chain: Areas → Buildings → Floors. This ensures correct creation order, but during update-in-place operations, this same order is followed, which is against Catalyst Center’s deletion requirements.


sites.nac.yaml
catalyst_center:
sites:
areas:
- name: Global
- name: France
parent_name: Global
- name: Paris
parent_name: Global/France
- name: Poland
parent_name: Global
- name: Krakow
parent_name: Global/Poland
buildings:
- name: Paris_Bld_A
parent_name: Global/France/Paris
latitude: 48.8575
longitude: 2.3514
country: France
- name: Paris_Bld_B
parent_name: Global/France/Paris
latitude: 48.8575
longitude: 2.3514
country: France
- name: KRK_Bld_A
latitude: 50.0623225
longitude: 19.937975
country: Poland
parent_name: Global/Poland/Krakow
floors:
- name: Floor_1
floor_number: 1
parent_name: Global/France/Paris/Paris_Bld_A
- name: FLOOR_1
floor_number: 1
parent_name: Global/Poland/Krakow/KRK_Bld_A

This creates the following hierarchy in Catalyst Center:

Global
├── France (Area)
│ └── Paris (Area)
│ ├── Paris_Bld_A (Building)
│ │ └── Floor_1 (Floor)
│ └── Paris_Bld_B (Building)
└── Poland (Area)
└── Krakow (Area)
└── KRK_Bld_A (Building)
└── FLOOR_1 (Floor)

When removing France from the configuration while Poland/Krakow remains, Terraform sees:

  • The catalystcenter_areas.bulk_areas resource still exists (Poland areas remain in the map)
  • The catalystcenter_buildings.bulk_buildings resource still exists (KRK_Bld_A remains in the map)
  • The catalystcenter_floors.bulk_floors resource still exists (FLOOR_1 remains in the map)

Because items remain in each map, Terraform classifies this as update-in-place—not destroy. The bulk resources continue to exist; only their contents change (France entries removed, Poland entries unchanged).

If you were removing all sites (emptying the maps entirely), Terraform would destroy the bulk resources, which would trigger proper DESTROY ordering (Floors → Buildings → Areas). But partial removal from a map is always an update-in-place operation.


Goal: Remove the entire France site hierarchy in one operation.

Action: Remove all France-related entries from sites.nac.yaml and run terraform apply.

Terraform Plan Output:

# module.catalyst_center.catalystcenter_areas.bulk_areas[0] will be updated in-place
~ resource "catalystcenter_areas" "bulk_areas" {
~ areas = {
- "Global/France" = {
- id = "4d359396-59b8-4931-ac80-274cf6b3db65" -> null
- name = "France" -> null
- parent_name_hierarchy = "Global" -> null
}
- "Global/France/Paris" = {
- id = "c565b323-b3dc-4a67-ae95-fd34ce20f96d" -> null
- name = "Paris" -> null
- parent_name_hierarchy = "Global/France" -> null
}
}
}
# module.catalyst_center.catalystcenter_buildings.bulk_buildings[0] will be updated in-place
~ resource "catalystcenter_buildings" "bulk_buildings" {
~ buildings = {
- "Global/France/Paris/Paris_Bld_A" = {
- id = "53855e96-25aa-436a-95a2-56a7ab8c71ab" -> null
- name = "Paris_Bld_A" -> null
- parent_name_hierarchy = "Global/France/Paris" -> null
}
- "Global/France/Paris/Paris_Bld_B" = {
- id = "9b7550f4-f2ad-43bb-9834-3fad9e0e0b45" -> null
- name = "Paris_Bld_B" -> null
- parent_name_hierarchy = "Global/France/Paris" -> null
}
}
}
Plan: 0 to add, 4 to change, 0 to destroy.

Result: Terraform attempts to update Areas first (following CREATE order), but Catalyst Center rejects the request:

Error: Client Error
with module.catalyst_center.catalystcenter_areas.bulk_areas[0],
on .terraform/modules/catalyst_center/cc_sites.tf line 12, in resource "catalystcenter_areas" "bulk_areas":
12: resource "catalystcenter_areas" "bulk_areas" {
Failed to delete object (DELETE), got error: task failed:
"NCGR10012: Group cannot be deleted as there are child groups. Please delete them first."

Why it fails: Terraform processed the Areas update before Buildings and Floors because update-in-place follows CREATE ordering (Areas → Buildings → Floors), not DESTROY ordering (Floors → Buildings → Areas).


To align Terraform’s execution with Catalyst Center’s hierarchical constraints, deletion must be performed in multiple applies.

Edit sites.nac.yaml to remove only the France floor entries (Poland floors remain):

catalyst_center:
sites:
areas:
- name: Global
- name: France
parent_name: Global
- name: Paris
parent_name: Global/France
- name: Poland
parent_name: Global
- name: Krakow
parent_name: Global/Poland
buildings:
- name: Paris_Bld_A
parent_name: Global/France/Paris
latitude: 48.8575
longitude: 2.3514
country: France
- name: Paris_Bld_B
parent_name: Global/France/Paris
latitude: 48.8575
longitude: 2.3514
country: France
- name: KRK_Bld_A
latitude: 50.0623225
longitude: 19.937975
country: Poland
parent_name: Global/Poland/Krakow
floors:
# France Floor_1 removed
- name: FLOOR_1
floor_number: 1
parent_name: Global/Poland/Krakow/KRK_Bld_A

Run terraform apply. Only the Floors resource is updated (France floor removed), Areas and Buildings remain unchanged.

Edit sites.nac.yaml to remove France building entries (Poland buildings remain):

catalyst_center:
sites:
areas:
- name: Global
- name: France
parent_name: Global
- name: Paris
parent_name: Global/France
- name: Poland
parent_name: Global
- name: Krakow
parent_name: Global/Poland
buildings:
# France buildings removed
- name: KRK_Bld_A
latitude: 50.0623225
longitude: 19.937975
country: Poland
parent_name: Global/Poland/Krakow
floors:
- name: FLOOR_1
floor_number: 1
parent_name: Global/Poland/Krakow/KRK_Bld_A

Run terraform apply. France buildings are removed while Areas and Poland hierarchy remain.

Edit sites.nac.yaml to remove France area entries (Poland areas remain):

catalyst_center:
sites:
areas:
- name: Global
# France and Paris areas removed
- name: Poland
parent_name: Global
- name: Krakow
parent_name: Global/Poland
buildings:
- name: KRK_Bld_A
latitude: 50.0623225
longitude: 19.937975
country: Poland
parent_name: Global/Poland/Krakow
floors:
- name: FLOOR_1
floor_number: 1
parent_name: Global/Poland/Krakow/KRK_Bld_A

Run terraform apply. France areas are now safely removed. Poland hierarchy remains intact.


Terraform categorizes operations as:

  • Create: New resource
  • Update in place: Existing resource, modify attributes
  • Replace: Destroy + Create (ForceNew)
  • Destroy: Remove resource entirely

Removing items from a bulk resource’s map is an update-in-place, the resource continues to exist, just with fewer items. Terraform only reverses dependency order for explicit Destroy operations.

depends_on chain:
catalystcenter_areas.bulk_areas
└── catalystcenter_buildings.bulk_buildings
└── catalystcenter_floors.bulk_floors

For CREATE: Areas → Buildings → Floors (correct) For UPDATE: Areas → Buildings → Floors (problematic for deletions) For DESTROY: Floors → Buildings → Areas (would be correct, but not triggered)


  1. Update-in-place follows CREATE ordering, not DESTROY ordering
  2. Bulk resources (maps of items) treat partial item removal as an update-in-place
  3. Catalyst Center enforces hierarchy: children must be deleted before parents
  4. Multi-step deletion is required when partially removing entire site hierarchies
  5. This behavior applies to Provider >= 0.5.2, Module >= 0.4.0 with use_bulk_api = true

Update-in-place follows CREATE ordering. Only explicit DESTROY reverses dependencies. Delete children before parents using multiple applies.

This behavior may also occur for other hierarchical, bulk-managed resources when the bulk_site_provisioning flag is enabled,due to deletions being handled as update-in-place operations