From a181dd04fcbcb038ed5265ee6b4a6d70439ce790 Mon Sep 17 00:00:00 2001 From: Andrey Vertiprahov Date: Fri, 9 Aug 2019 21:04:17 +0500 Subject: [PATCH 1/4] Delete include from command in Qtech.QSW2800 profiles. --- sa/profiles/Qtech/QSW2800/get_chassis_id.py | 2 +- sa/profiles/Qtech/QSW2800/get_interfaces.py | 97 +++++++++++++-------- sa/profiles/Qtech/QSW2800/get_version.py | 82 +++++++---------- 3 files changed, 90 insertions(+), 91 deletions(-) diff --git a/sa/profiles/Qtech/QSW2800/get_chassis_id.py b/sa/profiles/Qtech/QSW2800/get_chassis_id.py index 70fe97765b..4688e6fb15 100644 --- a/sa/profiles/Qtech/QSW2800/get_chassis_id.py +++ b/sa/profiles/Qtech/QSW2800/get_chassis_id.py @@ -26,7 +26,7 @@ class Script(BaseScript): def execute_cli(self): macs = [] if self.is_support_mac_version: - cmd = self.cli("show version") + cmd = self.cli("show version", cached=True) for match in self.rx_mac.finditer(cmd): macs += [match.group("mac")] if not macs: diff --git a/sa/profiles/Qtech/QSW2800/get_interfaces.py b/sa/profiles/Qtech/QSW2800/get_interfaces.py index 987f9d8b8b..36675519f5 100644 --- a/sa/profiles/Qtech/QSW2800/get_interfaces.py +++ b/sa/profiles/Qtech/QSW2800/get_interfaces.py @@ -30,6 +30,16 @@ class Script(BaseScript): r"^\s*(?P\S+) is (?P\S*\s*\S+), " r"line protocol is (?P\S+)" ) + rx_switchport = re.compile( + r"(?P\S+\d+(/\d+)?)\n" + r"Type :(?PUniversal|" + r"Aggregation(?: member)?)\n" + r"(?:Mac addr num: No limit\n)?" + r"Mode :\S+\s*\nPort VID :(?P\d+)\n" + r"((?:Hybrid tag|Trunk) allowed Vlan:" + r"\s+(?P\S+))?", + re.MULTILINE, + ) rx_description = re.compile(r"alias name is (?P[A-Za-z0-9\-_/\.\s\(\)]*)") rx_ifindex = re.compile(r"index is (?P\d+)$") rx_ipv4 = re.compile(r"^\s+(?P[\d+\.]+)\s+(?P[\d+\.]+)\s+") @@ -37,6 +47,9 @@ class Script(BaseScript): rx_mtu = re.compile(r"^\s+MTU(?: is)? (?P\d+) bytes") rx_oam = re.compile(r"Doesn\'t (support efmoam|enable EFMOAM!)") rx_vid = re.compile(r"(?P\d+)") + rx_interface_lag = re.compile( + r"^\s+(?P\S+) is LAG member port, " r"LAG port:(?P\S+)", re.MULTILINE + ) MAX_REPETITIONS = 10 MAX_GETNEXT_RETIRES = 1 @@ -48,25 +61,48 @@ class Script(BaseScript): r = l.split(":")[1].split() return r + def get_interface_oam(self, ifname): + try: + v = self.cli("show ethernet-oam local interface %s" % ifname) + match = self.rx_oam.search(v) + if not match: + return True + except self.CLISyntaxError: + pass + + def get_port_vlans(self): + r = {} + # @todo 'show vlan' parser + # @todo add QinQ translation parser + v = self.cli("show switchport interface") + for match in self.rx_switchport.finditer(v): + ifname = match.group("interface") + pvid = int(match.group("pvid")) + # initial data + r[ifname] = { + "interface": ifname, + "tagged": [], + "untagged": pvid, + "802.1ad Tunnel": False, + } + if match.group("tags"): + ma_group = match.group("tags").replace(";", ",") + if "showOneSwitchPort" in ma_group: + continue + for tag in self.expand_rangelist(ma_group): + if tag != pvid: + r[ifname]["tagged"] += [tag] + return r + def execute_cli(self): # get switchports - swports = {} - for sp in self.scripts.get_switchport(): - swports[sp["interface"]] = (sp["untagged"] if "untagged" in sp else None, sp["tagged"]) - - # get portchannels - pc_members = {} - for pc in self.scripts.get_portchannel(): - i = pc["interface"] - t = pc["type"] == "L" - for m in pc["members"]: - pc_members[m] = (i, t) + swports = self.get_port_vlans() # Get LLDP port lldp = self.get_lldp() # process all interfaces and form result r = [] - cmd = self.cli("show interface") + cmd = self.cli("show interface", cached=True) for l in cmd.splitlines(): # find interface name match = self.rx_interface.match(l) @@ -80,35 +116,14 @@ class Script(BaseScript): "enabled_protocols": [], "subinterfaces": [], } - # detect interface type - if ifname.startswith("Eth"): - iface["type"] = "physical" - elif ifname.startswith("Po") or ifname.startswith("Vsf"): - iface["type"] = "aggregated" - elif ifname.startswith("Vlan"): - iface["type"] = "SVI" - elif ifname.startswith("l2over"): - iface["type"] = "tunnel" - elif ifname.startswith("Loop"): - iface["type"] = "loopback" - elif ifname.startswith("vpls_dev"): - iface["type"] = "other" + iftype = self.profile.get_interface_type(ifname) + iface["type"] = iftype # proccess LLDP if ifname in lldp: iface["enabled_protocols"] += ["LLDP"] - # process portchannels' members - if ifname in pc_members: - iface["aggregated_interface"] = pc_members[ifname][0] - if pc_members[ifname][1]: - iface["enabled_protocols"] += ["LACP"] if ifname.startswith("Ethernet"): - try: - v = self.cli("show ethernet-oam local interface %s" % ifname) - match = self.rx_oam.search(v) - if not match: - iface["enabled_protocols"] += ["OAM"] - except self.CLISyntaxError: - pass + if self.get_interface_oam(ifname): + iface["enabled_protocols"] += ["OAM"] # process subinterfaces if "aggregated_interface" not in iface: sub = { @@ -119,7 +134,7 @@ class Script(BaseScript): } # process switchports if ifname in swports: - u, t = swports[ifname] + u, t = swports[ifname]["untagged"], swports[ifname]["tagged"] if u: sub["untagged_vlan"] = u if t: @@ -127,6 +142,12 @@ class Script(BaseScript): sub["enabled_afi"] += ["BRIDGE"] else: sub = {} + match = self.rx_interface_lag.search(l) + if match: + iface["aggregated_interface"] = self.profile.convert_interface_name( + match.group("pc") + ) + iface["enabled_protocols"] += ["LACP"] # get snmp ifindex match = self.rx_ifindex.search(l) if match: diff --git a/sa/profiles/Qtech/QSW2800/get_version.py b/sa/profiles/Qtech/QSW2800/get_version.py index fd02387231..f4df707cdf 100644 --- a/sa/profiles/Qtech/QSW2800/get_version.py +++ b/sa/profiles/Qtech/QSW2800/get_version.py @@ -26,7 +26,7 @@ class Script(BaseScript): r"^\s*SoftWare(?: Package)? Version\s+(?P\S+(?:\(\S+\))?)\n" r"^\s*BootRom Version\s+(?P\S+)\n" r"^\s*HardWare Version\s+(?P\S+).+" - r"^\s*(?:Device serial number |Serial No.:(?:|\s))(?P\S+)\n", + r"^\s*(?:Device serial number |Serial No.:(?:|\s+))(?P\S+)\n", re.MULTILINE | re.DOTALL, ) @@ -38,6 +38,11 @@ class Script(BaseScript): re.MULTILINE | re.DOTALL, ) + rx_ver3 = re.compile( + r"(?P\S+),\s*(?P.+)," + r"\s*(?P\S+),\s+Linux (?P\S+)" + ) + rx_vendor = re.compile(r"^DeviceOid\s+\d+\s+(?P\S+)", re.MULTILINE) rx_version = re.compile(r"Software, Version (?P\S+),") @@ -51,7 +56,7 @@ class Script(BaseScript): "1.3.6.1.4.1.6339.1.1.2.59": "QSW-8200-28F-AC-DC", "1.3.6.1.4.1.13464.1.3.13": "QSW-2900-24T", "1.3.6.1.4.1.13464.1.3.26.7": "QSW-2910", - "1.3.6.1.4.1.27514": "QSW-8200–28F-AC-DC rev.Q1", + "1.3.6.1.4.1.27514": "QSW-8200–28F-AC-DC rev.Q1", # Bad lifehack "1.3.6.1.4.1.27514.1.1.1.39": "QSW-2800-26T-AC", "1.3.6.1.4.1.27514.1.1.1.48": "QSW-2800-10T-AC", "1.3.6.1.4.1.27514.1.1.1.49": "QSW-2800-28T-AC", @@ -96,6 +101,7 @@ class Script(BaseScript): def fix_platform(self, oid): if oid.startswith("."): oid = oid[1:] + # self.snmp.get(mib[".1.3.6.1.4.1.27514.1.1.1.1.1.1", 0], cached=True) platform = self.qtech_platforms.get(oid) if platform is None: self.logger.info("Unknown platform OID: %s" % oid) @@ -103,55 +109,28 @@ class Script(BaseScript): return platform def execute_snmp(self, **kwargs): - try: - ver = self.snmp.get(mib["SNMPv2-MIB::sysDescr.0"], cached=True) - match = self.rx_ver.search(ver) - match2 = self.rx_ver2.search(ver) + r = {"vendor": "Qtech", "attributes": {}} + sys_descr = self.snmp.get(mib["SNMPv2-MIB::sysDescr.0"], cached=True) + for ree in [self.rx_ver, self.rx_ver2, self.rx_ver3]: + match = ree.match(sys_descr) if match: - platform = match.group("platform").strip(" ,") - version = match.group("version") - bootprom = match.group("bootprom") - hardware = match.group("hardware") - serial = match.group("serial") - if platform == "Switch": - oid = self.snmp.get(mib["SNMPv2-MIB::sysObjectID.0"]) - platform = self.fix_platform(oid) - - return { - "vendor": "Qtech", - "platform": platform, - "version": version, - "attributes": { - "Boot PROM": bootprom, - "HW version": hardware, - "Serial Number": serial, - }, - } - elif match2: - version = match2.group("version") - bootprom = match2.group("bootprom") - hardware = match2.group("hardware") - serial = match2.group("serial") - oid = self.snmp.get(mib["SNMPv2-MIB::sysObjectID.0"]) - platform = self.fix_platform(oid) - return { - "vendor": "Qtech", - "platform": platform, - "version": version, - "attributes": { - "Boot PROM": bootprom, - "HW version": hardware, - "Serial Number": serial, - }, - } - else: - oid = self.snmp.get(mib["SNMPv2-MIB::sysObjectID.0"]) - platform = self.fix_platform(oid) - match = self.rx_version.search(ver) - version = match.group("version") - return {"vendor": "Qtech", "platform": platform, "version": version} - except self.snmp.TimeOutError: - raise self.NotSupportedError + match = match.groupdict() + if "platform" in match: + r["platform"] = match["platform"] + r["version"] = match["version"] + break + if not match or "platform" not in match or match["platform"] == "Switch": + oid = self.snmp.get(mib["SNMPv2-MIB::sysObjectID.0"]) + r["platform"] = self.fix_platform(oid) + if "version" not in r: + r["version"] = self.rx_version.search(sys_descr).group("version") + if "bootprom" in match: + r["attributes"]["Boot PROM"] = match["bootprom"] + if "hardware" in match: + r["attributes"]["HW version"] = match["hardware"] + if "serial" in match: + r["attributes"]["Serial Number"] = match["serial"] + return r def execute_cli(self, **kwargs): ver = self.cli("show version", cached=True) @@ -171,7 +150,6 @@ class Script(BaseScript): platform = self.fix_platform(match.group("oid")) except self.CLISyntaxError: pass - return { "vendor": "Qtech", "platform": platform, @@ -183,4 +161,4 @@ class Script(BaseScript): }, } else: - return {"vendor": "Qtech", "platform": "Unknown", "version": "Unknown"} + raise NotImplementedError("Unknown platform") -- GitLab From 75c11b4844e57b1b9905a237096b6f1a38947a1b Mon Sep 17 00:00:00 2001 From: Andrey Vertiprahov Date: Thu, 22 Aug 2019 09:47:12 +0500 Subject: [PATCH 2/4] Fix Qtech.QSW2800.get_version for unknown serial. --- sa/profiles/Qtech/QSW2800/get_version.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sa/profiles/Qtech/QSW2800/get_version.py b/sa/profiles/Qtech/QSW2800/get_version.py index f4df707cdf..372def9ea3 100644 --- a/sa/profiles/Qtech/QSW2800/get_version.py +++ b/sa/profiles/Qtech/QSW2800/get_version.py @@ -26,7 +26,8 @@ class Script(BaseScript): r"^\s*SoftWare(?: Package)? Version\s+(?P\S+(?:\(\S+\))?)\n" r"^\s*BootRom Version\s+(?P\S+)\n" r"^\s*HardWare Version\s+(?P\S+).+" - r"^\s*(?:Device serial number |Serial No.:(?:|\s+))(?P\S+)\n", + r"^\s*(?:Device serial number |Serial No.:(?:|\s+))(?P\S+|\S+pn sw)\n", + # pn sw on serial - QSW-3500-10T-AC, 8.2.1.52 re.MULTILINE | re.DOTALL, ) @@ -108,6 +109,16 @@ class Script(BaseScript): raise NotImplementedError("Unknown platform OID: %s" % oid) return platform + def fix_hw_serial(self): + serial, hw_ver = None, None + try: + # SNMPv2-MIB::sysDescr.0 + serial = self.snmp.get(mib["1.3.6.1.4.1.27514.1.1.1.1.1.4.0"]) + hw_ver = self.snmp.get(mib["1.3.6.1.4.1.27514.1.1.1.1.1.6.0"]) + except (self.snmp.TimeOutError, self.snmp.SNMPError): + pass + return serial, hw_ver + def execute_snmp(self, **kwargs): r = {"vendor": "Qtech", "attributes": {}} sys_descr = self.snmp.get(mib["SNMPv2-MIB::sysDescr.0"], cached=True) @@ -126,10 +137,15 @@ class Script(BaseScript): r["version"] = self.rx_version.search(sys_descr).group("version") if "bootprom" in match: r["attributes"]["Boot PROM"] = match["bootprom"] + hw_ver, serial = self.fix_hw_serial() if "hardware" in match: r["attributes"]["HW version"] = match["hardware"] + elif hw_ver: + r["attributes"]["HW version"] = hw_ver if "serial" in match: r["attributes"]["Serial Number"] = match["serial"] + elif serial: + r["attributes"]["Serial Number"] = serial return r def execute_cli(self, **kwargs): -- GitLab From 5bb845f9ea88309bc4d0482f4ffd5f95d5eb00e9 Mon Sep 17 00:00:00 2001 From: Andrey Vertiprahov Date: Thu, 22 Aug 2019 16:26:55 +0500 Subject: [PATCH 3/4] Fix QSW-3400-28T-AC rogue chars in output. --- sa/profiles/Qtech/QSW2800/get_version.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sa/profiles/Qtech/QSW2800/get_version.py b/sa/profiles/Qtech/QSW2800/get_version.py index 372def9ea3..d73b790849 100644 --- a/sa/profiles/Qtech/QSW2800/get_version.py +++ b/sa/profiles/Qtech/QSW2800/get_version.py @@ -122,6 +122,7 @@ class Script(BaseScript): def execute_snmp(self, **kwargs): r = {"vendor": "Qtech", "attributes": {}} sys_descr = self.snmp.get(mib["SNMPv2-MIB::sysDescr.0"], cached=True) + sys_descr = sys_descr.replace("\x16", "") # On QSW-3400-28T-AC 7.0.3.5(B0221.0055) for ree in [self.rx_ver, self.rx_ver2, self.rx_ver3]: match = ree.match(sys_descr) if match: -- GitLab From 5a690349613c5b195e1102b24b003f118c78a0f1 Mon Sep 17 00:00:00 2001 From: Andrey Vertiprahov Date: Thu, 22 Aug 2019 18:40:30 +0500 Subject: [PATCH 4/4] Qtech.QSW2800. Add QSW-3470-10T-AC-POE platform. --- sa/profiles/Qtech/QSW2800/get_version.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sa/profiles/Qtech/QSW2800/get_version.py b/sa/profiles/Qtech/QSW2800/get_version.py index d73b790849..c8a9aee8df 100644 --- a/sa/profiles/Qtech/QSW2800/get_version.py +++ b/sa/profiles/Qtech/QSW2800/get_version.py @@ -69,6 +69,7 @@ class Script(BaseScript): "1.3.6.1.4.1.27514.1.1.1.235": "QSW-8200-28F-AC-DC", "1.3.6.1.4.1.27514.1.1.1.248": "QSW-3450-28T-POE-AC", "1.3.6.1.4.1.27514.1.1.1.282": "QSW-3470-10T-AC", + "1.3.6.1.4.1.6339.1.1.1.301": "QSW-3470-10T-AC-POE", "1.3.6.1.4.1.27514.1.1.1.310": "QSW-3580-28T-AC", "1.3.6.1.4.1.27514.1.1.1.337": "QSW-2850-28T-AC", "1.3.6.1.4.1.27514.1.1.1.354": "QSW-3470-28T-AC-POE", -- GitLab