From 05291c93bba1aa364ba1ac7f2508e24bb362a814 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 1 May 2020 14:36:54 -0700 Subject: [PATCH 1/3] vendorize ifconfig-parser module for easier packaging in Fedora --- jc/parsers/ifconfig.py | 201 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 3 deletions(-) diff --git a/jc/parsers/ifconfig.py b/jc/parsers/ifconfig.py index 60515a76..d724482a 100644 --- a/jc/parsers/ifconfig.py +++ b/jc/parsers/ifconfig.py @@ -141,16 +141,17 @@ Examples: } ] """ +import re +from collections import namedtuple import jc.utils -from ifconfigparser import IfconfigParser class info(): - version = '1.6' + version = '1.7' description = 'ifconfig command parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' - details = 'Using ifconfig-parser package from https://github.com/KnightWhoSayNi/ifconfig-parser' + details = 'Using ifconfig-parser from https://github.com/KnightWhoSayNi/ifconfig-parser' # compatible options: linux, darwin, cygwin, win32, aix, freebsd compatible = ['linux', 'aix', 'freebsd', 'darwin'] @@ -160,6 +161,200 @@ class info(): __version__ = info.version +class IfconfigParser(object): + # Author: threeheadedknight@protonmail.com + # Date created: 30.06.2018 17:03 + # Python Version: 3.7 + + attributes = ['name', 'type', 'mac_addr', 'ipv4_addr', 'ipv4_bcast', 'ipv4_mask', 'ipv6_addr', 'ipv6_mask', + 'ipv6_scope', 'state', 'mtu', 'metric', 'rx_packets', 'rx_errors', 'rx_dropped', 'rx_overruns', + 'rx_frame', 'tx_packets', 'tx_errors', 'tx_dropped', 'tx_overruns', 'tx_carrier', 'tx_collisions', + 'rx_bytes', 'tx_bytes'] + + def __init__(self, console_output): + """ + :param console_output: + """ + + if isinstance(console_output, list): + source_data = " ".join(console_output) + else: + source_data = console_output.replace("\n", " ") + self.interfaces = self.parser(source_data=source_data) + + def list_interfaces(self): + """ + :return: + """ + return sorted(self.interfaces.keys()) + + def count_interfaces(self): + """ + :return: + """ + return len(self.interfaces.keys()) + + def filter_interfaces(self, **kwargs): + """ + :param kwargs: + :return: + """ + for attr in kwargs.keys(): + if attr not in IfconfigParser.attributes: + raise ValueError("Attribute [{}] not supported.".format(attr)) + + filtered_interfaces = [] + for name, details in self.interfaces.items(): + + if all(getattr(details, attr) == kwargs[attr] for attr in kwargs.keys()): + filtered_interfaces.append(name) + + return sorted(filtered_interfaces) + + def get_interface(self, name): + """ + :param name: + :return: + """ + if name in self.list_interfaces(): + return self.interfaces[name] + else: + raise InterfaceNotFound("Interface [{}] not found.".format(name)) + + def get_interfaces(self): + """ + :return: + """ + return self.interfaces + + def is_available(self, name): + """ + :param name: + :return: + """ + return name in self.interfaces + + def parser(self, source_data): + """ + :param source_data: + :return: + """ + + # Linux syntax + re_linux_interface = re.compile( + r"(?P[a-zA-Z0-9:._-]+)\s+Link encap:(?P\S+\s?\S+)(\s+HWaddr\s+\b" + r"(?P[0-9A-Fa-f:?]+))?", + re.I) + re_linux_ipv4 = re.compile( + r"inet addr:(?P(?:[0-9]{1,3}\.){3}[0-9]{1,3})(\s+Bcast:" + r"(?P(?:[0-9]{1,3}\.){3}[0-9]{1,3}))?\s+Mask:(?P(?:[0-9]{1,3}\.){3}[0-9]{1,3})", + re.I) + re_linux_ipv6 = re.compile( + r"inet6 addr:\s+(?P\S+)/(?P[0-9]+)\s+Scope:(?PLink|Host)", + re.I) + re_linux_state = re.compile( + r"\W+(?P(?:\w+\s)+)(?:\s+)?MTU:(?P[0-9]+)\s+Metric:(?P[0-9]+)", re.I) + re_linux_rx = re.compile( + r"RX packets:(?P[0-9]+)\s+errors:(?P[0-9]+)\s+dropped:" + r"(?P[0-9]+)\s+overruns:(?P[0-9]+)\s+frame:(?P[0-9]+)", + re.I) + re_linux_tx = re.compile( + r"TX packets:(?P[0-9]+)\s+errors:(?P[0-9]+)\s+dropped:" + r"(?P[0-9]+)\s+overruns:(?P[0-9]+)\s+carrier:(?P[0-9]+)", + re.I) + re_linux_bytes = re.compile(r"\W+RX bytes:(?P\d+)\s+\(.*\)\s+TX bytes:(?P\d+)\s+\(.*\)", re.I) + re_linux_tx_stats = re.compile(r"collisions:(?P[0-9]+)\s+txqueuelen:[0-9]+", re.I) + re_linux = [re_linux_interface, re_linux_ipv4, re_linux_ipv6, re_linux_state, re_linux_rx, re_linux_tx, + re_linux_bytes, re_linux_tx_stats] + + # OpenBSD syntax + re_openbsd_interface = re.compile( + r"(?P[a-zA-Z0-9:._-]+):\s+flags=(?P[0-9]+)<(?P\S+)?>\s+mtu\s+(?P[0-9]+)", + re.I) + re_openbsd_ipv4 = re.compile( + r"inet (?P(?:[0-9]{1,3}\.){3}[0-9]{1,3})\s+netmask\s+" + r"(?P(?:[0-9]{1,3}\.){3}[0-9]{1,3})(\s+broadcast\s+" + r"(?P(?:[0-9]{1,3}\.){3}[0-9]{1,3}))?", + re.I) + re_openbsd_ipv6 = re.compile( + r"inet6\s+(?P\S+)\s+prefixlen\s+(?P[0-9]+)\s+scopeid\s+(?P\w+x\w+)<" + r"(?:link|host)>", + re.I) + re_openbsd_details = re.compile( + r"\S+\s+(?:(?P[0-9A-Fa-f:?]+)\s+)?txqueuelen\s+[0-9]+\s+\((?P\S+\s?\S+)\)", re.I) + re_openbsd_rx = re.compile(r"RX packets (?P[0-9]+)\s+bytes\s+(?P\d+)\s+.*", re.I) + re_openbsd_rx_stats = re.compile( + r"RX errors (?P[0-9]+)\s+dropped\s+(?P[0-9]+)\s+overruns\s+" + r"(?P[0-9]+)\s+frame\s+(?P[0-9]+)", + re.I) + re_openbsd_tx = re.compile(r"TX packets (?P[0-9]+)\s+bytes\s+(?P\d+)\s+.*", re.I) + re_openbsd_tx_stats = re.compile( + r"TX errors (?P[0-9]+)\s+dropped\s+(?P[0-9]+)\s+overruns\s+" + r"(?P[0-9]+)\s+carrier\s+(?P[0-9]+)\s+collisions\s+(?P[0-9]+)", + re.I) + re_openbsd = [re_openbsd_interface, re_openbsd_ipv4, re_openbsd_ipv6, re_openbsd_details, re_openbsd_rx, + re_openbsd_rx_stats, re_openbsd_tx, re_openbsd_tx_stats] + + # FreeBSD syntax + re_freebsd_interface = re.compile( + r"(?P[a-zA-Z0-9:._-]+):\s+flags=(?P[0-9]+)<(?P\S+)>\s+metric\s+" + r"(?P[0-9]+)\s+mtu\s+(?P[0-9]+)", + re.I) + re_freebsd_ipv4 = re.compile( + r"inet (?P(?:[0-9]{1,3}\.){3}[0-9]{1,3})\s+netmask\s+(?P0x\S+)(\s+broadcast\s+" + r"(?P(?:[0-9]{1,3}\.){3}[0-9]{1,3}))?", + re.I) + re_freebsd_ipv6 = re.compile(r"\s?inet6\s(?P.*)(?:\%\w+\d+)\sprefixlen\s(?P\d+)(?:\s\w+)?\sscopeid\s(?P\w+x\w+)", re.I) + re_freebsd_details = re.compile(r"ether\s+(?P[0-9A-Fa-f:?]+)", re.I) + re_freebsd = [re_freebsd_interface, re_freebsd_ipv4, re_freebsd_ipv6, re_freebsd_details] + + available_interfaces = dict() + + for pattern in [re_linux_interface, re_openbsd_interface, re_freebsd_interface]: + network_interfaces = re.finditer(pattern, source_data) + positions = [] + while True: + try: + pos = next(network_interfaces) + positions.append(max(pos.start() - 1, 0)) + except StopIteration: + break + if positions: + positions.append(len(source_data)) + break + + if not positions: + return available_interfaces + + for l, r in zip(positions, positions[1:]): + chunk = source_data[l:r] + _interface = dict() + for pattern in re_linux + re_openbsd + re_freebsd: + match = re.search(pattern, chunk.replace('\t', '\n')) + if match: + details = match.groupdict() + for k, v in details.items(): + if isinstance(v, str): details[k] = v.strip() + _interface.update(details) + if _interface is not None: + available_interfaces[_interface['name']] = self.update_interface_details(_interface) + + return available_interfaces + + @staticmethod + def update_interface_details(interface): + for attr in IfconfigParser.attributes: + if attr not in interface: + interface[attr] = None + return namedtuple('Interface', interface.keys())(**interface) + + +class InterfaceNotFound(Exception): + """ + """ + pass + + def process(proc_data): """ Final processing to conform to the schema. From d13606b6dc2c207be6dea89a2c3e713c18a574b8 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 1 May 2020 14:37:23 -0700 Subject: [PATCH 2/3] modify dependencies for easier packaging into Fedora --- changelog.txt | 3 +++ jc/cli.py | 2 +- requirements.txt | 3 +-- setup.py | 5 ++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/changelog.txt b/changelog.txt index 7793908b..52516a53 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ jc changelog +20200501 v1.10.7 +- Requirements modifications for Fedora RPM packaging requirements + 20200420 v1.10.6 - Remove homebrew shim references from du osx tests diff --git a/jc/cli.py b/jc/cli.py index fa398aab..1aab30be 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -18,7 +18,7 @@ import jc.utils class info(): - version = '1.10.6' + version = '1.10.7' description = 'jc cli output JSON conversion tool' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' diff --git a/requirements.txt b/requirements.txt index c5b92888..8ad5147f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ -ifconfig-parser>=0.0.5 ruamel.yaml>=0.15.0 xmltodict>=0.12.0 -Pygments>=2.5.2 +Pygments>=2.4.2 diff --git a/setup.py b/setup.py index d25ea1b2..6e5cf5fa 100755 --- a/setup.py +++ b/setup.py @@ -5,15 +5,14 @@ with open('README.md', 'r') as f: setuptools.setup( name='jc', - version='1.10.6', + version='1.10.7', author='Kelly Brazil', author_email='kellyjonbrazil@gmail.com', description='This tool serializes the output of popular command line tools and filetypes to structured JSON output.', install_requires=[ - 'ifconfig-parser>=0.0.5', 'ruamel.yaml>=0.15.0', 'xmltodict>=0.12.0', - 'Pygments>=2.5.2' + 'Pygments>=2.4.2' ], license='MIT', long_description=long_description, From 4a77ec63a46554c84e646d31564230774ed87431 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 1 May 2020 14:57:50 -0700 Subject: [PATCH 3/3] add IfconfigParser class --- docs/parsers/ifconfig.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/parsers/ifconfig.md b/docs/parsers/ifconfig.md index f84d05f3..366cdb41 100644 --- a/docs/parsers/ifconfig.md +++ b/docs/parsers/ifconfig.md @@ -147,6 +147,17 @@ Examples: info(self, /, *args, **kwargs) ``` +## IfconfigParser +```python +IfconfigParser(self, console_output) +``` + +## InterfaceNotFound +```python +InterfaceNotFound(self, /, *args, **kwargs) +``` + + ## process ```python process(proc_data)