Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions plugins/modules/dcnm_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -1882,6 +1882,11 @@
find_dict_in_list_by_key_value,
)
from ..module_utils.common.log_v2 import Log
from ..module_utils.common.controller_version_v2 import ControllerVersion
from ..module_utils.common.rest_send_v2 import RestSend
from ..module_utils.common.response_handler import ResponseHandler
from ..module_utils.common.sender_dcnm import Sender
from ..module_utils.common.exceptions import ControllerResponseError


def json_pretty(msg):
Expand Down Expand Up @@ -1968,6 +1973,7 @@ def __init__(self, module):
]

self.dcnm_version = dcnm_version_supported(self.module)
self.ndfc_version = self._get_ndfc_version()

self.inventory_data = {}
self.manageable = []
Expand Down Expand Up @@ -2062,6 +2068,12 @@ def __init__(self, module):

}

# NDFC 12.4.1+ (ND 4.1.1+) parameters
if self._ndfc_version_gte("12.4.1"):
self.keymap.update({
"FEC": "fec",
})

# New Interfaces
self.pol_types = {
11: {
Expand Down Expand Up @@ -2161,6 +2173,35 @@ def __init__(self, module):
msg = "ENTERED DcnmIntf: "
self.log.debug(msg)

def _get_ndfc_version(self):
"""Return the full NDFC version string (e.g. '12.4.1.245') using ControllerVersion, or None on failure."""
try:
sender = Sender()
sender.ansible_module = self.module
rest_send = RestSend(self.module.params)
rest_send.response_handler = ResponseHandler()
rest_send.sender = sender
controller_version = ControllerVersion()
controller_version.rest_send = rest_send
controller_version.refresh()
raw_version = controller_version.version
if raw_version:
return re.sub(r'[a-zA-Z]+$', '', raw_version)
except (ControllerResponseError, ValueError) as error:
self.log.warning("Unable to determine NDFC version: %s", error)
return None

def _ndfc_version_gte(self, target):
"""Check if NDFC version >= target. Uses tuple comparison on version segments."""
if not self.ndfc_version:
return False
try:
current = tuple(int(x) for x in self.ndfc_version.split(".")[:3])
required = tuple(int(x) for x in target.split(".")[:3])
return current >= required
except (ValueError, AttributeError):
return False

def dcnm_intf_breakout_format(self, if_name):
# Define the pattern to match '1/x/y' where x and y are integers
pattern = r'^ethernet1/\d+/\d+$'
Expand Down Expand Up @@ -2676,6 +2717,11 @@ def dcnm_intf_validate_ethernet_interface_input(self, cfg):
queuing_policy=dict(type="str", default=""),
)

if self._ndfc_version_gte("12.4.1"):
eth_prof_spec_trunk.update({
"fec": dict(type="str", default="auto", choices=["auto", "fc-fec", "off", "rs-cons16", "rs-fec", "rs-ieee"]),
})

eth_prof_spec_access = dict(
mode=dict(required=True, type="str"),
bpdu_guard=dict(type="str", default="true"),
Expand All @@ -2699,6 +2745,11 @@ def dcnm_intf_validate_ethernet_interface_input(self, cfg):
queuing_policy=dict(type="str", default=""),
)

if self._ndfc_version_gte("12.4.1"):
eth_prof_spec_access.update({
"fec": dict(type="str", default="auto", choices=["auto", "fc-fec", "off", "rs-cons16", "rs-fec", "rs-ieee"]),
})

eth_prof_spec_routed_host = dict(
int_vrf=dict(type="str", default="default"),
ipv4_addr=dict(type="ipv4", default=""),
Expand All @@ -2714,6 +2765,11 @@ def dcnm_intf_validate_ethernet_interface_input(self, cfg):
queuing_policy=dict(type="str", default=""),
)

if self._ndfc_version_gte("12.4.1"):
eth_prof_spec_routed_host.update({
"fec": dict(type="str", default="auto", choices=["auto", "fc-fec", "off", "rs-cons16", "rs-fec", "rs-ieee"]),
})

eth_prof_spec_epl_routed_host = dict(
mode=dict(required=True, type="str"),
ipv4_addr=dict(required=True, type="ipv4"),
Expand Down Expand Up @@ -2746,6 +2802,11 @@ def dcnm_intf_validate_ethernet_interface_input(self, cfg):
type="str", default="auto", choices=["auto", "full", "half"]),
)

if self._ndfc_version_gte("12.4.1"):
eth_prof_spec_dot1q_tunnel_host.update({
"fec": dict(type="str", default="auto", choices=["auto", "fc-fec", "off", "rs-cons16", "rs-fec", "rs-ieee"]),
})

if "trunk" == cfg[0]["profile"]["mode"]:
self.dcnm_intf_validate_interface_input(
cfg, eth_spec, eth_prof_spec_trunk
Expand Down Expand Up @@ -3565,6 +3626,8 @@ def dcnm_intf_get_eth_payload(self, delem, intf, profile):
intf["interfaces"][0]["nvPairs"]["QUEUING_POLICY"] = delem[profile]["queuing_policy"]
else:
intf["interfaces"][0]["nvPairs"]["QUEUING_POLICY"] = ""
if self._ndfc_version_gte("12.4.1"):
intf["interfaces"][0]["nvPairs"]["FEC"] = delem[profile].get("fec", "auto")
if delem[profile]["mode"] == "access":
intf["interfaces"][0]["nvPairs"]["BPDUGUARD_ENABLED"] = delem[
profile
Expand Down Expand Up @@ -3602,6 +3665,8 @@ def dcnm_intf_get_eth_payload(self, delem, intf, profile):
intf["interfaces"][0]["nvPairs"]["QUEUING_POLICY"] = delem[profile]["queuing_policy"]
else:
intf["interfaces"][0]["nvPairs"]["QUEUING_POLICY"] = ""
if self._ndfc_version_gte("12.4.1"):
intf["interfaces"][0]["nvPairs"]["FEC"] = delem[profile].get("fec", "auto")
if delem[profile]["mode"] == "routed":
intf["interfaces"][0]["nvPairs"]["INTF_VRF"] = delem[profile][
"int_vrf"
Expand Down Expand Up @@ -3635,6 +3700,8 @@ def dcnm_intf_get_eth_payload(self, delem, intf, profile):
intf["interfaces"][0]["nvPairs"]["QUEUING_POLICY"] = delem[profile]["queuing_policy"]
else:
intf["interfaces"][0]["nvPairs"]["QUEUING_POLICY"] = ""
if self._ndfc_version_gte("12.4.1"):
intf["interfaces"][0]["nvPairs"]["FEC"] = delem[profile].get("fec", "auto")
if delem[profile]["mode"] == "monitor":
intf["interfaces"][0]["nvPairs"]["INTF_NAME"] = ifname
if delem[profile]["mode"] == "epl_routed":
Expand Down Expand Up @@ -3692,6 +3759,8 @@ def dcnm_intf_get_eth_payload(self, delem, intf, profile):
intf["interfaces"][0]["nvPairs"]["INTF_NAME"] = ifname
intf["interfaces"][0]["nvPairs"][
"PORT_DUPLEX_MODE"] = delem[profile]["duplex"]
if self._ndfc_version_gte("12.4.1"):
intf["interfaces"][0]["nvPairs"]["FEC"] = delem[profile].get("fec", "auto")

def dcnm_intf_get_st_fex_payload(self, delem, intf, profile):

Expand Down Expand Up @@ -4565,6 +4634,9 @@ def dcnm_intf_compare_want_and_have(self, state):
"QUEUING_POLICY"
]

if self._ndfc_version_gte("12.4.1"):
keys_to_check.append("FEC")

for key in keys_to_check:
# Remove the key from nv_keys only if it exists and is not present in 'have'
if key in nv_keys and d[k][index][ik].get(key, None) is None:
Expand Down
Loading