From 28517534f4e75f429df444e69075d073ac2ba368 Mon Sep 17 00:00:00 2001 From: Dmitry Lukhtionov Date: Tue, 16 Aug 2022 08:33:43 +0000 Subject: [PATCH] Merge branch 'snr_1' into 'master' Update NAG.SNR profile See merge request noc/noc!6384 (cherry picked from commit 347c3dc698e8aa3bc897e043f303883f3bf5b188) 0d584695 Update NAG.SNR profile 8f5a49fc Fix formatting ec30d781 Fix formatting 94b2c3fa Add 'NAG | SNR | CLI | FoxGate' capabilities. 4ebdeb83 Fix CLI Name. --- .../inv.capabilities/NAG/SNR/CLI_FoxGate.json | 8 + sa/profiles/NAG/SNR/get_arp.py | 29 +-- sa/profiles/NAG/SNR/get_capabilities.py | 44 ++-- sa/profiles/NAG/SNR/get_chassis_id.py | 8 +- sa/profiles/NAG/SNR/get_interfaces.py | 223 +++++++++++++----- sa/profiles/NAG/SNR/get_inventory.py | 217 ++++++++--------- sa/profiles/NAG/SNR/get_version.py | 28 ++- sa/profiles/NAG/SNR/profile.py | 6 + 8 files changed, 352 insertions(+), 211 deletions(-) create mode 100644 collections/inv.capabilities/NAG/SNR/CLI_FoxGate.json diff --git a/collections/inv.capabilities/NAG/SNR/CLI_FoxGate.json b/collections/inv.capabilities/NAG/SNR/CLI_FoxGate.json new file mode 100644 index 0000000000..461ae2f3bf --- /dev/null +++ b/collections/inv.capabilities/NAG/SNR/CLI_FoxGate.json @@ -0,0 +1,8 @@ +{ + "name": "NAG | SNR | CLI | Old", + "$collection": "inv.capabilities", + "uuid": "96cb024c-3062-415a-a2a7-d3503d7628c0", + "description": "Supported FoxGate CLI Syntax on SNR Profile", + "type": "bool", + "card_template": null +} diff --git a/sa/profiles/NAG/SNR/get_arp.py b/sa/profiles/NAG/SNR/get_arp.py index a22f467c35..6fb9f7a2d4 100644 --- a/sa/profiles/NAG/SNR/get_arp.py +++ b/sa/profiles/NAG/SNR/get_arp.py @@ -1,16 +1,15 @@ # --------------------------------------------------------------------- # NAG.SNR.get_arp # --------------------------------------------------------------------- -# Copyright (C) 2007-2019 The NOC Project +# Copyright (C) 2007-2022 The NOC Project # See LICENSE for details # --------------------------------------------------------------------- # Python modules import re -from builtins import str # NOC modules -from noc.core.script.base import BaseScript +from noc.sa.profiles.Generic.get_arp import Script as BaseScript from noc.sa.interfaces.igetarp import IGetARP @@ -20,21 +19,15 @@ class Script(BaseScript): cache = True rx_arp = re.compile(r"^(?P\d+\S+)\s+(?P\S+)\s+(?P\S+\d+)", re.MULTILINE) - - def execute_snmp(self): - r = [] - for v in self.snmp.get_tables( - ["1.3.6.1.2.1.4.22.1.1", "1.3.6.1.2.1.4.22.1.2", "1.3.6.1.2.1.4.22.1.3"], bulk=True - ): - iface = self.snmp.get("1.3.6.1.2.1.31.1.1.1.1." + str(v[1]), cached=True) # IF-MIB - mac = ":".join(["%02x" % ord(c) for c in v[2]]) - # ip = ["%02x" % ord(c) for c in v[3]] - # ip = ".".join(str(int(c, 16)) for c in ip) - r.append({"ip": v[3], "mac": mac, "interface": iface}) - return r + rx_arp2 = re.compile( + r"^(?P\d+\S+)\s+(?P\S+)\s+\d+\s+(?P\S+\d+)", re.MULTILINE + ) def execute_cli(self): - r = [] - for match in self.rx_arp.finditer(self.cli("show arp")): - r += [match.groupdict()] + if self.is_foxgate_cli: + v = self.cli("show arp all") + r = [match.groupdict() for match in self.rx_arp2.finditer(v)] + else: + v = self.cli("show arp") + r = [match.groupdict() for match in self.rx_arp.finditer(v)] return r diff --git a/sa/profiles/NAG/SNR/get_capabilities.py b/sa/profiles/NAG/SNR/get_capabilities.py index db5b76d670..3f61c12873 100644 --- a/sa/profiles/NAG/SNR/get_capabilities.py +++ b/sa/profiles/NAG/SNR/get_capabilities.py @@ -1,7 +1,7 @@ # --------------------------------------------------------------------- # NAG.SNR.get_capabilities # --------------------------------------------------------------------- -# Copyright (C) 2007-2019 The NOC Project +# Copyright (C) 2007-2022 The NOC Project # See LICENSE for details # --------------------------------------------------------------------- @@ -10,7 +10,6 @@ import re # NOC modules from noc.sa.profiles.Generic.get_capabilities import Script as BaseScript -from noc.sa.profiles.Generic.get_capabilities import false_on_cli_error class Script(BaseScript): @@ -19,23 +18,36 @@ class Script(BaseScript): rx_lldp_en = re.compile(r"LLDP has been enabled globally?") rx_stack = re.compile(r"-+member :(?P\d+)-+") - @false_on_cli_error - def has_lldp_cli(self): + def get_lldp_cli(self): """ Check box has lldp enabled on SNR """ - cmd = self.cli("show lldp", ignore_errors=True) - return self.rx_lldp_en.search(cmd) is not None + try: + cmd = self.cli("show lldp") + except self.CLISyntaxError: + # FoxGate CLI + cmd = self.cli("show lldp interface") + return "System LLDP: enable" in cmd, True + return self.rx_lldp_en.search(cmd) is not None, False - def execute_platform_cli(self, caps): + def get_stack_members(self): + s = [] try: - s = [] cmd = self.cli("show slot") - for match in self.rx_stack.finditer(cmd): - i = match.group("id") - s += [i] - if s: - caps["Stack | Members"] = len(s) if len(s) != 1 else 0 - caps["Stack | Member Ids"] = " | ".join(s) - except Exception: - pass + except self.CLISyntaxError: + return + for match in self.rx_stack.finditer(cmd): + i = match.group("id") + s += [i] + return s + + def execute_platform_cli(self, caps): + members = self.get_stack_members() + if members: + caps["Stack | Members"] = len(members) if len(members) != 1 else 0 + caps["Stack | Member Ids"] = " | ".join(members) + has_lldp, foxgate_cli = self.get_lldp_cli() + if has_lldp: + caps["Network | LLDP"] = True + if foxgate_cli: + caps["NAG | SNR | CLI | Old"] = True diff --git a/sa/profiles/NAG/SNR/get_chassis_id.py b/sa/profiles/NAG/SNR/get_chassis_id.py index 55f0796008..0bdbdd94a4 100644 --- a/sa/profiles/NAG/SNR/get_chassis_id.py +++ b/sa/profiles/NAG/SNR/get_chassis_id.py @@ -1,7 +1,7 @@ # --------------------------------------------------------------------- # NAG.SNR.get_chassis_id # --------------------------------------------------------------------- -# Copyright (C) 2007-2019 The NOC Project +# Copyright (C) 2007-2022 The NOC Project # See LICENSE for details # --------------------------------------------------------------------- @@ -20,11 +20,15 @@ class Script(BaseScript): cache = True rx_mac = re.compile(r"^\s+\S+\s+mac\s+(\S+)\s*\n", re.MULTILINE | re.IGNORECASE) + rx_mac2 = re.compile(r"^MAC address\s+: (?P\S+)", re.MULTILINE) SNMP_GET_OIDS = {"SNMP": [mib["IF-MIB::ifPhysAddress", 1]]} def execute_cli(self): - macs = sorted(self.rx_mac.findall(self.cli("show version", cached=True))) + if self.is_foxgate_cli: + macs = sorted(self.rx_mac2.findall(self.cli("show ip", cached=True))) + else: + macs = sorted(self.rx_mac.findall(self.cli("show version", cached=True))) return [ {"first_chassis_mac": f, "last_chassis_mac": t} for f, t in self.macs_to_ranges(macs) ] diff --git a/sa/profiles/NAG/SNR/get_interfaces.py b/sa/profiles/NAG/SNR/get_interfaces.py index c05e47a282..57117cc957 100644 --- a/sa/profiles/NAG/SNR/get_interfaces.py +++ b/sa/profiles/NAG/SNR/get_interfaces.py @@ -1,12 +1,14 @@ # --------------------------------------------------------------------- # NAG.SNR.get_interfaces # --------------------------------------------------------------------- -# Copyright (C) 2007-2021 The NOC Project +# Copyright (C) 2007-2022 The NOC Project # See LICENSE for details # --------------------------------------------------------------------- # Python modules import re +from typing import Set, Dict, Any +from collections import defaultdict # NOC modules from noc.core.script.base import BaseScript @@ -29,6 +31,24 @@ class Script(BaseScript): r"(?:^\s+Encapsulation |^\s+Output packets statistics:)", re.MULTILINE, ) + rx_sh_int_old = re.compile( + r"^\s+(?:Fast|Gigabit) Ethernet (?P\S+) current state: (?P\S+), port link is (?P\S+)\s*\n" + r"(?:^\s+Port type status : .+\n)?" + r"(?:^\s+Time duration of linkup is .+\n)?" + r"^\s+Hardware address is (?P\S+)\s*\n" + r"^\s+SetSpeed is .+\n" + r"^\s+Current port type: .+\n" + r"(?:^\s+Transceiver is .+\n)?" + r"(?:^\s+Transceiver Compliance: .+\n)?" + r"^\s+Priority is \d+\s*\n" + r"^\s+Flow control is .+\n" + r"^\s+Broadcast storm control target rate is .+\n" + r"^\s+PVID is (?P\d+)\s*\n" + r"^\s+Port mode: (?Ptrunk|access)\s*\n" + r"(?:^\s+Untagged\s+VLAN ID: (?P\d+)\s*\n)?" + r"(?:^\s+Vlan\s+allowed: (?P\S+)\s*\n)?", + re.MULTILINE, + ) rx_hw = re.compile( r"^\s+Hardware is (?P\S+)(\(card not installed\))?(, active is \S+)?" r"(,\s+address is (?P\S+))?\s*\n", @@ -50,91 +70,174 @@ class Script(BaseScript): r"(^Trunk allowed Vlan\s*:\s*(?P\S+)\s*\n)?", re.MULTILINE, ) + rx_mgmt = re.compile( + r"^ip address\s+: (?P\S+)\s*\n" + r"^netmask\s+: (?P\S+)\s*\n" + r"^gateway\s+: .+\n" + r"^ManageVLAN\s+: (?P\d+)\s*\n" + r"^MAC address\s+: (?P\S+)", + re.MULTILINE, + ) rx_lag_port = re.compile(r"\s*\S+ is LAG member port, LAG port:(?P\S+)\n") - def execute_cli(self): - interfaces = [] - # Get LLDP interfaces - lldp = [] + def get_switchport_cli(self) -> Dict[str, Dict[str, Any]]: + if self.is_foxgate_cli: + return {} + # New CLI syntax + result = defaultdict(lambda: {"untagged": None, "tagged": []}) + v = self.cli("show switchport interface") + for match in self.rx_vlan.finditer(v): + ifname = match.group("ifname") + result[ifname]["untagged"] = match.group("untagged_vlan") + if match.group("tagged_vlans"): + tagged_vlans = match.group("tagged_vlans").replace(";", ",") + result[ifname]["tagged"] = self.expand_rangelist(tagged_vlans) + return result + + def get_interface_lldp(self) -> Set[str]: + lldp = set() + if self.is_foxgate_cli: + return lldp c = self.cli("show lldp", ignore_errors=True) if self.rx_lldp_en.search(c): ll = self.rx_lldp.search(c) if ll: - lldp = ll.group("local_if").split() + lldp = set(ll.group("local_if").split()) + return lldp + + def get_interfaces_foxgatecli(self): + """ + For FoxGate Like CLI syntax + :return: + """ + v = self.cli("show interface", cached=True) + interfaces = {} + for match in self.rx_sh_int_old.finditer(v): + ifname = match.group("interface") + sub = { + "name": match.group("interface"), + "admin_status": match.group("admin_status") == "enabled", + "oper_status": match.group("oper_status") == "up", + "mac": match.group("mac"), + "enabled_afi": ["BRIDGE"], + } + if match.group("mode") == "access": + sub["untagged_vlan"] = match.group("untagged") + else: + sub["untagged_vlan"] = match.group("pvid") + sub["tagged_vlans"] = self.expand_rangelist(match.group("tagged")) + interfaces[ifname] = { + "name": ifname, + "type": "physical", + "admin_status": match.group("admin_status") == "enabled", + "oper_status": match.group("oper_status") == "up", + "mac": match.group("mac"), + "subinterfaces": [sub], + } + + v = self.cli("show ip", cached=True) + match = self.rx_mgmt.search(v) + ip_address = f'{match.group("ip")}/{IPv4.netmask_to_len(match.group("mask"))}' + interfaces["system"] = { + "name": "system", + "type": "SVI", + "admin_status": True, + "oper_status": True, + "mac": match.group("mac"), + "subinterfaces": [ + { + "name": "system", + "admin_status": True, + "oper_status": True, + "mac": match.group("mac"), + "enabled_afi": ["IPv4"], + "ipv4_addresses": [ip_address], + "vlan_ids": match.group("vlan_id"), + } + ], + } + return [{"interfaces": list(interfaces.values())}] + + def execute_cli(self, **kwargs): + interfaces = {} + if self.is_foxgate_cli: + return self.get_interfaces_foxgatecli() + # Get LLDP enabled interfaces + lldp = self.get_interface_lldp() + # Get switchports and fill tagged/untagged lists if they are not empty + switchports = self.get_switchport_cli() v = self.cli("show interface", cached=True) for match in self.rx_sh_int.finditer(v): - name = match.group("interface") + ifname = match.group("interface") a_stat = match.group("admin_status").lower() == "up" o_stat = match.group("oper_status").lower() == "up" + sub = { + "name": ifname, + "admin_status": a_stat, + "oper_status": o_stat, + "enabled_protocols": [], + "enabled_afi": [], + } + # Switchport + if ifname in switchports: + # Bridge + sub["enabled_afi"] += ["BRIDGE"] + u, t = switchports[ifname]["untagged"], switchports[ifname].get("tagged") + if u: + sub["untagged_vlan"] = u + if t: + sub["tagged_vlans"] = t + # Other other = match.group("other") - match1 = self.rx_hw.search(other) + # MTU + match1 = self.rx_mtu.search(other) + if match1: + sub["mtu"] = match1.group("mtu") + # PVID + match1 = self.rx_pvid.search(other) + if match1: + sub["untagged_vlan"] = match1.group("pvid") + if ifname.startswith("Vlan"): + sub["vlan_ids"] = [int(ifname[4:])] + # IP Address + match1 = self.rx_ip.search(other) + if match1 and "NULL" not in match1.group("ip"): + ip_address = f'{match1.group("ip")}/{IPv4.netmask_to_len(match1.group("mask"))}' + sub["ipv4_addresses"] = [ip_address] + sub["enabled_afi"] = ["IPv4"] iface = { - "type": self.profile.get_interface_type(name), - "name": name, + "name": ifname, "admin_status": a_stat, "oper_status": o_stat, + "type": self.profile.get_interface_type(ifname), + "enabled_protocols": [], + "subinterfaces": [sub], } - sub = {"name": name, "admin_status": a_stat, "oper_status": o_stat} - # LLDP protocol - if name in lldp: - iface["enabled_protocols"] = ["LLDP"] - if iface["type"] == "physical": - sub["enabled_afi"] = ["BRIDGE"] + # MAC + match1 = self.rx_hw.search(other) if match1.group("mac"): iface["mac"] = match1.group("mac") sub["mac"] = match1.group("mac") + # Description match1 = self.rx_alias.search(other) if match1 and match1.group("alias") != "(null),": iface["description"] = match1.group("alias") sub["description"] = match1.group("alias") + # Ifindex match1 = self.rx_index.search(other) if match1: iface["snmp_ifindex"] = match1.group("ifindex") sub["snmp_ifindex"] = match1.group("ifindex") - else: - if match.group("snmp_ifindex"): - iface["snmp_ifindex"] = match.group("snmp_ifindex") - sub["snmp_ifindex"] = match.group("snmp_ifindex") - # Correct alias and index on some device - match1 = self.rx_alias_and_index.search(other) - if match1: - if match1.group("alias") != "(null)": - iface["description"] = match1.group("alias") - sub["description"] = match1.group("alias") - iface["snmp_ifindex"] = match1.group("ifindex") - sub["snmp_ifindex"] = match1.group("ifindex") - match1 = self.rx_mtu.search(other) - if match1: - sub["mtu"] = match1.group("mtu") - match1 = self.rx_pvid.search(other) - if match1: - sub["untagged_vlan"] = match1.group("pvid") - if name.startswith("Vlan"): - sub["vlan_ids"] = [int(name[4:])] + elif match.group("snmp_ifindex"): + iface["snmp_ifindex"] = match.group("snmp_ifindex") + sub["snmp_ifindex"] = match.group("snmp_ifindex") + # LAG match1 = self.rx_lag_port.search(other) if match1: iface["aggregated_interface"] = match1.group("lag_port") - match1 = self.rx_ip.search(other) - if match1: - if "NULL" in match1.group("ip"): - continue - ip_address = "%s/%s" % ( - match1.group("ip"), - IPv4.netmask_to_len(match1.group("mask")), - ) - sub["ipv4_addresses"] = [ip_address] - sub["enabled_afi"] = ["IPv4"] - iface["subinterfaces"] = [sub] - interfaces += [iface] - v = self.cli("show switchport interface") - for match in self.rx_vlan.finditer(v): - ifname = match.group("ifname") - untagged_vlan = match.group("untagged_vlan") - for i in interfaces: - if ifname == i["name"]: - i["subinterfaces"][0]["untagged_vlan"] = untagged_vlan - if match.group("tagged_vlans"): - tagged_vlans = match.group("tagged_vlans").replace(";", ",") - i["subinterfaces"][0]["tagged_vlans"] = self.expand_rangelist(tagged_vlans) - break - return [{"interfaces": interfaces}] + # LLDP protocol + if ifname in lldp: + iface["enabled_protocols"] = ["LLDP"] + interfaces[ifname] = iface + + return [{"interfaces": list(interfaces.values())}] diff --git a/sa/profiles/NAG/SNR/get_inventory.py b/sa/profiles/NAG/SNR/get_inventory.py index 23db62721b..a683775fe2 100644 --- a/sa/profiles/NAG/SNR/get_inventory.py +++ b/sa/profiles/NAG/SNR/get_inventory.py @@ -1,7 +1,7 @@ # --------------------------------------------------------------------- # NAG.SNR.get_inventory # --------------------------------------------------------------------- -# Copyright (C) 2007-2019 The NOC Project +# Copyright (C) 2007-2022 The NOC Project # See LICENSE for details # --------------------------------------------------------------------- @@ -50,134 +50,135 @@ class Script(BaseScript): "Dec": "12", } - def execute(self): + def execute_cli(self, **kwargs): r = [] s = self.scripts.get_version() revision = s["attributes"]["HW version"] serial = s["attributes"]["Serial Number"] part_no = s["platform"] - slot = self.cli("show slot") - slot_id = 0 - if "Invalid" in slot: - p = { - "type": "CHASSIS", - "vendor": "NAG", - "part_no": part_no, - "revision": revision, - "serial": serial, - "description": "", - } - r += [p] + vendor = s["vendor"] + if self.is_foxgate_cli: + r += [ + { + "type": "CHASSIS", + "vendor": vendor, + "part_no": part_no, + "revision": revision, + "serial": serial, + "description": "", + } + ] r += self.get_transceivers(1) - else: - for match in self.rx_stack.finditer(slot): - mfg_date = match.group("mfg_date") - date = mfg_date.replace("/", "-") - slot_id += 1 - sl = { + return r + try: + slot = self.cli("show slot") + except self.CLISyntaxError: + slot = "Invalid" + for slot_id, match in enumerate(self.rx_stack.finditer(slot), start=1): + mfg_date = match.group("mfg_date") + date = mfg_date.replace("/", "-") + r += [ + { "type": "CHASSIS", "number": slot_id, - "vendor": "NAG", + "vendor": vendor, "mfg_date": date, "part_no": part_no, "revision": match.group("hardware"), "serial": match.group("serial"), "description": "", } - r += [sl] - r += self.get_transceivers(slot_id) + ] + r += self.get_transceivers(slot_id) return r def get_transceivers(self, slot_id): out = [] try: c = self.cli("show transceiver detail", cached=True) - for match in self.rx_media_type.finditer(c): - description = match.group("part_no") - mbd = int(match.group("mbd")) - nm = match.group("nm") - ch_id = int(match.group("ch_id")) - if ch_id == slot_id: - if not nm: - nm = 0 + except self.CLISyntaxError: + return out + for match in self.rx_media_type.finditer(c): + description = match.group("part_no") + mbd = int(match.group("mbd")) + nm = match.group("nm") + ch_id = int(match.group("ch_id")) + if ch_id == slot_id: + nm = nm or 0 + nm = int(nm) + vendor = "NONAME" + part_no = "NoName | Transceiver | " + if mbd == 1300 and nm == 1310: + part_no = part_no + "1G | SFP BXU" + elif mbd == 1300 and nm == 1550: + part_no = part_no + "1G | SFP BXD" + elif mbd == 1200 and nm == 1310: + part_no = part_no + "1G | SFP BX10U" + elif mbd >= 1200 and nm == 1490: + part_no = part_no + "1G | SFP BX10D" + elif mbd == 10300 and nm == 0 and description.startswith("unkn"): + part_no = part_no + "10G | SFP+ Twinax" + elif mbd == 10300 and description.startswith("10G"): + if description.endswith(tuple([" ER", "-ER"])): + part_no = part_no + "10G | SFP+ ER" + elif description.endswith(tuple([" LR", "-LR"])): + part_no = part_no + "10G | SFP+ LR" + elif description.endswith(tuple([" SR", "-SR"])): + part_no = part_no + "10G | SFP+ SR" + elif description.endswith(tuple([" ZR", "-ZR"])): + part_no = part_no + "10G | SFP+ ZR" else: - nm = int(nm) - vendor = "NONAME" - part_no = "NoName | Transceiver | " - if mbd == 1300 and nm == 1310: - part_no = part_no + "1G | SFP BXU" - elif mbd == 1300 and nm == 1550: - part_no = part_no + "1G | SFP BXD" - elif mbd == 1200 and nm == 1310: - part_no = part_no + "1G | SFP BX10U" - elif mbd >= 1200 and nm == 1490: - part_no = part_no + "1G | SFP BX10D" - elif mbd == 10300 and nm == 0 and description.startswith("unkn"): - part_no = part_no + "10G | SFP+ Twinax" - elif mbd == 10300 and description.startswith("10G"): - if description.endswith(tuple([" ER", "-ER"])): - part_no = part_no + "10G | SFP+ ER" - elif description.endswith(tuple([" LR", "-LR"])): - part_no = part_no + "10G | SFP+ LR" - elif description.endswith(tuple([" SR", "-SR"])): - part_no = part_no + "10G | SFP+ SR" - elif description.endswith(tuple([" ZR", "-ZR"])): - part_no = part_no + "10G | SFP+ ZR" - else: - part_no = part_no + "10G | SFP+" - elif mbd == 12000 and nm == 0: - part_no = part_no + "10G | SFP+ Twinax" - elif mbd >= 1000 and mbd <= 1300 and nm == 0: - if description.endswith(tuple([" EX", "-EX"])): - part_no = part_no + "1G | SFP EX" - elif description.endswith(tuple([" LH", "-LH"])): - part_no = part_no + "1G | SFP LH" - elif description.endswith(tuple([" LX", "-LX"])): - part_no = part_no + "1G | SFP LX" - elif description.endswith(tuple([" SX", "-SX"])): - part_no = part_no + "1G | SFP SX" - elif description.endswith(tuple([" T", "-T"])): - part_no = part_no + "1G | SFP T" - elif description.endswith(tuple([" TX", "-TX"])): - part_no = part_no + "1G | SFP TX" - elif description.endswith(tuple([" ZX", "-ZX"])): - part_no = part_no + "1G | SFP ZX" - else: - part_no = part_no + "1G | SFP" - elif mbd == 100 and nm == 1310: - part_no = part_no + "100M | SFP BX100U" - elif mbd == 100 and nm == 1550: - part_no = part_no + "100M | SFP BX100D" - elif description.startswith("40G"): - part_no = part_no + "40G | QSFP+" + part_no = part_no + "10G | SFP+" + elif mbd == 12000 and nm == 0: + part_no = part_no + "10G | SFP+ Twinax" + elif mbd >= 1000 and mbd <= 1300 and nm == 0: + if description.endswith(tuple([" EX", "-EX"])): + part_no = part_no + "1G | SFP EX" + elif description.endswith(tuple([" LH", "-LH"])): + part_no = part_no + "1G | SFP LH" + elif description.endswith(tuple([" LX", "-LX"])): + part_no = part_no + "1G | SFP LX" + elif description.endswith(tuple([" SX", "-SX"])): + part_no = part_no + "1G | SFP SX" + elif description.endswith(tuple([" T", "-T"])): + part_no = part_no + "1G | SFP T" + elif description.endswith(tuple([" TX", "-TX"])): + part_no = part_no + "1G | SFP TX" + elif description.endswith(tuple([" ZX", "-ZX"])): + part_no = part_no + "1G | SFP ZX" else: - part_no = part_no + "Unknown SFP" - - mf_m = match.group("mf_m") - if mf_m == "(null)": - i = { - "type": "XCVR", - "number": "Ethernet1/" + match.group("port"), - "vendor": vendor, - "part_no": part_no, - "serial": match.group("serial"), - "description": "%s, %dMbd, %dnm" % (description, mbd, nm), - } - else: - mf_mon = self.month.get(mf_m) - mf_parts = [match.group("mf_y"), mf_mon, match.group("mf_d")] - mf_date = "-".join(mf_parts) - i = { - "type": "XCVR", - "number": "Ethernet1/" + match.group("port"), - "vendor": vendor, - "part_no": part_no, - "mfg_date": mf_date, - "serial": match.group("serial"), - "description": "%s, %dMbd, %dnm" % (description, mbd, nm), - } - out += [i] - except self.CLISyntaxError: - pass + part_no = part_no + "1G | SFP" + elif mbd == 100 and nm == 1310: + part_no = part_no + "100M | SFP BX100U" + elif mbd == 100 and nm == 1550: + part_no = part_no + "100M | SFP BX100D" + elif description.startswith("40G"): + part_no = part_no + "40G | QSFP+" + else: + part_no = part_no + "Unknown SFP" + mf_m = match.group("mf_m") + if mf_m == "(null)": + i = { + "type": "XCVR", + "number": "Ethernet1/" + match.group("port"), + "vendor": vendor, + "part_no": part_no, + "serial": match.group("serial"), + "description": "%s, %dMbd, %dnm" % (description, mbd, nm), + } + else: + mf_mon = self.month.get(mf_m) + mf_parts = [match.group("mf_y"), mf_mon, match.group("mf_d")] + mf_date = "-".join(mf_parts) + i = { + "type": "XCVR", + "number": "Ethernet1/" + match.group("port"), + "vendor": vendor, + "part_no": part_no, + "mfg_date": mf_date, + "serial": match.group("serial"), + "description": "%s, %dMbd, %dnm" % (description, mbd, nm), + } + out += [i] return out diff --git a/sa/profiles/NAG/SNR/get_version.py b/sa/profiles/NAG/SNR/get_version.py index b175fcf346..4378e6f61a 100644 --- a/sa/profiles/NAG/SNR/get_version.py +++ b/sa/profiles/NAG/SNR/get_version.py @@ -1,7 +1,7 @@ # --------------------------------------------------------------------- # NAG.SNR.get_version # --------------------------------------------------------------------- -# Copyright (C) 2007-2020 The NOC Project +# Copyright (C) 2007-2022 The NOC Project # See LICENSE for details # --------------------------------------------------------------------- @@ -20,13 +20,13 @@ class Script(BaseScript): cache = True rx_ver = re.compile( - r"^\s+(?P\S+) Device, Compiled on.*\n" + r"^\s+(?:(?PFoxGate) )?(?P\S+) Device, Compiled on.*\n" r"(^\s+sysLocation.*\n)?" r"(^\s+CPU Mac \S+\s*\n)?" r"(^\s+Vlan MAC \S+\s*\n)?" - r"^\s+SoftWare(?: Package)? Version (?P\S+)\s*\n" + r"^\s+Soft[Ww]are(?: Package)? Version (?P\S+)\s*\n" r"^\s+BootRom Version (?P\S+)\s*\n" - r"^\s+HardWare Version (?P\S+)\s*\n" + r"^\s+Hard[Ww]are Version (?P\S+)\s*\n" r"^\s+CPLD Version.*\n" r"^\s+(?:Serial No.:|Device serial number)\s*(?P\S+)\s*\n", re.MULTILINE, @@ -39,12 +39,14 @@ class Script(BaseScript): r"^\s+(?:Serial No.:|Device serial number)\s*(?P\S+)\s*\n", re.MULTILINE, ) + rx_ver_snmp2 = re.compile(r"^(?PFoxGate) (?P\S+)$", re.MULTILINE) def execute_snmp(self): - match = self.rx_ver_snmp.search(self.snmp.get(mib["SNMPv2-MIB::sysDescr.0"], cached=True)) + v = self.snmp.get(mib["SNMPv2-MIB::sysDescr", 0], cached=True) + match = self.rx_ver_snmp.search(v) if match: return { - "vendor": "NAG", + "vendor": "NAG", # Need more examples for other vendors "platform": match.group("platform"), "version": match.group("version"), "attributes": { @@ -53,6 +55,15 @@ class Script(BaseScript): "Serial Number": match.group("serial"), }, } + else: + match = self.rx_ver_snmp.search(v) + if match: + # Device do not support .1.3.6.1.2.1.47.x SNMP table + return { + "vendor": "FoxGate", + "platform": match.group("platform"), + "version": "unknown", # I do not know right OID + } vendor = self.snmp.get("1.3.6.1.2.1.47.1.1.1.1.12.1", cached=True) platform = self.snmp.get(mib["SNMPv2-MIB::sysDescr.0"], cached=True) platform = platform.split(" ")[0] @@ -72,8 +83,11 @@ class Script(BaseScript): match = self.rx_ver.search(v) if not match: match = self.rx_ver_snmp.search(v) + vendor = "NAG" + if match.group("vendor"): + vendor = "FoxGate" return { - "vendor": "NAG", + "vendor": vendor, "platform": match.group("platform"), "version": match.group("version"), "attributes": { diff --git a/sa/profiles/NAG/SNR/profile.py b/sa/profiles/NAG/SNR/profile.py index 1f12c9e880..b840c3fe9e 100644 --- a/sa/profiles/NAG/SNR/profile.py +++ b/sa/profiles/NAG/SNR/profile.py @@ -18,7 +18,9 @@ class Profile(BaseProfile): pattern_more = [ (rb"^ --More-- ", b"\n"), (rb"^Confirm to overwrite current startup-config configuration \[Y/N\]:", b"y\n"), + (rb"^\.\.\.\.press ENTER to next line, Q to quit, other key to next page\.\.\.\.", b" "), ] + pattern_syntax_error = rb"% (?:Unrecognized|Incomplete) command, and error detected at" username_submit = b"\r" password_submit = b"\r" command_submit = b"\r" @@ -27,6 +29,7 @@ class Profile(BaseProfile): command_exit = "exit" config_tokenizer = "indent" config_tokenizer_settings = {"line_comment": "!"} + matchers = {"is_foxgate_cli": {"caps": {"$in": ["NAG | SNR | CLI | Old"]}}} rx_pager = re.compile(r"0 for no pausing") @@ -44,6 +47,7 @@ class Profile(BaseProfile): INTERFACE_TYPES = { "Ethe": "physical", # Ethernet "Vlan": "SVI", # Vlan + "syst": "SVI", # system "Port": "aggregated", # Port-Channel "Vsf-": "aggregated", # Vsf-Port "vpls": "unknown", # vpls_dev @@ -54,4 +58,6 @@ class Profile(BaseProfile): def get_interface_type(cls, name): if name == "Ethernet0": return "management" + if name.startswith("e0/"): + return "physical" return cls.INTERFACE_TYPES.get(name[:4]) -- GitLab