From 9ef6fd7261085cad163f135737d7471e13ed2f95 Mon Sep 17 00:00:00 2001 From: Conor Murphy Date: Mon, 16 Jun 2025 16:29:27 +0200 Subject: [PATCH 1/4] Adding support to enable the N9300 smart switch with DPUs and Hypershield --- README.md | 7 +++ nxos_feature.tf | 9 +++ nxos_service_hypershield.tf | 118 ++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 nxos_service_hypershield.tf diff --git a/README.md b/README.md index d4b40d1..6f5b9fd 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,13 @@ module "nxos" { | [nxos_port_channel_interface.port_channel_interface](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/port_channel_interface) | resource | | [nxos_port_channel_interface_member.port_channel_interface_member](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/port_channel_interface_member) | resource | | [nxos_port_channel_interface_vrf.port_channel_interface_vrf](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/port_channel_interface_vrf) | resource | +| [nxos_rest.service_acceleration](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | +| [nxos_rest.service_system_hypershield_sas_sas](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | +| [nxos_rest.service_system_hypershield_sas_svc](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | +| [nxos_rest.service_system_hypershield_sas_svc_fw_policy](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | +| [nxos_rest.service_system_hypershield_sas_svc_fw_policy_ip_vrf](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | +| [nxos_rest.service_system_hypershield_sas_svc_instance](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | +| [nxos_rest.service_system_hypershield_sas_svc_scontroller](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | | [nxos_route_map_rule.route_map_rule](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/route_map_rule) | resource | | [nxos_route_map_rule_entry.route_map_rule_entry](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/route_map_rule_entry) | resource | | [nxos_route_map_rule_entry_match_route.route_map_rule_entry_match_route](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/route_map_rule_entry_match_route) | resource | diff --git a/nxos_feature.tf b/nxos_feature.tf index ec679f0..ff3bd27 100644 --- a/nxos_feature.tf +++ b/nxos_feature.tf @@ -110,6 +110,15 @@ resource "nxos_feature_pvlan" "pvlan" { admin_state = try(local.device_config[each.key].system.feature.pvlan, local.defaults.nxos.devices.configuration.system.feature.pvlan) ? "enabled" : "disabled" } +resource "nxos_rest" "service_acceleration" { + for_each = { for device in local.devices : device.name => device if try(local.device_config[device.name].system.feature.service_acceleration, local.defaults.nxos.devices.configuration.system.feature.service_acceleration, null) != null } + dn = "sys/fm/serviceacceleration" + class_name = "fmServiceAcceleration" + content = { + adminSt : try(local.device_config[each.key].system.feature.service_acceleration, local.defaults.nxos.devices.configuration.system.feature.service_acceleration) ? "enabled" : "disabled" + } +} + resource "nxos_feature_ssh" "ssh" { for_each = { for device in local.devices : device.name => device if try(local.device_config[device.name].system.feature.ssh, local.defaults.nxos.devices.configuration.system.feature.ssh, null) != null } device = each.key diff --git a/nxos_service_hypershield.tf b/nxos_service_hypershield.tf new file mode 100644 index 0000000..f004d81 --- /dev/null +++ b/nxos_service_hypershield.tf @@ -0,0 +1,118 @@ +locals { + service_hypershield = flatten([ + for device in local.devices : [ + { + key = format("%s", device.name) + device = device.name + source_interface = try(local.device_config[device.name].hypershield.source_interface, null) + https_proxy_port = try(local.device_config[device.name].hypershield.https_proxy_port, null) + https_proxy_server = try(local.device_config[device.name].hypershield.https_proxy_server, null) + admin_state = try(local.device_config[device.name].hypershield.admin_state == "in-service" || local.device_config[device.name].hypershield.admin_state == null ? "in-service" : local.device_config[device.name].hypershield.admin_state, null) + vrfs = try(local.device_config[device.name].hypershield.vrfs, []) + }] + ]) + +} + + +resource "nxos_rest" "service_system_hypershield_sas_sas" { + for_each = { for v in local.service_hypershield : v.key => v } + + dn = "sys/sas" + class_name = "sasSas" + +} + +resource "nxos_rest" "service_system_hypershield_sas_svc" { + for_each = { for v in local.service_hypershield : v.key => v } + + dn = "sys/sas/svc" + class_name = "sasSvc" + + depends_on = [nxos_rest.service_system_hypershield_sas_sas] + +} + +resource "nxos_rest" "service_system_hypershield_sas_svc_instance" { + for_each = { for v in local.service_hypershield : v.key => v } + + dn = "sys/sas/svc/svcinst-hypershield" + class_name = "sasSvcInstance" + + content = { + cpSrcInterface = each.value.source_interface + name = "hypershield" # This is the sevice name and must be set to hypershield - This line refers to the "service system hypershield" command + } + + depends_on = [nxos_rest.service_system_hypershield_sas_svc] +} + +resource "nxos_rest" "service_system_hypershield_sas_svc_scontroller" { + for_each = { for v in local.service_hypershield : v.key => v } + + dn = "sys/sas/svc/svcinst-hypershield/scontroller" + class_name = "sasSController" + content = { + httpsProxyPort = each.value.https_proxy_port + httpsProxySvr = each.value.https_proxy_server + } + + depends_on = [nxos_rest.service_system_hypershield_sas_svc_instance] + +} + +resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy" { + for_each = { for v in local.service_hypershield : v.key => v } + + dn = "sys/sas/svc/svcinst-hypershield/fwpolicy" + class_name = "sasFwSvcPolicy" + content = { + adminState = each.value.admin_state + } + + lifecycle { + precondition { + condition = each.value.admin_state == "in-service" || each.value.admin_state == null + error_message = "Allowed values: `in-service` or null" + } + } + + + depends_on = [nxos_rest.service_system_hypershield_sas_svc_instance] + +} + +locals { + service_hypershield_vrfs = flatten([ + for device in local.devices : [ + for vrf in try(local.device_config[device.name].hypershield.vrfs, []) : { + key = format("%s_vrf_%s", device.name, vrf.name) + device = device.name + vrf_name = vrf.name + affinity = try(contains([0, 1, 2, 3, 4], vrf.affinity) ? vrf.affinity : (vrf.affinity == "dynamic" || vrf.affinity == null ? "0" : vrf.affinity), "0") + } + ] + ]) +} + + +resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy_ip_vrf" { + for_each = { for v in local.service_hypershield_vrfs : v.key => v } + + dn = "sys/sas/svc/svcinst-hypershield/fwpolicy/ipvrf/dom-[${each.value.vrf_name}]" + class_name = "sasDom" + content = { + name = each.value.vrf_name + affinity = each.value.affinity + } + + lifecycle { + precondition { + condition = contains(["0", "1", "2", "3", "4", null, "dynamic"], each.value.affinity) + error_message = "Allowed values: 1, 2, 3, 4. For dynamic affinity use `dynamic`, 0, or null" + } + } + + depends_on = [nxos_rest.service_system_hypershield_sas_svc_fw_policy] + +} \ No newline at end of file From 0b645ed0a669c07aac1d6f0791ae2388174b5da2 Mon Sep 17 00:00:00 2001 From: Conor Murphy Date: Mon, 16 Jun 2025 17:45:59 +0200 Subject: [PATCH 2/4] Updated to allow for the deletion of source interface and proxy values --- nxos_service_hypershield.tf | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/nxos_service_hypershield.tf b/nxos_service_hypershield.tf index f004d81..9daa334 100644 --- a/nxos_service_hypershield.tf +++ b/nxos_service_hypershield.tf @@ -7,7 +7,7 @@ locals { source_interface = try(local.device_config[device.name].hypershield.source_interface, null) https_proxy_port = try(local.device_config[device.name].hypershield.https_proxy_port, null) https_proxy_server = try(local.device_config[device.name].hypershield.https_proxy_server, null) - admin_state = try(local.device_config[device.name].hypershield.admin_state == "in-service" || local.device_config[device.name].hypershield.admin_state == null ? "in-service" : local.device_config[device.name].hypershield.admin_state, null) + admin_state = try(local.device_config[device.name].hypershield.admin_state, null) vrfs = try(local.device_config[device.name].hypershield.vrfs, []) }] ]) @@ -40,7 +40,7 @@ resource "nxos_rest" "service_system_hypershield_sas_svc_instance" { class_name = "sasSvcInstance" content = { - cpSrcInterface = each.value.source_interface + cpSrcInterface = (each.value.source_interface == null || each.value.source_interface == "" ? "DME_UNSET_PROPERTY_MARKER" : each.value.source_interface) name = "hypershield" # This is the sevice name and must be set to hypershield - This line refers to the "service system hypershield" command } @@ -53,8 +53,8 @@ resource "nxos_rest" "service_system_hypershield_sas_svc_scontroller" { dn = "sys/sas/svc/svcinst-hypershield/scontroller" class_name = "sasSController" content = { - httpsProxyPort = each.value.https_proxy_port - httpsProxySvr = each.value.https_proxy_server + httpsProxyPort = (each.value.https_proxy_port == null || each.value.https_proxy_port == "" ? "DME_UNSET_PROPERTY_MARKER" : each.value.https_proxy_port) + httpsProxySvr = (each.value.https_proxy_server == null || each.value.https_proxy_server == "" ? "DME_UNSET_PROPERTY_MARKER" : each.value.https_proxy_server) } depends_on = [nxos_rest.service_system_hypershield_sas_svc_instance] @@ -72,12 +72,11 @@ resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy" { lifecycle { precondition { - condition = each.value.admin_state == "in-service" || each.value.admin_state == null - error_message = "Allowed values: `in-service` or null" + condition = each.value.admin_state == "in-service" || each.value.admin_state == "out-of-service" || each.value.admin_state == null + error_message = "Allowed values: `in-service`, `out-of-service`" } } - depends_on = [nxos_rest.service_system_hypershield_sas_svc_instance] } From fd8eec6bb5e19326c7449aec3c6295f20d50d253 Mon Sep 17 00:00:00 2001 From: Conor Murphy Date: Tue, 17 Jun 2025 08:28:36 +0200 Subject: [PATCH 3/4] Adding some checks for the main hypershield section and cleaning up if not there - equvalent of 'no service system hypershield command' --- README.md | 1 + nxos_service_hypershield.tf | 56 +++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 6f5b9fd..9c5ad02 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ module "nxos" { | [nxos_rest.service_system_hypershield_sas_svc_fw_policy](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | | [nxos_rest.service_system_hypershield_sas_svc_fw_policy_ip_vrf](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | | [nxos_rest.service_system_hypershield_sas_svc_instance](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | +| [nxos_rest.service_system_hypershield_sas_svc_instance_delete](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | | [nxos_rest.service_system_hypershield_sas_svc_scontroller](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/rest) | resource | | [nxos_route_map_rule.route_map_rule](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/route_map_rule) | resource | | [nxos_route_map_rule_entry.route_map_rule_entry](https://registry.terraform.io/providers/CiscoDevNet/nxos/latest/docs/resources/route_map_rule_entry) | resource | diff --git a/nxos_service_hypershield.tf b/nxos_service_hypershield.tf index 9daa334..dbfd9d5 100644 --- a/nxos_service_hypershield.tf +++ b/nxos_service_hypershield.tf @@ -3,6 +3,7 @@ locals { for device in local.devices : [ { key = format("%s", device.name) + hypershield = try(local.device_config[device.name].hypershield, null) device = device.name source_interface = try(local.device_config[device.name].hypershield.source_interface, null) https_proxy_port = try(local.device_config[device.name].hypershield.https_proxy_port, null) @@ -14,9 +15,8 @@ locals { } - resource "nxos_rest" "service_system_hypershield_sas_sas" { - for_each = { for v in local.service_hypershield : v.key => v } + for_each = { for v in local.service_hypershield : v.key => v if v.hypershield != null } dn = "sys/sas" class_name = "sasSas" @@ -24,7 +24,7 @@ resource "nxos_rest" "service_system_hypershield_sas_sas" { } resource "nxos_rest" "service_system_hypershield_sas_svc" { - for_each = { for v in local.service_hypershield : v.key => v } + for_each = { for v in local.service_hypershield : v.key => v if v.hypershield != null } dn = "sys/sas/svc" class_name = "sasSvc" @@ -34,21 +34,39 @@ resource "nxos_rest" "service_system_hypershield_sas_svc" { } resource "nxos_rest" "service_system_hypershield_sas_svc_instance" { - for_each = { for v in local.service_hypershield : v.key => v } + for_each = { for v in local.service_hypershield : v.key => v if v.hypershield != null } dn = "sys/sas/svc/svcinst-hypershield" class_name = "sasSvcInstance" - content = { - cpSrcInterface = (each.value.source_interface == null || each.value.source_interface == "" ? "DME_UNSET_PROPERTY_MARKER" : each.value.source_interface) - name = "hypershield" # This is the sevice name and must be set to hypershield - This line refers to the "service system hypershield" command - } + content = merge( + { + cpSrcInterface = (each.value.source_interface == null || each.value.source_interface == "" ? "DME_UNSET_PROPERTY_MARKER" : each.value.source_interface) + name = "hypershield" # This is the service name and must be set to hypershield - This line refers to the "service system hypershield" command + } + ) + + depends_on = [nxos_rest.service_system_hypershield_sas_svc] +} + +resource "nxos_rest" "service_system_hypershield_sas_svc_instance_delete" { + for_each = { for v in local.service_hypershield : v.key => v if v.hypershield == null } + + dn = "sys/sas/svc/svcinst-hypershield" + class_name = "sasSvcInstance" + + content = merge( + { + name = "hypershield" # This is the equvalent of the "no service system hypershield" command + status = "deleted" + } + ) depends_on = [nxos_rest.service_system_hypershield_sas_svc] } resource "nxos_rest" "service_system_hypershield_sas_svc_scontroller" { - for_each = { for v in local.service_hypershield : v.key => v } + for_each = { for v in local.service_hypershield : v.key => v if v.hypershield != null } dn = "sys/sas/svc/svcinst-hypershield/scontroller" class_name = "sasSController" @@ -62,7 +80,7 @@ resource "nxos_rest" "service_system_hypershield_sas_svc_scontroller" { } resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy" { - for_each = { for v in local.service_hypershield : v.key => v } + for_each = { for v in local.service_hypershield : v.key => v if v.hypershield != null } dn = "sys/sas/svc/svcinst-hypershield/fwpolicy" class_name = "sasFwSvcPolicy" @@ -80,23 +98,25 @@ resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy" { depends_on = [nxos_rest.service_system_hypershield_sas_svc_instance] } - locals { service_hypershield_vrfs = flatten([ for device in local.devices : [ for vrf in try(local.device_config[device.name].hypershield.vrfs, []) : { - key = format("%s_vrf_%s", device.name, vrf.name) - device = device.name - vrf_name = vrf.name - affinity = try(contains([0, 1, 2, 3, 4], vrf.affinity) ? vrf.affinity : (vrf.affinity == "dynamic" || vrf.affinity == null ? "0" : vrf.affinity), "0") + key = format("%s_vrf_%s", device.name, vrf.name) + hypershield = try(local.device_config[device.name].hypershield, null) + device = device.name + vrf_name = vrf.name + affinity = ( + contains([0, 1, 2, 3, 4], vrf.affinity) ? vrf.affinity : + (vrf.affinity == "dynamic" || vrf.affinity == null ? "0" : vrf.affinity) + ) } ] ]) } - resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy_ip_vrf" { - for_each = { for v in local.service_hypershield_vrfs : v.key => v } + for_each = { for v in local.service_hypershield_vrfs : v.key => v if v.hypershield != null } dn = "sys/sas/svc/svcinst-hypershield/fwpolicy/ipvrf/dom-[${each.value.vrf_name}]" class_name = "sasDom" @@ -108,7 +128,7 @@ resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy_ip_vrf" { lifecycle { precondition { condition = contains(["0", "1", "2", "3", "4", null, "dynamic"], each.value.affinity) - error_message = "Allowed values: 1, 2, 3, 4. For dynamic affinity use `dynamic`, 0, or null" + error_message = "Allowed values: 1, 2, 3, 4. For dynamic affinity use `dynamic`, 0" } } From 9654cb0704fff46f5a9143a0b32af7ab44587346 Mon Sep 17 00:00:00 2001 From: Conor Murphy Date: Tue, 17 Jun 2025 08:50:02 +0200 Subject: [PATCH 4/4] Fixed affinity validation check to make this attribute optional --- nxos_service_hypershield.tf | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/nxos_service_hypershield.tf b/nxos_service_hypershield.tf index dbfd9d5..9a56a65 100644 --- a/nxos_service_hypershield.tf +++ b/nxos_service_hypershield.tf @@ -107,8 +107,8 @@ locals { device = device.name vrf_name = vrf.name affinity = ( - contains([0, 1, 2, 3, 4], vrf.affinity) ? vrf.affinity : - (vrf.affinity == "dynamic" || vrf.affinity == null ? "0" : vrf.affinity) + try(contains([0, 1, 2, 3, 4], vrf.affinity) ? vrf.affinity : + (vrf.affinity == "dynamic" ? "0" : vrf.affinity), null) ) } ] @@ -127,7 +127,11 @@ resource "nxos_rest" "service_system_hypershield_sas_svc_fw_policy_ip_vrf" { lifecycle { precondition { - condition = contains(["0", "1", "2", "3", "4", null, "dynamic"], each.value.affinity) + condition = ( + each.value.affinity == null ? true : ( + contains(["0", "1", "2", "3", "4", "dynamic"], each.value.affinity) + ) + ) error_message = "Allowed values: 1, 2, 3, 4. For dynamic affinity use `dynamic`, 0" } }