From 875b351a473bc9c5508beb1ebda2a33bcba0f0d1 Mon Sep 17 00:00:00 2001 From: Zachery Lantz Date: Wed, 6 Aug 2025 13:28:07 -0400 Subject: [PATCH 1/5] added support for epg static aaeps --- aci_tenants.tf | 14 ++++++++++++++ modules/terraform-aci-endpoint-group/README.md | 1 + modules/terraform-aci-endpoint-group/main.tf | 14 +++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/aci_tenants.tf b/aci_tenants.tf index 05059404..530b5484 100644 --- a/aci_tenants.tf +++ b/aci_tenants.tf @@ -425,6 +425,13 @@ locals { vlan = try(se.vlan, null) additional_ips = try(se.additional_ips, []) }] + static_aaeps = [for sa in try(epg.static_aaeps, []) : { + aaep = try(sa.aaep, null) + encap = try(sa.encap, null) + primaryEncap = try(sa.primary_encap, null) + mode = try(sa.mode, local.defaults.apic.tenants.application_profiles.endpoint_groups.static_aaeps.mode) + deployment_immediacy = try(sa.deployment_immediacy, local.defaults.apic.tenants.application_profiles.endpoint_groups.static_aaeps.deployment_immediacy) + }] l4l7_virtual_ips = [for vip in try(epg.l4l7_virtual_ips, []) : { ip = vip.ip description = try(vip.description, "") @@ -510,6 +517,13 @@ module "aci_endpoint_group" { vlan = se.vlan additional_ips = se.additional_ips }] + static_aaeps = [for sa in try(each.value.static_aaeps, []) : { + aaep = sa.aaep + encap = sa.encap + primary_encap = sa.primary_encap + mode = sa.mode + deployment_immediacy = sa.deployment_immediacy + }] l4l7_virtual_ips = each.value.l4l7_virtual_ips l4l7_address_pools = each.value.l4l7_address_pools diff --git a/modules/terraform-aci-endpoint-group/README.md b/modules/terraform-aci-endpoint-group/README.md index 5bc86e92..5db617f0 100644 --- a/modules/terraform-aci-endpoint-group/README.md +++ b/modules/terraform-aci-endpoint-group/README.md @@ -170,6 +170,7 @@ module "aci_endpoint_group" { | [aci_rest_managed.fvEpAnycast](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvEpNlb](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvEpReachability](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | +| [aci_rest_managed.fvRsAepAtt](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsBd](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsCons](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsConsIf](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | diff --git a/modules/terraform-aci-endpoint-group/main.tf b/modules/terraform-aci-endpoint-group/main.tf index e377b792..80ba82a1 100644 --- a/modules/terraform-aci-endpoint-group/main.tf +++ b/modules/terraform-aci-endpoint-group/main.tf @@ -522,6 +522,19 @@ resource "aci_rest_managed" "fvRsDomAtt_vmm" { } } +resource "aci_rest_managed" "fvRsAepAtt" { + for_each = { for sa in var.static_aaeps : sa.aaep => sa } + dn = "${aci_rest_managed.fvAEPg.dn}/rsaepAtt-${each.value.aaep}" + class_name = "fvRsAepAtt" + content = { + tnInfraAttEntityPName = each.value.aaep + encap = "vlan-${each.value.encap}" + primaryEncap = each.value.primary_encap != null ? "vlan-${each.value.primary_encap}" : "unknown" + mode = each.value.mode + instrImedcy = each.value.deployment_immediacy + } +} + resource "aci_rest_managed" "fvUplinkOrderCont" { for_each = { for vmm_vwm in var.vmware_vmm_domains : vmm_vwm.name => vmm_vwm if vmm_vwm.active_uplinks_order != "" || vmm_vwm.standby_uplinks != "" } dn = "${aci_rest_managed.fvRsDomAtt_vmm[each.key].dn}/uplinkorder" @@ -588,4 +601,3 @@ resource "aci_rest_managed" "fvnsUcastAddrBlk" { to = each.value.to } } - From 407639c20877fa8537262fbb3184aa6aa2f6cde2 Mon Sep 17 00:00:00 2001 From: Zachery Lantz Date: Wed, 6 Aug 2025 13:54:27 -0400 Subject: [PATCH 2/5] added static_aaep variable --- modules/terraform-aci-endpoint-group/README.md | 1 + modules/terraform-aci-endpoint-group/variables.tf | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/modules/terraform-aci-endpoint-group/README.md b/modules/terraform-aci-endpoint-group/README.md index 5db617f0..91b9b593 100644 --- a/modules/terraform-aci-endpoint-group/README.md +++ b/modules/terraform-aci-endpoint-group/README.md @@ -149,6 +149,7 @@ module "aci_endpoint_group" { | [static\_leafs](#input\_static\_leafs) | List of static leaf switches. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `node_id`: `1` - `4000`. Allowed values `vlan`: `1` - `4096`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `immediate` |
list(object({
pod_id = optional(number, 1)
node_id = number
vlan = number
mode = optional(string, "regular")
deployment_immediacy = optional(string, "immediate")
}))
| `[]` | no | | [static\_ports](#input\_static\_ports) | List of static ports. Allowed values `node_id`, `node2_id`: `1` - `4000`. Allowed values `fex_id`, `fex2_id`: `101` - `199`. Allowed values `vlan`: `1` - `4096`. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `port`: `1` - `127`. Allowed values `sub_port`: `1` - `16`. Allowed values `module`: `1` - `9`. Default value `module`: `1`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. |
list(object({
description = optional(string, "")
node_id = number
node2_id = optional(number)
fex_id = optional(number)
fex2_id = optional(number)
vlan = number
primary_vlan = optional(number)
pod_id = optional(number, 1)
port = optional(number)
sub_port = optional(number)
module = optional(number, 1)
channel = optional(string)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
ptp_source_ip = optional(string, "0.0.0.0")
ptp_mode = optional(string, "multicast")
ptp_profile = optional(string)
}))
| `[]` | no | | [static\_endpoints](#input\_static\_endpoints) | List of static endpoints. Format `mac`: `12:34:56:78:9A:BC`. Choices `type`: `silent-host`, `tep`, `vep`. Allowed values `node_id`, `node2_id`: `1` - `4000`. Allowed values `vlan`: `1` - `4096`. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `port`: `1` - `127`. Allowed values `module`: `1` - `9`. Default value `module`: `1`. |
list(object({
name = optional(string, "")
alias = optional(string, "")
mac = string
ip = optional(string, "0.0.0.0")
type = string
node_id = optional(number)
node2_id = optional(number)
vlan = optional(number)
pod_id = optional(number, 1)
port = optional(number)
module = optional(number, 1)
channel = optional(string)
additional_ips = optional(list(string), [])
}))
| `[]` | no | +| [static\_aaeps](#input\_static\_aaeps) | List of static aaeps. Allowed values |
list(object({
aaep = string
encap = optional(number)
primary_encap = optional(number)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
}))
| n/a | yes | | [l4l7\_virtual\_ips](#input\_l4l7\_virtual\_ips) | List of EPG L4/L7 Virtual IPs. |
list(object({
ip = string
description = optional(string, "")
}))
| `[]` | no | | [l4l7\_address\_pools](#input\_l4l7\_address\_pools) | List of EPG L4/L7 Address Pools. |
list(object({
name = string
gateway_address = string
from = optional(string, "")
to = optional(string, "")
}))
| `[]` | no | | [bulk\_static\_ports](#input\_bulk\_static\_ports) | Use bulk resource to configure static ports. | `bool` | `false` | no | diff --git a/modules/terraform-aci-endpoint-group/variables.tf b/modules/terraform-aci-endpoint-group/variables.tf index d3a5861a..7f79513b 100644 --- a/modules/terraform-aci-endpoint-group/variables.tf +++ b/modules/terraform-aci-endpoint-group/variables.tf @@ -641,6 +641,17 @@ variable "static_endpoints" { } } +variable "static_aaeps" { + description = "List of static aaeps. Allowed values" + type = list(object({ + aaep = string + encap = optional(number) + primary_encap = optional(number) + deployment_immediacy = optional(string, "lazy") + mode = optional(string, "regular") + })) +} + variable "l4l7_virtual_ips" { description = "List of EPG L4/L7 Virtual IPs." type = list(object({ From 5cf817194e0398554351489c77f795392833592f Mon Sep 17 00:00:00 2001 From: Zachery Lantz Date: Wed, 6 Aug 2025 15:10:15 -0400 Subject: [PATCH 3/5] added defaults --- aci_tenants.tf | 2 +- defaults/defaults.yaml | 3 ++ .../terraform-aci-endpoint-group/README.md | 2 +- .../terraform-aci-endpoint-group/variables.tf | 38 ++++++++++++++++++- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/aci_tenants.tf b/aci_tenants.tf index 530b5484..ad2f31cf 100644 --- a/aci_tenants.tf +++ b/aci_tenants.tf @@ -428,7 +428,7 @@ locals { static_aaeps = [for sa in try(epg.static_aaeps, []) : { aaep = try(sa.aaep, null) encap = try(sa.encap, null) - primaryEncap = try(sa.primary_encap, null) + primary_encap = try(sa.primary_encap, null) mode = try(sa.mode, local.defaults.apic.tenants.application_profiles.endpoint_groups.static_aaeps.mode) deployment_immediacy = try(sa.deployment_immediacy, local.defaults.apic.tenants.application_profiles.endpoint_groups.static_aaeps.deployment_immediacy) }] diff --git a/defaults/defaults.yaml b/defaults/defaults.yaml index 5e478045..33e1a12f 100644 --- a/defaults/defaults.yaml +++ b/defaults/defaults.yaml @@ -1098,6 +1098,9 @@ defaults: name_suffix: "" ip: "0.0.0.0" module: 1 + static_aaeps: + deployment_immediacy: lazy + mode: regular subnets: primary_ip: false public: false diff --git a/modules/terraform-aci-endpoint-group/README.md b/modules/terraform-aci-endpoint-group/README.md index 91b9b593..fc8f3a9b 100644 --- a/modules/terraform-aci-endpoint-group/README.md +++ b/modules/terraform-aci-endpoint-group/README.md @@ -149,7 +149,7 @@ module "aci_endpoint_group" { | [static\_leafs](#input\_static\_leafs) | List of static leaf switches. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `node_id`: `1` - `4000`. Allowed values `vlan`: `1` - `4096`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `immediate` |
list(object({
pod_id = optional(number, 1)
node_id = number
vlan = number
mode = optional(string, "regular")
deployment_immediacy = optional(string, "immediate")
}))
| `[]` | no | | [static\_ports](#input\_static\_ports) | List of static ports. Allowed values `node_id`, `node2_id`: `1` - `4000`. Allowed values `fex_id`, `fex2_id`: `101` - `199`. Allowed values `vlan`: `1` - `4096`. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `port`: `1` - `127`. Allowed values `sub_port`: `1` - `16`. Allowed values `module`: `1` - `9`. Default value `module`: `1`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. |
list(object({
description = optional(string, "")
node_id = number
node2_id = optional(number)
fex_id = optional(number)
fex2_id = optional(number)
vlan = number
primary_vlan = optional(number)
pod_id = optional(number, 1)
port = optional(number)
sub_port = optional(number)
module = optional(number, 1)
channel = optional(string)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
ptp_source_ip = optional(string, "0.0.0.0")
ptp_mode = optional(string, "multicast")
ptp_profile = optional(string)
}))
| `[]` | no | | [static\_endpoints](#input\_static\_endpoints) | List of static endpoints. Format `mac`: `12:34:56:78:9A:BC`. Choices `type`: `silent-host`, `tep`, `vep`. Allowed values `node_id`, `node2_id`: `1` - `4000`. Allowed values `vlan`: `1` - `4096`. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `port`: `1` - `127`. Allowed values `module`: `1` - `9`. Default value `module`: `1`. |
list(object({
name = optional(string, "")
alias = optional(string, "")
mac = string
ip = optional(string, "0.0.0.0")
type = string
node_id = optional(number)
node2_id = optional(number)
vlan = optional(number)
pod_id = optional(number, 1)
port = optional(number)
module = optional(number, 1)
channel = optional(string)
additional_ips = optional(list(string), [])
}))
| `[]` | no | -| [static\_aaeps](#input\_static\_aaeps) | List of static aaeps. Allowed values |
list(object({
aaep = string
encap = optional(number)
primary_encap = optional(number)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
}))
| n/a | yes | +| [static\_aaeps](#input\_static\_aaeps) | List of static aaeps. Allowed values |
list(object({
aaep = string
encap = number
primary_encap = optional(number)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
}))
| `[]` | no | | [l4l7\_virtual\_ips](#input\_l4l7\_virtual\_ips) | List of EPG L4/L7 Virtual IPs. |
list(object({
ip = string
description = optional(string, "")
}))
| `[]` | no | | [l4l7\_address\_pools](#input\_l4l7\_address\_pools) | List of EPG L4/L7 Address Pools. |
list(object({
name = string
gateway_address = string
from = optional(string, "")
to = optional(string, "")
}))
| `[]` | no | | [bulk\_static\_ports](#input\_bulk\_static\_ports) | Use bulk resource to configure static ports. | `bool` | `false` | no | diff --git a/modules/terraform-aci-endpoint-group/variables.tf b/modules/terraform-aci-endpoint-group/variables.tf index 7f79513b..b80254b1 100644 --- a/modules/terraform-aci-endpoint-group/variables.tf +++ b/modules/terraform-aci-endpoint-group/variables.tf @@ -645,11 +645,47 @@ variable "static_aaeps" { description = "List of static aaeps. Allowed values" type = list(object({ aaep = string - encap = optional(number) + encap = number primary_encap = optional(number) deployment_immediacy = optional(string, "lazy") mode = optional(string, "regular") })) + default = [] + + validation { + condition = alltrue([ + for sa in var.static_aaeps : can(regex("^[a-zA-Z0-9_.:-]{0,64}$", sa.aaep)) + ]) + error_message = "Allowed characters: `a`-`z`, `A`-`Z`, `0`-`9`, `_`, `.`, `:`, `-`. Maximum characters: 64." + } + + validation { + condition = alltrue([ + for sa in var.static_aaeps : (sa.encap >= 1 && sa.encap <= 4096) + ]) + error_message = "`vlan`: Minimum value: `1`. Maximum value: `4096`." + } + + validation { + condition = alltrue([ + for sa in var.static_aaeps : sa.primary_encap == null || try(sa.primary_encap >= 1 && sa.primary_encap <= 4096, false) + ]) + error_message = "`primary_encap`: Minimum value: `1`. Maximum value: `4096`." + } + + validation { + condition = alltrue([ + for sa in var.static_aaeps : sa.deployment_immediacy == null || try(contains(["immediate", "lazy"], sa.deployment_immediacy), false) + ]) + error_message = "`deployment_immediacy`: Allowed values are `immediate` or `lazy`." + } + + validation { + condition = alltrue([ + for sa in var.static_aaeps : sa.mode == null || try(contains(["regular", "native", "untagged"], sa.mode), false) + ]) + error_message = "`mode`: Allowed values are `regular`, `native` or `untagged`." + } } variable "l4l7_virtual_ips" { From 7949710dff81f2b68c7f1a9aa7597bf2fc4b5b09 Mon Sep 17 00:00:00 2001 From: Zachery Lantz Date: Wed, 6 Aug 2025 15:24:57 -0400 Subject: [PATCH 4/5] updated variable description --- modules/terraform-aci-endpoint-group/README.md | 2 +- modules/terraform-aci-endpoint-group/variables.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/terraform-aci-endpoint-group/README.md b/modules/terraform-aci-endpoint-group/README.md index fc8f3a9b..c82c9be4 100644 --- a/modules/terraform-aci-endpoint-group/README.md +++ b/modules/terraform-aci-endpoint-group/README.md @@ -149,7 +149,7 @@ module "aci_endpoint_group" { | [static\_leafs](#input\_static\_leafs) | List of static leaf switches. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `node_id`: `1` - `4000`. Allowed values `vlan`: `1` - `4096`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `immediate` |
list(object({
pod_id = optional(number, 1)
node_id = number
vlan = number
mode = optional(string, "regular")
deployment_immediacy = optional(string, "immediate")
}))
| `[]` | no | | [static\_ports](#input\_static\_ports) | List of static ports. Allowed values `node_id`, `node2_id`: `1` - `4000`. Allowed values `fex_id`, `fex2_id`: `101` - `199`. Allowed values `vlan`: `1` - `4096`. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `port`: `1` - `127`. Allowed values `sub_port`: `1` - `16`. Allowed values `module`: `1` - `9`. Default value `module`: `1`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. |
list(object({
description = optional(string, "")
node_id = number
node2_id = optional(number)
fex_id = optional(number)
fex2_id = optional(number)
vlan = number
primary_vlan = optional(number)
pod_id = optional(number, 1)
port = optional(number)
sub_port = optional(number)
module = optional(number, 1)
channel = optional(string)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
ptp_source_ip = optional(string, "0.0.0.0")
ptp_mode = optional(string, "multicast")
ptp_profile = optional(string)
}))
| `[]` | no | | [static\_endpoints](#input\_static\_endpoints) | List of static endpoints. Format `mac`: `12:34:56:78:9A:BC`. Choices `type`: `silent-host`, `tep`, `vep`. Allowed values `node_id`, `node2_id`: `1` - `4000`. Allowed values `vlan`: `1` - `4096`. Allowed values `pod_id`: `1` - `255`. Default value `pod_id`: `1`. Allowed values `port`: `1` - `127`. Allowed values `module`: `1` - `9`. Default value `module`: `1`. |
list(object({
name = optional(string, "")
alias = optional(string, "")
mac = string
ip = optional(string, "0.0.0.0")
type = string
node_id = optional(number)
node2_id = optional(number)
vlan = optional(number)
pod_id = optional(number, 1)
port = optional(number)
module = optional(number, 1)
channel = optional(string)
additional_ips = optional(list(string), [])
}))
| `[]` | no | -| [static\_aaeps](#input\_static\_aaeps) | List of static aaeps. Allowed values |
list(object({
aaep = string
encap = number
primary_encap = optional(number)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
}))
| `[]` | no | +| [static\_aaeps](#input\_static\_aaeps) | List of static aaeps. Allowed values `encap`: `1` - `4096`. Allowed values `primary_encap`: `1` - `4096`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular` |
list(object({
aaep = string
encap = number
primary_encap = optional(number)
deployment_immediacy = optional(string, "lazy")
mode = optional(string, "regular")
}))
| `[]` | no | | [l4l7\_virtual\_ips](#input\_l4l7\_virtual\_ips) | List of EPG L4/L7 Virtual IPs. |
list(object({
ip = string
description = optional(string, "")
}))
| `[]` | no | | [l4l7\_address\_pools](#input\_l4l7\_address\_pools) | List of EPG L4/L7 Address Pools. |
list(object({
name = string
gateway_address = string
from = optional(string, "")
to = optional(string, "")
}))
| `[]` | no | | [bulk\_static\_ports](#input\_bulk\_static\_ports) | Use bulk resource to configure static ports. | `bool` | `false` | no | diff --git a/modules/terraform-aci-endpoint-group/variables.tf b/modules/terraform-aci-endpoint-group/variables.tf index b80254b1..f055e8d7 100644 --- a/modules/terraform-aci-endpoint-group/variables.tf +++ b/modules/terraform-aci-endpoint-group/variables.tf @@ -642,7 +642,7 @@ variable "static_endpoints" { } variable "static_aaeps" { - description = "List of static aaeps. Allowed values" + description = "List of static aaeps. Allowed values `encap`: `1` - `4096`. Allowed values `primary_encap`: `1` - `4096`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`" type = list(object({ aaep = string encap = number From 234df9eaaa2a424f64dc46fef3ab57b9cd8c1b81 Mon Sep 17 00:00:00 2001 From: Zachery Lantz Date: Mon, 11 Aug 2025 16:54:39 -0400 Subject: [PATCH 5/5] ignore annotation for static aaeps --- modules/terraform-aci-endpoint-group/main.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/terraform-aci-endpoint-group/main.tf b/modules/terraform-aci-endpoint-group/main.tf index 80ba82a1..57d89be6 100644 --- a/modules/terraform-aci-endpoint-group/main.tf +++ b/modules/terraform-aci-endpoint-group/main.tf @@ -533,6 +533,9 @@ resource "aci_rest_managed" "fvRsAepAtt" { mode = each.value.mode instrImedcy = each.value.deployment_immediacy } + lifecycle { + ignore_changes = [ annotation ] + } } resource "aci_rest_managed" "fvUplinkOrderCont" {