diff --git a/aci_tenants.tf b/aci_tenants.tf index 0ac60a5e..c3cffd59 100644 --- a/aci_tenants.tf +++ b/aci_tenants.tf @@ -297,18 +297,19 @@ locals { application_profile = try(master.application_profile, "${ap.name}${local.defaults.apic.tenants.application_profiles.name_suffix}") }] subnets = [for subnet in try(epg.subnets, []) : { - description = try(subnet.description, "") - ip = subnet.ip - public = try(subnet.public, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.public) - shared = try(subnet.shared, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.shared) - igmp_querier = try(subnet.igmp_querier, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.igmp_querier) - nd_ra_prefix = try(subnet.nd_ra_prefix, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.nd_ra_prefix) - no_default_gateway = try(subnet.no_default_gateway, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.no_default_gateway) - next_hop_ip = try(subnet.next_hop_ip, "") - anycast_mac = try(subnet.anycast_mac, "") - nlb_group = try(subnet.nlb_group, "0.0.0.0") - nlb_mac = try(subnet.nlb_mac, "00:00:00:00:00:00") - nlb_mode = try(subnet.nlb_mode, "") + description = try(subnet.description, "") + ip = subnet.ip + public = try(subnet.public, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.public) + shared = try(subnet.shared, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.shared) + igmp_querier = try(subnet.igmp_querier, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.igmp_querier) + nd_ra_prefix = try(subnet.nd_ra_prefix, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.nd_ra_prefix) + no_default_gateway = try(subnet.no_default_gateway, local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.no_default_gateway) + nd_ra_prefix_policy = try("${subnet.nd_ra_prefix_policy}${local.defaults.apic.tenants.policies.nd_ra_prefix_policies.name_suffix}", "") + next_hop_ip = try(subnet.next_hop_ip, "") + anycast_mac = try(subnet.anycast_mac, "") + nlb_group = try(subnet.nlb_group, "0.0.0.0") + nlb_mac = try(subnet.nlb_mac, "00:00:00:00:00:00") + nlb_mode = try(subnet.nlb_mode, "") ip_pools = [for pool in try(subnet.ip_pools, []) : { name = "${pool.name}${local.defaults.apic.tenants.application_profiles.endpoint_groups.subnets.ip_pools.name_suffix}" start_ip = try(pool.start_ip, "") diff --git a/modules/terraform-aci-endpoint-group/README.md b/modules/terraform-aci-endpoint-group/README.md index 771113fe..0df058f2 100644 --- a/modules/terraform-aci-endpoint-group/README.md +++ b/modules/terraform-aci-endpoint-group/README.md @@ -139,7 +139,7 @@ module "aci_endpoint_group" { | [contract\_intra\_epgs](#input\_contract\_intra\_epgs) | List of intra-EPG contracts. | `list(string)` | `[]` | no | | [contract\_masters](#input\_contract\_masters) | List of EPG contract masters. |
list(object({
endpoint_group = string
application_profile = optional(string, "")
}))
| `[]` | no | | [physical\_domains](#input\_physical\_domains) | List of physical domains. | `list(string)` | `[]` | no | -| [subnets](#input\_subnets) | List of subnets. Default value `public`: `false`. Default value `shared`: `false`. Default value `igmp_querier`: `false`. Default value `nd_ra_prefix`: `true`. Default value `no_default_gateway`: `false`. `nlb_mode` allowed values: `mode-mcast-igmp`, `mode-uc` or `mode-mcast-static`. |
list(object({
description = optional(string, "")
ip = string
public = optional(bool, false)
shared = optional(bool, false)
igmp_querier = optional(bool, false)
nd_ra_prefix = optional(bool, true)
no_default_gateway = optional(bool, false)
ip_pools = optional(list(object({
name = string
start_ip = optional(string, "")
end_ip = optional(string, "")
dns_search_suffix = optional(string, "")
dns_server = optional(string, "")
dns_suffix = optional(string, "")
wins_server = optional(string, "")
})), [])
next_hop_ip = optional(string, "")
anycast_mac = optional(string, "")
nlb_group = optional(string, "0.0.0.0")
nlb_mac = optional(string, "00:00:00:00:00:00")
nlb_mode = optional(string, "")
}))
| `[]` | no | +| [subnets](#input\_subnets) | List of subnets. Default value `public`: `false`. Default value `shared`: `false`. Default value `igmp_querier`: `false`. Default value `nd_ra_prefix`: `true`. Default value `no_default_gateway`: `false`. `nlb_mode` allowed values: `mode-mcast-igmp`, `mode-uc` or `mode-mcast-static`. |
list(object({
description = optional(string, "")
ip = string
public = optional(bool, false)
shared = optional(bool, false)
igmp_querier = optional(bool, false)
nd_ra_prefix = optional(bool, true)
no_default_gateway = optional(bool, false)
nd_ra_prefix_policy = optional(string, "")
ip_pools = optional(list(object({
name = string
start_ip = optional(string, "")
end_ip = optional(string, "")
dns_search_suffix = optional(string, "")
dns_server = optional(string, "")
dns_suffix = optional(string, "")
wins_server = optional(string, "")
})), [])
next_hop_ip = optional(string, "")
anycast_mac = optional(string, "")
nlb_group = optional(string, "0.0.0.0")
nlb_mac = optional(string, "00:00:00:00:00:00")
nlb_mode = optional(string, "")
}))
| `[]` | no | | [vmware\_vmm\_domains](#input\_vmware\_vmm\_domains) | List of VMware VMM domains. Default value `u_segmentation`: `false`. Default value `netflow`: `false`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`. Choices `resolution_immediacy`: `immediate`, `lazy`, `pre-provision`. Default value `resolution_immediacy`: `immediate`. Default value `allow_promiscuous`: `false`. Default value `forged_transmits`: `false`. Default value `mac_changes`: `false`. |
list(object({
name = string
u_segmentation = optional(bool, false)
delimiter = optional(string, "")
vlan = optional(number)
primary_vlan = optional(number)
secondary_vlan = optional(number)
netflow = optional(bool, false)
deployment_immediacy = optional(string, "lazy")
resolution_immediacy = optional(string, "immediate")
allow_promiscuous = optional(bool, false)
forged_transmits = optional(bool, false)
mac_changes = optional(bool, false)
custom_epg_name = optional(string, "")
elag = optional(string, "")
active_uplinks_order = optional(string, "")
standby_uplinks = optional(string, "")
}))
| `[]` | no | | [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({
node_id = number
node2_id = optional(number)
fex_id = optional(number)
fex2_id = optional(number)
vlan = 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")
}))
| `[]` | no | @@ -171,6 +171,7 @@ module "aci_endpoint_group" { | [aci_rest_managed.fvRsDomAtt](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsDomAtt_vmm](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsIntraEpg](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | +| [aci_rest_managed.fvRsNdPfxPol](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsNodeAtt](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsPathAtt_channel](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource | | [aci_rest_managed.fvRsPathAtt_fex_channel](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 1d30cfd6..be216263 100644 --- a/modules/terraform-aci-endpoint-group/main.tf +++ b/modules/terraform-aci-endpoint-group/main.tf @@ -69,6 +69,15 @@ resource "aci_rest_managed" "fvSubnet" { } } +resource "aci_rest_managed" "fvRsNdPfxPol" { + for_each = { for subnet in var.subnets : subnet.ip => subnet if subnet.nd_ra_prefix_policy != "" } + dn = "${aci_rest_managed.fvSubnet[each.key].dn}/rsNdPfxPol" + class_name = "fvRsNdPfxPol" + content = { + tnNdPfxPolName = each.value.nd_ra_prefix_policy + } +} + resource "aci_rest_managed" "fvCepNetCfgPol" { for_each = { for pool in local.ip_pools_list : pool.id => pool } dn = "${aci_rest_managed.fvSubnet[each.value.subnet_ip].dn}/cepNetCfgPol-${each.value.name}" diff --git a/modules/terraform-aci-endpoint-group/variables.tf b/modules/terraform-aci-endpoint-group/variables.tf index a005f4fb..1aec5ce3 100644 --- a/modules/terraform-aci-endpoint-group/variables.tf +++ b/modules/terraform-aci-endpoint-group/variables.tf @@ -221,13 +221,14 @@ variable "physical_domains" { variable "subnets" { description = "List of subnets. Default value `public`: `false`. Default value `shared`: `false`. Default value `igmp_querier`: `false`. Default value `nd_ra_prefix`: `true`. Default value `no_default_gateway`: `false`. `nlb_mode` allowed values: `mode-mcast-igmp`, `mode-uc` or `mode-mcast-static`." type = list(object({ - description = optional(string, "") - ip = string - public = optional(bool, false) - shared = optional(bool, false) - igmp_querier = optional(bool, false) - nd_ra_prefix = optional(bool, true) - no_default_gateway = optional(bool, false) + description = optional(string, "") + ip = string + public = optional(bool, false) + shared = optional(bool, false) + igmp_querier = optional(bool, false) + nd_ra_prefix = optional(bool, true) + no_default_gateway = optional(bool, false) + nd_ra_prefix_policy = optional(string, "") ip_pools = optional(list(object({ name = string start_ip = optional(string, "") @@ -252,6 +253,13 @@ variable "subnets" { error_message = "`description`: Allowed characters: `a`-`z`, `A`-`Z`, `0`-`9`, `\\`, `!`, `#`, `$`, `%`, `(`, `)`, `*`, `,`, `-`, `.`, `/`, `:`, `;`, `@`, ` `, `_`, `{`, `|`, }`, `~`, `?`, `&`, `+`. Maximum characters: 128." } + validation { + condition = alltrue([ + for s in var.subnets : s.nd_ra_prefix_policy == null || can(regex("^[a-zA-Z0-9_.-]{0,64}$", s.nd_ra_prefix_policy)) + ]) + error_message = "`nd_ra_prefix_policy`: Allowed characters: `a`-`z`, `A`-`Z`, `0`-`9`, `_`, `.`, `-`. Maximum characters: 64." + } + validation { condition = alltrue([ for s in var.subnets : try(contains(["mode-mcast-igmp", "mode-uc", "mode-mcast-static", ""], s.nlb_mode), false)