diff --git a/aci_access_policies.tf b/aci_access_policies.tf index e8f197e7..f6e5222f 100644 --- a/aci_access_policies.tf +++ b/aci_access_policies.tf @@ -44,14 +44,15 @@ module "aci_routed_domain" { module "aci_aaep" { source = "./modules/terraform-aci-aaep" - for_each = { for aaep in try(local.access_policies.aaeps, []) : aaep.name => aaep if local.modules.aci_aaep && var.manage_access_policies } - name = "${each.value.name}${local.defaults.apic.access_policies.aaeps.name_suffix}" - description = try(each.value.description, "") - infra_vlan = try(each.value.infra_vlan, local.defaults.apic.access_policies.aaeps.infra_vlan) == true ? try(local.access_policies.infra_vlan, 0) : 0 - physical_domains = [for dom in try(each.value.physical_domains, []) : "${dom}${local.defaults.apic.access_policies.physical_domains.name_suffix}"] - routed_domains = [for dom in try(each.value.routed_domains, []) : "${dom}${local.defaults.apic.access_policies.routed_domains.name_suffix}"] - vmware_vmm_domains = try(each.value.vmware_vmm_domains, []) - endpoint_groups = try(each.value.endpoint_groups, []) + for_each = { for aaep in try(local.access_policies.aaeps, []) : aaep.name => aaep if local.modules.aci_aaep && var.manage_access_policies } + name = "${each.value.name}${local.defaults.apic.access_policies.aaeps.name_suffix}" + description = try(each.value.description, "") + infra_vlan = try(each.value.infra_vlan, local.defaults.apic.access_policies.aaeps.infra_vlan) == true ? try(local.access_policies.infra_vlan, 0) : 0 + physical_domains = [for dom in try(each.value.physical_domains, []) : "${dom}${local.defaults.apic.access_policies.physical_domains.name_suffix}"] + routed_domains = [for dom in try(each.value.routed_domains, []) : "${dom}${local.defaults.apic.access_policies.routed_domains.name_suffix}"] + vmware_vmm_domains = try(each.value.vmware_vmm_domains, []) + nutanix_vmm_domains = try(each.value.nutanix_vmm_domains, []) + endpoint_groups = try(each.value.endpoint_groups, []) depends_on = [ module.aci_physical_domain, diff --git a/aci_tenants.tf b/aci_tenants.tf index 05059404..71862f44 100644 --- a/aci_tenants.tf +++ b/aci_tenants.tf @@ -382,6 +382,16 @@ locals { active_uplinks_order = try(vmm.active_uplinks_order, "") standby_uplinks = try(vmm.standby_uplinks, "") }] + nutanix_vmm_domains = [for vmm in try(epg.nutanix_vmm_domains, []) : { + name = "${vmm.name}${local.defaults.apic.tenants.application_profiles.endpoint_groups.nutanix_vmm_domains.name_suffix}" + custom_epg_name = try(vmm.custom_epg_name, "") + ipam = try(vmm.ipam, local.defaults.apic.tenants.application_profiles.endpoint_groups.nutanix_vmm_domains.ipam) + ipam_gateway = try(vmm.ipam_gateway, null) + dhcp_server_address_override = try(vmm.dhcp_server_address_override, null) + dhcp_address_pool = try(vmm.dhcp_address_pool, null) + vlan = try(vmm.vlan, null) + deployment_immediacy = try(vmm.deployment_immediacy, local.defaults.apic.tenants.application_profiles.endpoint_groups.nutanix_vmm_domains.deployment_immediacy) + }] static_ports = [for sp in try(epg.static_ports, []) : { node_id = try(sp.node_id, [for pg in local.leaf_interface_policy_group_mapping : pg.node_ids if pg.name == sp.channel][0][0], null) # set node2_id to "vpc" if channel IPG is vPC, otherwise "null" @@ -469,6 +479,7 @@ module "aci_endpoint_group" { physical_domains = each.value.physical_domains subnets = each.value.subnets vmware_vmm_domains = each.value.vmware_vmm_domains + nutanix_vmm_domains = each.value.nutanix_vmm_domains static_ports = [for sp in try(each.value.static_ports, []) : { description = sp.description node_id = sp.node_id diff --git a/defaults/defaults.yaml b/defaults/defaults.yaml index 5e478045..4e2a8af9 100644 --- a/defaults/defaults.yaml +++ b/defaults/defaults.yaml @@ -1084,6 +1084,10 @@ defaults: allow_promiscuous: reject forged_transmits: reject mac_changes: reject + nutanix_vmm_domains: + name_suffix: "" + ipam: false + deployment_immediacy: lazy static_ports: module: 1 mode: regular diff --git a/modules/terraform-aci-aaep/README.md b/modules/terraform-aci-aaep/README.md index 5ee23577..d94ff693 100644 --- a/modules/terraform-aci-aaep/README.md +++ b/modules/terraform-aci-aaep/README.md @@ -54,6 +54,7 @@ module "aci_aaep" { | [physical\_domains](#input\_physical\_domains) | Physical domains. | `list(string)` | `[]` | no | | [routed\_domains](#input\_routed\_domains) | Routed domains. | `list(string)` | `[]` | no | | [vmware\_vmm\_domains](#input\_vmware\_vmm\_domains) | VMware VMM domains. | `list(string)` | `[]` | no | +| [nutanix\_vmm\_domains](#input\_nutanix\_vmm\_domains) | Nutanix VMM Domains. | `list(string)` | `[]` | no | | [endpoint\_groups](#input\_endpoint\_groups) | List of application endpoint groups. Allowed values `vlan`, `primary_vlan`, `secondary_vlan`: `1` - `4096`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`. |
list(object({
tenant = string
application_profile = string
endpoint_group = string
vlan = optional(number)
primary_vlan = optional(number)
secondary_vlan = optional(number)
mode = optional(string, "regular")
deployment_immediacy = optional(string, "lazy")
})) | `[]` | no |
## Outputs
diff --git a/modules/terraform-aci-aaep/main.tf b/modules/terraform-aci-aaep/main.tf
index dd93a361..918759cf 100644
--- a/modules/terraform-aci-aaep/main.tf
+++ b/modules/terraform-aci-aaep/main.tf
@@ -1,8 +1,9 @@
locals {
- physical_domains = [for dom in var.physical_domains : "uni/phys-${dom}"]
- routed_domains = [for dom in var.routed_domains : "uni/l3dom-${dom}"]
- vmware_vmm_domains = [for dom in var.vmware_vmm_domains : "uni/vmmp-VMware/dom-${dom}"]
- domains = concat(local.physical_domains, local.routed_domains, local.vmware_vmm_domains)
+ physical_domains = [for dom in var.physical_domains : "uni/phys-${dom}"]
+ routed_domains = [for dom in var.routed_domains : "uni/l3dom-${dom}"]
+ vmware_vmm_domains = [for dom in var.vmware_vmm_domains : "uni/vmmp-VMware/dom-${dom}"]
+ nutanix_vmm_domains = [for dom in var.nutanix_vmm_domains : "uni/vmmp-Nutanix/dom-${dom}"]
+ domains = concat(local.physical_domains, local.routed_domains, local.vmware_vmm_domains, local.nutanix_vmm_domains)
}
resource "aci_rest_managed" "infraAttEntityP" {
diff --git a/modules/terraform-aci-aaep/variables.tf b/modules/terraform-aci-aaep/variables.tf
index 36e8c3a3..2b73eca5 100644
--- a/modules/terraform-aci-aaep/variables.tf
+++ b/modules/terraform-aci-aaep/variables.tf
@@ -69,6 +69,19 @@ variable "vmware_vmm_domains" {
}
}
+variable "nutanix_vmm_domains" {
+ description = "Nutanix VMM Domains."
+ type = list(string)
+ default = []
+
+ validation {
+ condition = alltrue([
+ for ntxd in var.nutanix_vmm_domains : can(regex("^[a-zA-Z0-9_.:-]{0,64}$", ntxd))
+ ])
+ error_message = "Allowed characters: `a`-`z`, `A`-`Z`, `0`-`9`, `_`, `.`, `:`, `-`. Maximum characters: 64."
+ }
+}
+
variable "endpoint_groups" {
description = "List of application endpoint groups. Allowed values `vlan`, `primary_vlan`, `secondary_vlan`: `1` - `4096`. Choices `mode`: `regular`, `native`, `untagged`. Default value `mode`: `regular`. Choices `deployment_immediacy`: `immediate`, `lazy`. Default value `deployment_immediacy`: `lazy`."
type = list(object({
diff --git a/modules/terraform-aci-endpoint-group/README.md b/modules/terraform-aci-endpoint-group/README.md
index 5bc86e92..721ebc96 100644
--- a/modules/terraform-aci-endpoint-group/README.md
+++ b/modules/terraform-aci-endpoint-group/README.md
@@ -112,12 +112,14 @@ module "aci_endpoint_group" {
|------|---------|
| [terraform](#requirement\_terraform) | >= 1.3.0 |
| [aci](#requirement\_aci) | >= 2.0.0 |
+| [null](#requirement\_null) | >= 3.2.4 |
## Providers
| Name | Version |
|------|---------|
| [aci](#provider\_aci) | >= 2.0.0 |
+| [null](#provider\_null) | >= 3.2.4 |
## Inputs
@@ -146,6 +148,7 @@ module "aci_endpoint_group" {
| [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)
nd_ra_prefix_policy = optional(string, "")
ip_dataplane_learning = optional(bool, null)
ip_pools = optional(list(object({
name = string
start_ip = optional(string, "0.0.0.0")
end_ip = optional(string, "0.0.0.0")
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 |
+| [nutanix\_vmm\_domains](#input\_nutanix\_vmm\_domains) | List of Nutanix VMM Domains. | list(object({
name = string
custom_epg_name = optional(string, "")
ipam = optional(bool, false)
ipam_gateway = optional(string)
dhcp_server_address_override = optional(string)
dhcp_address_pool = optional(string)
vlan = optional(number)
deployment_immediacy = optional(string, "lazy")
})) | `[]` | 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({
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 |
@@ -165,6 +168,7 @@ module "aci_endpoint_group" {
| Name | Type |
|------|------|
| [aci_rest_managed.fvAEPg](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
+| [aci_rest_managed.fvAEPgAddrMgmtPoolAtt_vmm_nutanix](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
| [aci_rest_managed.fvAEPgLagPolAtt](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
| [aci_rest_managed.fvCepNetCfgPol](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
| [aci_rest_managed.fvEpAnycast](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
@@ -176,6 +180,7 @@ module "aci_endpoint_group" {
| [aci_rest_managed.fvRsCustQosPol](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
| [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.fvRsDomAtt_vmm_nutanix](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 |
@@ -205,4 +210,5 @@ module "aci_endpoint_group" {
| [aci_rest_managed.tagInst](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
| [aci_rest_managed.vmmSecP](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
| [aci_rest_managed.vnsAddrInst](https://registry.terraform.io/providers/CiscoDevNet/aci/latest/docs/resources/rest_managed) | resource |
+| [null_resource.nutanix_vmm_ipam_disable](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
\ No newline at end of file
diff --git a/modules/terraform-aci-endpoint-group/main.tf b/modules/terraform-aci-endpoint-group/main.tf
index e377b792..3c7dbd1b 100644
--- a/modules/terraform-aci-endpoint-group/main.tf
+++ b/modules/terraform-aci-endpoint-group/main.tf
@@ -522,6 +522,50 @@ resource "aci_rest_managed" "fvRsDomAtt_vmm" {
}
}
+resource "null_resource" "nutanix_vmm_ipam_disable" {
+ for_each = { for vmm_ntx in var.nutanix_vmm_domains : vmm_ntx.name => vmm_ntx }
+
+ triggers = {
+ ipam_disable = each.value.ipam != false ? "yes" : "no"
+ }
+}
+
+resource "aci_rest_managed" "fvRsDomAtt_vmm_nutanix" {
+ for_each = { for vmm_ntx in var.nutanix_vmm_domains : vmm_ntx.name => vmm_ntx }
+ dn = "${aci_rest_managed.fvAEPg.dn}/rsdomAtt-[uni/vmmp-Nutanix/dom-${each.value.name}]"
+ class_name = "fvRsDomAtt"
+ content = {
+ tDn = "uni/vmmp-Nutanix/dom-${each.value.name}"
+ customEpgName = each.value.custom_epg_name
+ encapMode = "auto"
+ encap = each.value.vlan != null ? "vlan-${each.value.vlan}" : "unknown"
+ instrImedcy = each.value.deployment_immediacy
+ resImedcy = "pre-provision"
+ switchingMode = "native"
+ ipamEnabled = each.value.ipam != false ? "yes" : "no"
+ ipamGateway = each.value.ipam_gateway != null ? each.value.ipam_gateway : "0.0.0.0"
+ ipamDhcpOverride = each.value.dhcp_server_address_override != null ? each.value.dhcp_server_address_override : "0.0.0.0"
+ }
+ lifecycle {
+ replace_triggered_by = [null_resource.nutanix_vmm_ipam_disable[each.key]]
+ }
+}
+
+resource "aci_rest_managed" "fvAEPgAddrMgmtPoolAtt_vmm_nutanix" {
+ for_each = { for vmm_ntx in var.nutanix_vmm_domains : vmm_ntx.name => vmm_ntx if vmm_ntx.ipam && vmm_ntx.dhcp_address_pool != null }
+ dn = "${aci_rest_managed.fvAEPg.dn}/rsdomAtt-[uni/vmmp-Nutanix/dom-${each.value.name}]/epgipampoolatt"
+ class_name = "fvAEPgAddrMgmtPoolAtt"
+ content = {}
+ child {
+ class_name = "fvRsAddrMgmtPool"
+ rn = "rsAddrMgmtPool"
+ content = {
+ tDn = "uni/tn-${var.tenant}/ipampool-${each.value.dhcp_address_pool}"
+ }
+ }
+ depends_on = [aci_rest_managed.fvRsDomAtt_vmm_nutanix]
+}
+
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"
diff --git a/modules/terraform-aci-endpoint-group/variables.tf b/modules/terraform-aci-endpoint-group/variables.tf
index d3a5861a..b2bdcc98 100644
--- a/modules/terraform-aci-endpoint-group/variables.tf
+++ b/modules/terraform-aci-endpoint-group/variables.tf
@@ -360,6 +360,50 @@ variable "vmware_vmm_domains" {
}
+variable "nutanix_vmm_domains" {
+ description = "List of Nutanix VMM Domains."
+ type = list(object({
+ name = string
+ custom_epg_name = optional(string, "")
+ ipam = optional(bool, false)
+ ipam_gateway = optional(string)
+ dhcp_server_address_override = optional(string)
+ dhcp_address_pool = optional(string)
+ vlan = optional(number)
+ deployment_immediacy = optional(string, "lazy")
+ }))
+ default = []
+
+ validation {
+ condition = alltrue([
+ for dom in var.nutanix_vmm_domains : can(regex("^[a-zA-Z0-9_.:-]{0,64}$", dom.name))
+ ])
+ error_message = "`name`: Allowed characters: `a`-`z`, `A`-`Z`, `0`-`9`, `_`, `.`, `:`, `-`. Maximum characters: 64."
+ }
+
+ validation {
+ condition = alltrue([
+ for dom in var.nutanix_vmm_domains : dom.vlan == null || try(dom.vlan >= 1 && dom.vlan <= 4096, false)
+ ])
+ error_message = "`vlan`: Minimum value: `1`. Maximum value: `4096`."
+ }
+
+ validation {
+ condition = alltrue([
+ for dom in var.nutanix_vmm_domains : dom.deployment_immediacy == null || try(contains(["immediate", "lazy"], dom.deployment_immediacy), false)
+ ])
+ error_message = "`deployment_immediacy`: Allowed values are `immediate` or `lazy`."
+ }
+
+ validation {
+ condition = alltrue([
+ for dom in var.nutanix_vmm_domains : dom.custom_epg_name == null || can(regex("^.{0,55}$", dom.custom_epg_name))
+ ])
+ error_message = "`custom_epg_name`: Maximum characters: 55."
+ }
+
+}
+
variable "static_leafs" {
description = "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`"
type = list(object({
diff --git a/modules/terraform-aci-endpoint-group/versions.tf b/modules/terraform-aci-endpoint-group/versions.tf
index 9299fb61..0dc468bb 100644
--- a/modules/terraform-aci-endpoint-group/versions.tf
+++ b/modules/terraform-aci-endpoint-group/versions.tf
@@ -7,5 +7,9 @@ terraform {
source = "CiscoDevNet/aci"
version = ">= 2.0.0"
}
+ null = {
+ source = "hashicorp/null"
+ version = ">= 3.2.4"
+ }
}
}