From 69c93c9644de94fc5c6c068b002f0cc55f410157 Mon Sep 17 00:00:00 2001 From: Zachery Lantz Date: Mon, 11 Aug 2025 16:43:21 -0400 Subject: [PATCH 1/2] added support for epg nutanix vmm binding --- aci_tenants.tf | 11 +++++ defaults/defaults.yaml | 4 ++ .../terraform-aci-endpoint-group/README.md | 6 +++ modules/terraform-aci-endpoint-group/main.tf | 44 +++++++++++++++++++ .../terraform-aci-endpoint-group/variables.tf | 44 +++++++++++++++++++ .../terraform-aci-endpoint-group/versions.tf | 4 ++ 6 files changed, 113 insertions(+) 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-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" + } } } From 0d4c02be7956acca79516084201f47fa2ae4f755 Mon Sep 17 00:00:00 2001 From: Zachery Lantz Date: Wed, 13 Aug 2025 14:30:28 -0400 Subject: [PATCH 2/2] added support for binding ntx vmm domain to aaep --- aci_access_policies.tf | 17 +++++++++-------- modules/terraform-aci-aaep/README.md | 1 + modules/terraform-aci-aaep/main.tf | 9 +++++---- modules/terraform-aci-aaep/variables.tf | 13 +++++++++++++ 4 files changed, 28 insertions(+), 12 deletions(-) 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/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({