Skip to content

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

💙 Cisco ACI FC Domain Terraform Module

Manage a Cisco ACI FC domain — a fabric-scoped access-policy object (class fcDomP, DN uni/fc-{name}) that binds a VSAN pool to a name every Fibre Channel connectivity binding references — as a typed, secure-by-default building block targeting CiscoDevNet/aci ~> 2.20.

Terraform Provider Module Version Type Resources

🧩 Overview

This module manages a single ACI FC domain and its pool/attribute bindings as one coherent, secure-by-default unit:

  • ⚓ The FC domain (aci_fc_domain.this) — a fabric-scoped access-policy object in the ACI Management Information Tree (MIT), addressed by the Distinguished Name uni/fc-{name}.
  • 🏷️ The ACI metadata tail — annotation (preserved as orchestrator:terraform so Terraform-managed objects are identifiable in APIC) and name_alias. The live schema for this resource carries no description, owner_key/owner_tag, or annotations/tags list.
  • 🔗 Classic flat pool/attribute relations — the VSAN pool binding that supplies this domain's Fibre Channel namespace and its resolved/definitive counterpart, an optional VSAN attribute policy binding and its resolved/definitive counterpart, an FCoE VLAN pool binding for FCoE deployments and its resolved/definitive counterpart, and the (rarely used outside GOLF/multi-pod) VIP address pool and VXLAN instance pool associations.
  • 🔑 Scope, not credentials — the FC domain is a fabric-root object with no parent DN; authentication and the APIC URL are the caller's provider concern and are never module variables.

💡 Why it matters: the FC domain is the pivot between an access-policy VSAN pool and every downstream object that needs Fibre Channel connectivity — an Attachable Access Entity Profile's domain relation, or an application EPG's static/domain binding. A consistent, identifiable, correctly-bound FC domain keeps that storage-network plumbing auditable.

❤️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!

🗺️ Where this fits in the family

graph LR
  apic["Cisco APIC fabric (provider auth, out of band)"]:::ext
  vsp["terraform-aci-vsan-pool"]:::sib
  vp["terraform-aci-vlan-pool"]:::sib
  fcd["terraform-aci-fc-domain (this module)"]:::this
  fc["aci_fc_domain - class fcDomP - DN uni/fc-{name}"]:::keystone
  aaep["terraform-aci-attachable-access-entity-profile"]:::sib
  epg["terraform-aci-application-epg"]:::sib

  apic -->|"provider configured by caller"| fcd
  vsp -->|"vsan_pool_dn"| fcd
  vp -->|"vlan_pool_dn (FCoE)"| fcd
  fcd -->|"manages"| fc
  fcd -->|"fc_domain_dn"| aaep
  fcd -->|"fc_domain_dn (domain binding)"| epg

  classDef this fill:#00BCEB,color:#fff,stroke:#00BCEB;
  classDef keystone fill:#0D274D,color:#fff,stroke:#0D274D;
  classDef sib fill:#f5f5f5,color:#333,stroke:#cccccc;
  classDef ext fill:#eeeeff,color:#333,stroke:#9999ff;
Loading

The FC domain sits between an access-policy VSAN pool and every object that needs Fibre Channel connectivity. It takes no parent DN, consumes a VSAN pool's DN (and, for FCoE, a VLAN pool's DN) as optional relations, and emits an id (its DN, uni/fc-{name}) that Attachable Access Entity Profiles and application EPGs consume when binding Fibre Channel connectivity.

🧬 What this module builds

graph TD
  n["fc_domain.name (required, immutable)"]:::in
  meta["annotation / name_alias"]:::in
  vsp["vsan_pool_dn / vsan_pool_definitive_dn"]:::in
  vsa["vsan_attribute_dn / vsan_attribute_definitive_dn"]:::in
  vp["vlan_pool_dn / vlan_pool_definitive_dn (FCoE)"]:::in
  vip["vip_address_pool_dn / vxlan_pool_definitive_dn"]:::in
  this["aci_fc_domain.this (keystone, fcDomP)"]:::this
  oid["output: id (DN uni/fc-{name})"]:::out
  onm["output: name"]:::out
  orel["outputs: vsan_pool_dn / vsan_pool_definitive_dn / vsan_attribute_dn / vsan_attribute_definitive_dn / vlan_pool_dn / vlan_pool_definitive_dn / vip_address_pool_dn / vxlan_pool_definitive_dn"]:::out

  n --> this
  meta --> this
  vsp --> this
  vsa --> this
  vp --> this
  vip --> this
  this --> oid
  this --> onm
  this --> orel

  classDef this fill:#00BCEB,color:#fff,stroke:#00BCEB;
  classDef in fill:#f5f5f5,color:#333,stroke:#cccccc;
  classDef out fill:#eeeeff,color:#333,stroke:#9999ff;
Loading

Resource inventory

Resource Name Cardinality Role
aci_fc_domain this 1 (keystone) The FC domain / access-policy VSAN binding (fcDomP).

✅ Provider / Versions

Requirement Value
Terraform >= 1.3.0 (uses optional() object defaults)
Provider CiscoDevNet/aci ~> 2.20
Provider block None in this module — the caller configures and authenticates the provider (username/password, X.509 signature, or login domain) out of band.
Scope None — the FC domain is a fabric-root object (no parent DN).

Schema notes that bite (verified against the live provider schema):

  • 🔒 fc_domain.name is immutable. Changing it forces replacement — a brand-new FC domain DN, breaking every binding (AAEP, EPG) that referenced the old one until re-pointed.
  • ℹ️ aci_fc_domain is a classic (SDKv2) resource. It has not migrated to the plugin-framework typed relation_to_* shape — its pool/attribute bindings are flat string attributes (relation_fc_rs_vsan_ns, relation_fc_rs_vsan_ns_def, relation_fc_rs_vsan_attr, relation_fc_rs_vsan_attr_def, relation_infra_rs_vlan_ns, relation_infra_rs_vlan_ns_def, relation_infra_rs_vip_addr_ns, relation_infra_rs_dom_vxlan_ns_def), each holding a target DN directly.
  • ⚠️ The live schema has no description, owner_key/owner_tag, or annotations/tags list. Unlike migrated resources in this suite, the metadata tail here is limited to annotation and name_alias — nothing else is invented.
  • ℹ️ relation_fc_rs_vsan_ns_def, relation_fc_rs_vsan_attr_def, relation_infra_rs_vlan_ns_def, and relation_infra_rs_dom_vxlan_ns_def are optional, computed. The provider typically derives them once the corresponding primary relation is set; this module exposes them as inputs only for advanced migration/import scenarios — leave them null in the common case.
  • ℹ️ The FCoE VLAN pool relation (vlan_pool_dn) is only meaningful for FCoE deployments. A pure native Fibre Channel domain typically leaves it null; native FC uses the VSAN pool relation exclusively.
  • ℹ️ id is the DN (uni/fc-{name}), computed by APIC at create. It is the value downstream modules consume when binding Fibre Channel connectivity to this domain.
  • ⚠️ validate_relation_dn (provider default true) means a vsan_pool_dn (or any other relation DN) pointing at an object that does not yet exist will fail at apply — create the object first, or wire it by reference.

🔑 Required APIC Roles & Privileges

Scope the caller's APIC login to the least privilege this module needs:

  • Create / delete an FC domain: the admin role, or a custom role granted write privilege on fabric infrastructure/access-policy configuration (the APIC built-in access-admin role covers this), scoped to the all security domain — FC domains are fabric-wide objects, not tenant-scoped.
  • Referenced VSAN pool / VSAN attribute policy / VLAN pool / VIP address pool: read on any object targeted by the relation attributes.

The module never sees a credential — authentication is a provider/caller concern supplied out of band (e.g. ACI_USERNAME / ACI_PASSWORD, or ACI_PRIVATE_KEY / ACI_CERT_NAME for signature-based auth).

Cisco ACI Prerequisites

  • A reachable Cisco APIC (ACI_URL) whose version is compatible with the ~> 2.20 provider, with the provider configured and authenticated by the caller.
  • In production, the provider should be configured with insecure = false and proper CA trust — the provider's own default (insecure = true, skip TLS verification) is not a safe steady state.
  • If you set vsan_pool_dn, vsan_attribute_dn, vlan_pool_dn, or vip_address_pool_dn, the referenced object must exist (or be created in the same configuration) so the provider's DN validation passes.

📁 Module Structure

terraform-aci-fc-domain/
├── providers.tf     # terraform{} + required_providers (aci ~> 2.20); no provider block
├── variables.tf     # the fc_domain object — deeply typed, secure defaults, heredoc schema, validations
├── main.tf          # aci_fc_domain.this (keystone) + metadata tail + classic pool/attribute relations
├── outputs.tf       # id (the DN) first, then name and the resolved relations
├── README.md        # this document
├── SCOPE.md         # cross-module contract (scope, consumes/emits, roles, prerequisites)
├── LICENSE          # MIT
└── .gitignore       # canonical library ignore set

⚙️ Quick Start

# The caller configures the provider (authentication is out of band).
provider "aci" {
  # username / password, or private_key + cert_name for signature auth;
  # url = "https://apic.example.com"; set insecure = false in production.
}

module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name = "storage-fc"
  }
}

output "fc_domain_dn" {
  value = module.fc_domain.id # pass this to AAEP / application-EPG domain bindings
}

🔌 Cross-Module Contract

Consumes

Input Type Typical source
fc_domain object({...}) caller (name + metadata tail + optional pool/attribute relations)
fc_domain.vsan_pool_dn string (DN) terraform-aci-vsan-pool
fc_domain.vlan_pool_dn string (DN) terraform-aci-vlan-pool (FCoE only)

Emits

Output Description Consumed by
id FC domain DN (uni/fc-{name}) — primary reference attachable-access-entity-profile, application-epg — any module binding Fibre Channel connectivity
name FC domain name composition / audit
vsan_pool_dn DN of the bound VSAN pool, or null audits / downstream reference
vsan_pool_definitive_dn Resolved/definitive VSAN namespace association audits
vsan_attribute_dn DN of the bound VSAN attribute policy, or null audits / downstream reference
vsan_attribute_definitive_dn Resolved/definitive VSAN attribute policy association audits
vlan_pool_dn DN of the bound FCoE VLAN pool, or null audits / downstream reference
vlan_pool_definitive_dn Resolved/definitive VLAN namespace association audits
vip_address_pool_dn DN of the bound VIP address pool, or null audits / downstream reference
vxlan_pool_definitive_dn Resolved/definitive VXLAN instance pool association audits

📚 Example Library

1 · Minimal — an FC domain with secure defaults
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name = "storage-fc"
  }
}

💡 The minimal call creates only the domain. annotation is preserved as orchestrator:terraform, and no pool relation is forced — the domain is inert until deliberately bound.

2 · A GUI display alias
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name       = "storage-fc"
    name_alias = "Storage-Fabric-A"
  }
}

ℹ️ name_alias is a display alias shown in the APIC GUI; name remains the immutable identity encoded in the DN.

3 · A custom annotation marker
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name       = "storage-fc"
    annotation = "orchestrator:terraform:storage-team"
  }
}

🔒 Keep the orchestrator:terraform prefix so Terraform-managed objects stay identifiable in APIC. This suite defaults annotation to orchestrator:terraform; override it only to extend, not to erase, that marker.

4 · Binding a VSAN pool by DN literal
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name         = "storage-fc"
    vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static"
  }
}

⚠️ The referenced VSAN pool must exist. With the provider's validate_relation_dn default of true, a dangling relation fails at apply — fix the missing pool rather than disabling validation.

5 · Binding a VSAN pool via module reference
module "vsan_pool" {
  source    = "git::https://github.com/microsoftexpert/terraform-aci-vsan-pool.git?ref=v1.0.0"
  vsan_pool = { name = "storage-vsans", alloc_mode = "static" }
}

module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name         = "storage-fc"
    vsan_pool_dn = module.vsan_pool.id
  }
}

💡 Wiring the pool's id output avoids hand-typing the pool's DN and keeps the dependency explicit for Terraform's graph.

6 · A VSAN attribute policy binding
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name              = "storage-fc"
    vsan_pool_dn      = "uni/infra/vsanns-[storage-vsans]-static"
    vsan_attribute_dn = "uni/infra/vsanattrp-storage-loadbal"
  }
}

ℹ️ The VSAN attribute policy (fcVsanAttrP) sets per-VSAN load-balancing/rewrite behavior for the domain — leave it null to rely on switch defaults.

7 · An FCoE deployment — VSAN pool plus VLAN pool
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name         = "fcoe-storage"
    vsan_pool_dn = "uni/infra/vsanns-[fcoe-vsans]-static"
    vlan_pool_dn = "uni/infra/vlanns-[fcoe-vlans]-static"
  }
}

ℹ️ vlan_pool_dn is only relevant for FCoE — it supplies the Ethernet encapsulation namespace that carries FC traffic. A native (non-FCoE) FC domain leaves it null.

8 · A VIP address pool relation (GOLF / multi-pod)
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name                = "golf-fc"
    vsan_pool_dn        = "uni/infra/vsanns-[golf-vsans]-static"
    vip_address_pool_dn = "uni/infra/addrinst-[golf-vip-pool]"
  }
}

ℹ️ vip_address_pool_dn is rarely needed outside GOLF / multi-pod endpoint-tracking deployments — leave it null for a conventional FC domain.

9 · An explicit definitive VSAN namespace override (advanced)
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name                    = "migrated-fc"
    vsan_pool_dn            = "uni/infra/vsanns-[storage-vsans]-static"
    vsan_pool_definitive_dn = "uni/infra/vsanns-[storage-vsans]-static"
  }
}

⚠️ Leave vsan_pool_definitive_dn unset (null) in the common case — the provider derives it from vsan_pool_dn. Set it explicitly only when reconciling an imported or manually migrated domain.

10 · Full binding (all relations)
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name                         = "full-bound-fc"
    vsan_pool_dn                 = "uni/infra/vsanns-[storage-vsans]-static"
    vsan_pool_definitive_dn      = "uni/infra/vsanns-[storage-vsans]-static"
    vsan_attribute_dn            = "uni/infra/vsanattrp-storage-loadbal"
    vsan_attribute_definitive_dn = "uni/infra/vsanattrp-storage-loadbal"
    vlan_pool_dn                 = "uni/infra/vlanns-[fcoe-vlans]-static"
    vlan_pool_definitive_dn      = "uni/infra/vlanns-[fcoe-vlans]-static"
    vip_address_pool_dn          = "uni/infra/addrinst-[golf-vip-pool]"
    vxlan_pool_definitive_dn     = "uni/infra/vxlanns-default"
  }
}
11 · Least-privilege operating model (documentation variant)
# Configure the provider with a login scoped to access-policy management —
# not a full fabric admin — for day-2 changes to an existing domain.
provider "aci" {
  # username    = "svc-access-admin"    # an access-admin role, write-scoped
  #                                      # to fabric access-policy configuration
  # private_key = var.apic_private_key  # signature auth avoids login-rate limits
  # cert_name   = "terraform-cert"
  # url         = "https://apic.example.com"
  # insecure    = false
}

module "fc_domain" {
  source    = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
  fc_domain = { name = "storage-fc" }
}

🔒 Creating an FC domain is a fabric-scoped action; delegate ongoing management to an access-admin role. Prefer signature-based (X.509) auth for automation to avoid APIC login-rate thresholds.

12 · Many FC domains from one definition (caller-side for_each)
locals {
  fc_domains = {
    "storage-fc-a" = { name = "storage-fc-a", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans-a]-static" }
    "storage-fc-b" = { name = "storage-fc-b", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans-b]-static" }
    "backup-fc"    = { name = "backup-fc", vsan_pool_dn = "uni/infra/vsanns-[backup-vsans]-static" }
  }
}

module "fc_domains" {
  source   = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
  for_each = local.fc_domains

  fc_domain = each.value
}

output "fc_domain_dns" {
  value = { for k, m in module.fc_domains : k => m.id }
}

💡 Instantiate the module with for_each to manage a fleet of FC domains from a single, auditable map.

13 · Reading outputs for downstream wiring
module "fc_domain" {
  source    = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
  fc_domain = { name = "storage-fc", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static" }
}

output "fc_domain_dn"           { value = module.fc_domain.id }             # uni/fc-storage-fc
output "fc_domain_vsan_pool_dn" { value = module.fc_domain.vsan_pool_dn }
14 · Wiring the domain DN into an Attachable Access Entity Profile
module "fc_domain" {
  source    = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"
  fc_domain = { name = "storage-fc", vsan_pool_dn = "uni/infra/vsanns-[storage-vsans]-static" }
}

module "aaep" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-attachable-access-entity-profile.git?ref=v1.0.0"

  attachable_access_entity_profile = {
    name         = "storage-aaep"
    fc_domain_dn = module.fc_domain.id # <-- the domain's DN becomes the AAEP's relation
  }
}
15 · 🏗️ End-to-end composition — VSAN pool → FC domain → AAEP → tenant → EPG
provider "aci" {
  # configured + authenticated by the caller; insecure = false in production
}

# 1) A VSAN pool supplying the Fibre Channel namespace.
module "vsan_pool" {
  source    = "git::https://github.com/microsoftexpert/terraform-aci-vsan-pool.git?ref=v1.0.0"
  vsan_pool = { name = "storage-vsans", alloc_mode = "static" }
}

# 2) The keystone FC domain, bound to that pool.
module "fc_domain" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-fc-domain.git?ref=v1.0.0"

  fc_domain = {
    name         = "storage-fc"
    vsan_pool_dn = module.vsan_pool.id
  }
}

# 3) An Attachable Access Entity Profile binding the domain to interface policy.
module "aaep" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-attachable-access-entity-profile.git?ref=v1.0.0"

  attachable_access_entity_profile = {
    name         = "storage-aaep"
    fc_domain_dn = module.fc_domain.id
  }
}

# 4) A tenant + application EPG bound to the same FC domain.
module "tenant" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-tenant.git?ref=v1.0.0"
  tenant = { name = "core-prod" }
}

module "ap" {
  source              = "git::https://github.com/microsoftexpert/terraform-aci-application-profile.git?ref=v1.0.0"
  tenant_dn           = module.tenant.id
  application_profile = { name = "storage-apps" }
}

module "epg" {
  source = "git::https://github.com/microsoftexpert/terraform-aci-application-epg.git?ref=v1.0.0"

  application_profile_dn = module.ap.id
  application_epg        = { name = "storage-epg" }
  fc_domain_dn            = module.fc_domain.id
}

output "fc_domain_dn" { value = module.fc_domain.id }

🏗️ One VSAN pool in; a fully-bound Fibre Channel connectivity path out. The FC domain is the pivot every access-policy and tenant-side binding wires into through module.fc_domain.id.

📥 Inputs

Name Type Required Default Description
fc_domain object({...}) ✅ — The FC domain: name (required, immutable) plus the metadata tail and the classic pool/attribute-relation attributes.
Full input schema (from variables.tf)
variable "fc_domain" {
  type = object({
    name       = string                                     # REQUIRED, immutable (force-new), 1-64 chars
    annotation = optional(string, "orchestrator:terraform") # ACI annotation marker (kept identifiable)
    name_alias = optional(string, null)                     # GUI display alias

    vsan_pool_dn                 = optional(string, null) # VSAN pool binding (fcRsVsanNs)
    vsan_pool_definitive_dn      = optional(string, null) # resolved/definitive VSAN namespace (fcRsVsanNsDef); provider-computed in the common case
    vsan_attribute_dn            = optional(string, null) # VSAN attribute policy binding (fcRsVsanAttr)
    vsan_attribute_definitive_dn = optional(string, null) # resolved/definitive VSAN attribute policy (fcRsVsanAttrDef); provider-computed in the common case
    vlan_pool_dn                 = optional(string, null) # FCoE VLAN pool binding (infraRsVlanNs); FCoE only
    vlan_pool_definitive_dn      = optional(string, null) # resolved/definitive VLAN namespace (infraRsVlanNsDef); provider-computed in the common case
    vip_address_pool_dn          = optional(string, null) # VIP address pool binding (infraRsVipAddrNs); GOLF / multi-pod
    vxlan_pool_definitive_dn     = optional(string, null) # resolved/definitive VXLAN instance pool (infraRsDomVxlanNsDef); provider-computed in the common case
  })
  # validation: name is 1-64 chars and matches ^[a-zA-Z0-9_.:-]+$ (ACI naming rules);
  # each relation DN, if set, must begin with "uni/"
}

🧾 Outputs

Output Description Notes
id FC domain Distinguished Name (uni/fc-{name}) Primary cross-module reference.
name FC domain name For composition / audit.
vsan_pool_dn DN of the bound VSAN pool, or null Pass-through of the resolved relation.
vsan_pool_definitive_dn Resolved/definitive VSAN namespace association Provider-computed in the common case.
vsan_attribute_dn DN of the bound VSAN attribute policy, or null Pass-through of the resolved relation.
vsan_attribute_definitive_dn Resolved/definitive VSAN attribute policy association Provider-computed in the common case.
vlan_pool_dn DN of the bound FCoE VLAN pool, or null Pass-through of the resolved relation.
vlan_pool_definitive_dn Resolved/definitive VLAN namespace association Provider-computed in the common case.
vip_address_pool_dn DN of the bound VIP address pool, or null Pass-through of the resolved relation.
vxlan_pool_definitive_dn Resolved/definitive VXLAN instance pool association Provider-computed in the common case.

🧠 Architecture Notes

  • One keystone, no children. aci_fc_domain.this is the single resource. The domain is a fabric-scoped binding point; the objects that reference it (AAEPs, application EPGs) are owned by their own modules and consume this domain by DN — keeping this module small and composable.
  • Classic (SDKv2) shape. Unlike this suite's migrated modules, the pool/attribute relations here are flat string attributes, not typed relation_to_* nested objects. The module surfaces each as a plain optional(string, null) DN input and wires it directly to the matching provider attribute.
  • Minimal metadata tail. The live schema exposes only annotation and name_alias — no description, owner_key/owner_tag, or annotations/tags list exists on this resource, so none are modeled.
  • Computed relations left alone by default. vsan_pool_definitive_dn, vsan_attribute_definitive_dn, vlan_pool_definitive_dn, and vxlan_pool_definitive_dn are optional, computed in the schema; this module exposes them as inputs but defaults each to null so the provider resolves them from the primary relation rather than fighting computed state.
  • FCoE is opt-in. The FCoE VLAN pool relation (vlan_pool_dn) is only wired when set; a native Fibre Channel domain is fully described by the VSAN pool relation alone.
  • Immutable identity. fc_domain.name is force-new: a rename destroys and recreates the domain, breaking every DN-based binding that referenced it until re-pointed. The two validation blocks reject names that violate the ACI length/character rules at plan time.
  • Secure by omission. The minimal call preserves the orchestrator:terraform annotation and binds no pool — nothing is wired by default.

🧱 Design Principles

Concern Secure default How to opt out (deliberately)
fc_domain.annotation orchestrator:terraform — Terraform-managed objects stay identifiable in APIC Extend the marker (e.g. add a team suffix); do not blank it.
vsan_pool_dn null — no VSAN pool bound, domain is inert Set it to bind a VSAN pool by DN.
vsan_pool_definitive_dn / vsan_attribute_definitive_dn / vlan_pool_definitive_dn / vxlan_pool_definitive_dn null — left to the provider to compute Set explicitly only for advanced migration/import scenarios.
vlan_pool_dn null — no FCoE VLAN pool bound Set it only for an FCoE deployment.
vip_address_pool_dn null — no VIP address pool bound Set it for GOLF / multi-pod endpoint-tracking deployments.
Transport (provider) This suite instructs callers to set insecure = false with CA trust The provider default is insecure = true; do not keep it as a steady state.
Secrets None accepted or emitted n/a — the FC domain carries no secret material; credentials are provider config.

🚀 Runbook

# From the module directory (offline, no credentials, no backend):
terraform init -backend=false
terraform validate
terraform fmt -check
  • Pin the module by immutable tag: ?ref=v1.0.0 — never a branch.
  • This module is plan-only from the library's perspective. A human runs terraform plan / apply against a sub-production APIC from their own pipeline, with a login scoped to the permissions above. No cloud apply happens here.

🧪 Testing

The offline proof gate for this module:

  • ✅ terraform validate — parses the module, resolves the fc_domain object type, runs the name and relation-DN validations, and confirms every argument exists in the provider schema.
  • ✅ terraform fmt -check — canonical formatting.
  • ⛔ Not exercised offline (only a real plan / apply against an APIC covers these): DN validation of the pool/attribute relations (server-side validate_relation_dn), APIC-side name-collision checks, resolution of the _def computed relations, and the computed DN returned as id.

💬 Example Output

$ terraform output
id                            = "uni/fc-storage-fc"
name                          = "storage-fc"
vsan_pool_dn                  = "uni/infra/vsanns-[storage-vsans]-static"
vsan_pool_definitive_dn       = "uni/infra/vsanns-[storage-vsans]-static"
vsan_attribute_dn             = null
vsan_attribute_definitive_dn  = null
vlan_pool_dn                  = null
vlan_pool_definitive_dn       = null
vip_address_pool_dn           = null
vxlan_pool_definitive_dn      = null

🔍 Troubleshooting

Symptom Cause Fix
fc_domain.name must be 1-64 characters Name is empty or too long Use a 1-64 character name.
fc_domain.name may contain only letters, digits, and the characters _ . : - Name has spaces or unsupported characters Remove spaces/special characters (ACI naming rules).
fc_domain.vsan_pool_dn must be a Distinguished Name beginning with "uni/" A relation DN was set to a bare name instead of a full DN Pass the pool's id output (or its full uni/... DN), not just its name.
Changing name wants to destroy/recreate the domain fc_domain.name is immutable (force-new) Treat a rename as a migration; expect every binding referencing the old DN to need re-pointing.
Apply fails validating the VSAN pool relation vsan_pool_dn targets a pool that does not exist Create the VSAN pool first (or in the same apply); do not disable validate_relation_dn.
FCoE traffic not reaching leaf ports as expected vlan_pool_dn left null in an FCoE deployment Set vlan_pool_dn to the VLAN pool supplying the FCoE encapsulation namespace.
Post ... 401 / authentication error Provider not configured or wrong credentials Configure the aci provider with valid credentials and url; prefer signature auth for automation.
TLS verification error against the APIC insecure = false (correct) but no CA trust Install the APIC's CA chain in the caller's trust store rather than reverting to insecure = true.

🔗 Related Docs

  • Cisco ACI provider — aci_fc_domain
  • Cisco ACI provider — provider configuration & authentication
  • Cisco APIC object model — class fcDomP (the FC domain access-policy object).
  • Sibling modules: terraform-aci-vsan-pool, terraform-aci-vlan-pool, terraform-aci-attachable-access-entity-profile, terraform-aci-application-epg, terraform-aci-physical-domain, terraform-aci-l2-domain, terraform-aci-l3-domain.
  • This module's SCOPE.md — the cross-module contract.

💙 "Infrastructure as Code should be standardized, consistent, and secure."

About

Terraform module: terraform-aci-fc-domain

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages