From 78b34ed21ddbf88ed6ca9be81a9c33a2f90cc7f8 Mon Sep 17 00:00:00 2001 From: mpenning Date: Wed, 29 Nov 2023 17:00:04 -0600 Subject: [PATCH] Remove unused code --- ciscoconfparse/models_all.py | 2636 ---------------------------------- 1 file changed, 2636 deletions(-) delete mode 100644 ciscoconfparse/models_all.py diff --git a/ciscoconfparse/models_all.py b/ciscoconfparse/models_all.py deleted file mode 100644 index 7cae699..0000000 --- a/ciscoconfparse/models_all.py +++ /dev/null @@ -1,2636 +0,0 @@ -from __future__ import absolute_import -from abc import abstractmethod -import copy -import re -import os - -from ciscoconfparse.errors import DynamicAddressException - -from ciscoconfparse.ccp_util import CiscoRange, CiscoInterface -from ciscoconfparse.ccp_util import IPv4Obj, IPv6Obj -from ciscoconfparse.ccp_abc import BaseCfgLine - -from loguru import logger - -### HUGE UGLY WARNING: -### Anything in models_cisco.py could change at any time, until I remove this -### warning. I have good reason to believe that these methods are stable and -### function correctly, but I've been wrong before. There are no unit tests -### for this functionality yet, so I consider all this code alpha quality. -### -### Use models_cisco.py at your own risk. You have been warned :-) -r""" models_all.py - Parse, Query, Build, and Modify IOS-style configurations - - Copyright (C) 2023 David Michael Pennington - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - If you need to contact the author, you can do so by emailing: - mike [~at~] pennington [/dot\] net -""" - -MAX_VLAN = 4094 - -## -##------------- IOS Configuration line object -## - -class BaseCfgModel(BaseCfgLine): - """An object for a parsed IOS-style configuration line. - :class:`~models_cisco.IOSCfgLine` objects contain references to other - parent and child :class:`~models_cisco.IOSCfgLine` objects. - - Parameters - ---------- - text : str - A string containing a text copy of the text configuration line. :class:`~ciscoconfparse.CiscoConfParse` will automatically identify the parent and children (if any) when it parses the configuration. - comment_delimiter : str - A string which is considered a comment for the configuration format. Since this is for Cisco IOS-style configurations, it defaults to ``!``. - - Attributes - ---------- - text : str - A string containing the parsed IOS configuration statement - linenum : int - The line number of this configuration statement in the original config; default is -1 when first initialized. - parent : (:class:`~models_cisco.IOSCfgLine()`) - The parent of this object; defaults to ``self``. - children : list - A list of ``IOSCfgLine()`` objects which are children of this object. - child_indent : int - An integer with the indentation of this object's children - indent : int - An integer with the indentation of this object's ``text`` oldest_ancestor (bool): A boolean indicating whether this is the oldest ancestor in a family - is_comment : bool - A boolean indicating whether this is a comment - - Returns - ------- - An instance of :class:`~models_all.BaseCfgModel`. - - """ - - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - r"""Accept an IOS line number and initialize family relationship - attributes""" - super().__init__(*args, **kwargs) - - def __init_subclass__(cls, *args, **kwargs): - """Block methods in subclass that do not exist on this parent class: - ref: https://stackoverflow.com/q/61328355""" - super().__init_subclass__(*args, **kwargs) - # By inspecting `cls.__dict__` we pick all methods declared directly on the class - for name, attr in cls.__dict__.items(): - attr = getattr(cls, name) - if not callable(attr): - continue - for superclass in cls.__mro__[1:]: - if name in dir(superclass): - break - else: - # method not found in superclasses: - raise TypeError(f"Method {name} defined in {cls.__name__} does not exist in superclasses BaseCfgModel()") - - - def __str__(self): - raise NotImplementedError() - - def __repr__(self): - raise NotImplementedError() - - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - ## Default object, for now - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def _list(self): - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def is_intf(self): - # Includes subinterfaces - r"""Returns a boolean (True or False) to answer whether this - :class:`~models_cisco.IOSCfgLine` is an interface; subinterfaces - also return True. - - Returns - ------- - bool - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 18,21 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface Serial1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config) - >>> obj = parse.find_objects('^interface\sSerial')[0] - >>> obj.is_intf - True - >>> obj = parse.find_objects('^interface\sATM')[0] - >>> obj.is_intf - True - >>> - """ - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def is_subintf(self): - r"""Returns a boolean (True or False) to answer whether this - :class:`~models_cisco.IOSCfgLine` is a subinterface. - - Returns - ------- - bool - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 18,21 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface Serial1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config) - >>> obj = parse.find_objects(r'^interface\sSerial')[0] - >>> obj.is_subintf - False - >>> obj = parse.find_objects(r'^interface\sATM')[0] - >>> obj.is_subintf - True - >>> - """ - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def is_virtual_intf(self): - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def is_loopback_intf(self): - r"""Returns a boolean (True or False) to answer whether this - :class:`~models_cisco.IOSCfgLine` is a loopback interface. - - Returns - ------- - bool - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 13,16 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface Loopback0', - ... ' ip address 1.1.1.5 255.255.255.255', - ... '!', - ... ] - >>> parse = CiscoConfParse(config) - >>> obj = parse.find_objects(r'^interface\sFast')[0] - >>> obj.is_loopback_intf - False - >>> obj = parse.find_objects(r'^interface\sLoop')[0] - >>> obj.is_loopback_intf - True - >>> - """ - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def is_ethernet_intf(self): - r"""Returns a boolean (True or False) to answer whether this - :class:`~models_cisco.IOSCfgLine` is an ethernet interface. - Any ethernet interface (10M through 10G) is considered an ethernet - interface. - - Returns - ------- - bool - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 18,21 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.is_ethernet_intf - True - >>> obj = parse.find_objects('^interface\sATM')[0] - >>> obj.is_ethernet_intf - False - >>> - """ - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def intf_in_portchannel(self): - r"""Return a boolean indicating whether this port is configured in a port-channel - - Returns - ------- - bool - """ - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def portchannel_number(self): - r"""Return an integer for the port-channel which it's configured in. Return -1 if it's not configured in a port-channel - - Returns - ------- - bool - """ - retval = self.re_match_iter_typed( - r"^\s*channel-group\s+(\d+)", result_type=int, default=-1 - ) - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def is_portchannel_intf(self): - r"""Return a boolean indicating whether this port is a port-channel intf - - Returns - ------- - bool - """ - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @abstractmethod - @logger.catch(reraise=True) - def _build_abbvs(self): - r"""Build a set of valid abbreviations (lowercased) for the interface""" - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def abbvs(self): - r"""A python set of valid abbreviations (lowercased) for the interface""" - return self._build_abbvs() - - @abstractmethod - @logger.catch(reraise=True) - def get_vrrp_tracking_interfaces(self): - raise NotImplementedError() - - @abstractmethod - @logger.catch(reraise=True) - def get_glbp_tracking_interfaces(self): - raise NotImplementedError() - - @abstractmethod - @logger.catch(reraise=True) - def get_hsrp_tracking_interfaces(self): - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_interfaces(self): - """Return the list of configured HSRPInterfaceGroup() instances""" - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @abstractmethod - @logger.catch(reraise=True) - def reset(self, atomic=True): - # Insert build_reset_string() before this line... - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @abstractmethod - @logger.catch(reraise=True) - def build_reset_string(self): - # IOS interfaces are defaulted like this... - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def verbose(self): - """Return a verbose string representation of this object""" - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def interface_object(self): - """Return a CiscoInterface() instance for this interface - - Returns - ------- - CiscoInterface - The interface name as a CiscoInterface() instance, or '' if the object is not an interface. The CiscoInterface instance can be transparently cast as a string into a typical Cisco IOS name. - """ - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def name(self): - r"""Return the interface name as a string, such as 'GigabitEthernet0/1' - - Returns - ------- - str - The interface name as a string instance, or '' if the object is not an interface. - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 17,20,23 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.name - 'FastEthernet1/0' - >>> obj = parse.find_objects('^interface\sATM')[0] - >>> obj.name - 'ATM2/0' - >>> obj = parse.find_objects('^interface\sATM')[1] - >>> obj.name - 'ATM2/0.100' - >>> - """ - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def port(self): - r"""Return the interface's port number - - Returns - ------- - int - The interface number. - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 17,20 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.port - 0 - >>> obj = parse.find_objects('^interface\sATM')[0] - >>> obj.port - 0 - >>> - """ - return self.interface_object.port - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def port_type(self): - r"""Return Loopback, ATM, GigabitEthernet, Virtual-Template, etc... - - Returns - ------- - str - The port type. - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 17,20 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.port_type - 'FastEthernet' - >>> obj = parse.find_objects('^interface\sATM')[0] - >>> obj.port_type - 'ATM' - >>> - """ - port_type_regex = r"^interface\s+([A-Za-z\-]+)" - return self.re_match(port_type_regex, group=1, default="") - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ordinal_list(self): - r"""Return a tuple of numbers representing card, slot, port for this interface. If you call ordinal_list on GigabitEthernet2/25.100, you'll get this python tuple of integers: (2, 25). If you call ordinal_list on GigabitEthernet2/0/25.100 you'll get this python list of integers: (2, 0, 25). This method strips all subinterface information in the returned value. - - Returns - ------- - tuple - A tuple of port numbers as integers. - - Warnings - -------- - ordinal_list should silently fail (returning an empty python list) if the interface doesn't parse correctly - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 17,20 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.ordinal_list - (1, 0) - >>> obj = parse.find_objects('^interface\sATM')[0] - >>> obj.ordinal_list - (2, 0) - >>> - """ - if not self.is_intf: - return () - else: - ifobj = self.interface_object - retval = [] - static_list = ( - ifobj.slot, ifobj.card, ifobj.port, - ifobj.subinterface, ifobj.channel, ifobj.interface_class - ) - if ifobj: - for ii in static_list: - if isinstance(ii, int): - retval.append(ii) - else: - retval.append(-1) - return tuple(retval) - else: - return () - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def interface_number(self): - r"""Return a string representing the card, slot, port for this interface. If you call interface_number on GigabitEthernet2/25.100, you'll get this python string: '2/25'. If you call interface_number on GigabitEthernet2/0/25.100 you'll get this python string '2/0/25'. This method strips all subinterface information in the returned value. - - Returns - ------- - str - - Warnings - -------- - interface_number should silently fail (returning an empty python string) if the interface doesn't parse correctly - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 17,20 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.interface_number - '1/0' - >>> obj = parse.find_objects('^interface\sATM')[-1] - >>> obj.interface_number - '2/0' - >>> - """ - if not self.is_intf: - return "" - else: - intf_regex = r"^interface\s+[A-Za-z\-]+\s*(\d+.*?)(\.\d+)*(\s\S+)*\s*$" - intf_number = self.re_match(intf_regex, group=1, default="") - return intf_number - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def subinterface_number(self): - r"""Return a string representing the card, slot, port for this interface or subinterface. If you call subinterface_number on GigabitEthernet2/25.100, you'll get this python string: '2/25.100'. If you call interface_number on GigabitEthernet2/0/25 you'll get this python string '2/0/25'. This method strips all subinterface information in the returned value. - - Returns - ------- - str - - Warnings - -------- - subinterface_number should silently fail (returning an empty python string) if the interface doesn't parse correctly - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 17,20 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.subinterface_number - '1/0' - >>> obj = parse.find_objects('^interface\sATM')[-1] - >>> obj.subinterface_number - '2/0.100' - >>> - """ - if not self.is_intf: - return "" - else: - subintf_regex = r"^interface\s+[A-Za-z\-]+\s*(\d+.*?\.?\d?)(\s\S+)*\s*$" - subintf_number = self.re_match(subintf_regex, group=1, default="") - return subintf_number - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def description(self): - r"""Return the current interface description string. - - """ - retval = self.re_match_iter_typed( - r"^\s*description\s+(\S.*)$", result_type=str, default="" - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_bandwidth(self): - retval = self.re_match_iter_typed( - r"^\s*bandwidth\s+(\d+)$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_delay(self): - retval = self.re_match_iter_typed( - r"^\s*delay\s+(\d+)$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_holdqueue_out(self): - r"""Return the current hold-queue out depth, if default return 0""" - retval = self.re_match_iter_typed( - r"^\s*hold-queue\s+(\d+)\s+out$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_holdqueue_in(self): - r"""Return the current hold-queue in depth, if default return 0""" - retval = self.re_match_iter_typed( - r"^\s*hold-queue\s+(\d+)\s+in$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_encapsulation(self): - retval = self.re_match_iter_typed( - r"^\s*encapsulation\s+(\S+)", result_type=str, default="" - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_mpls(self): - retval = self.re_match_iter_typed( - r"^\s*(mpls\s+ip)$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4_addr_object(self): - r"""Return a ccp_util.IPv4Obj object representing the address on this interface; if there is no address, return IPv4Obj()""" - - if self.ipv4_addr=="": - return self.default_ipv4_addr_object - elif self.ipv4_addr=="dhcp": - return self.default_ipv4_addr_object - else: - return IPv4Obj(f"{self.ipv4_addr}/{self.ipv4_netmask}") - - try: - logger.info(f"intf='{self.name}' ipv4_addr='{self.ipv4_addr}' ipv4_netmask='{self.ipv4_netmask}'") - return IPv4Obj(f"{self.ipv4_addr}/{self.ipv4_netmask}") - except DynamicAddressException as eee: - logger.critical(f"intf='{self.name}' ipv4_addr='{self.ipv4_addr}' ipv4_netmask='{self.ipv4_netmask}': {eee}") - raise DynamicAddressException(eee) - except BaseException: - logger.warning(f"intf='{self.name}' ipv4_addr='{self.ipv4_addr}' ipv4_netmask='{self.ipv4_netmask}'") - return self.default_ipv4_addr_object - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_secondary(self): - r"""Return an boolean for whether this interface has IPv4 secondary addresses""" - retval = self.re_match_iter_typed( - r"^\s*ip\s+address\s+\S+\s+\S+\s+(?Psecondary)\s*$", - groupdict={"secondary": bool}, - default=False - ) - return retval["secondary"] - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip_secondary_addresses(self): - r"""Return a set of IPv4 secondary addresses (as strings)""" - retval = set() - for obj in self.parent.all_children: - _gg = obj.re_match_iter_typed( - r"^\s*ip\s+address\s+(?P\S+\s+\S+)\s+secondary\s*$", - groupdict={"secondary": IPv4Obj}, - default=False - ) - if _gg["secondary"]: - retval.add(str(_gg["secondary"].ip)) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip_secondary_networks(self): - r"""Return a set of IPv4 secondary addresses / prefixlen""" - retval = set() - for obj in self.parent.all_children: - _gg = obj.re_match_iter_typed( - r"^\s*ip\s+address\s+(?P\S+\s+\S+)\s+secondary\s*$", - groupdict={"secondary": IPv4Obj}, - default=False - ) - if _gg["secondary"]: - retval.add(f"{_gg['secondary'].ip}/{_gg['secondary'].prefixlen}") - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_no_ipv4(self): - r"""Return an ccp_util.IPv4Obj object representing the subnet on this interface; if there is no address, return ccp_util.IPv4Obj()""" - return self.ipv4_addr_object == IPv4Obj() - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip(self): - r"""Return an ccp_util.IPv4Obj object representing the IPv4 address on this interface; if there is no address, return ccp_util.IPv4Obj()""" - return self.ipv4_addr_object - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4(self): - r"""Return an ccp_util.IPv4Obj object representing the IPv4 address on this interface; if there is no address, return ccp_util.IPv4Obj()""" - return self.ipv4_addr_object - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4_network_object(self): - r"""Return an ccp_util.IPv4Obj object representing the subnet on this interface; if there is no address, return ccp_util.IPv4Obj()""" - return self.ip_network_object - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip_network_object(self): - # Simplified on 2014-12-02 - try: - return IPv4Obj(f"{self.ipv4_addr}/{self.ipv4_mask}", strict=False) - except DynamicAddressException as e: - raise DynamicAddressException(e) - except BaseException as e: - return self.default_ipv4_addr_object - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_autonegotiation(self): - if not self.is_ethernet_intf: - return False - elif self.is_ethernet_intf and ( - self.has_manual_speed or self.has_manual_duplex - ): - return False - elif self.is_ethernet_intf: - return True - else: - raise ValueError - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_speed(self): - retval = self.re_match_iter_typed( - r"^\s*speed\s+(\d+)$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_duplex(self): - retval = self.re_match_iter_typed( - r"^\s*duplex\s+(\S.+)$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_carrierdelay(self): - r"""Return a python boolean for whether carrier delay is manually configured on the interface""" - return bool(self.manual_carrierdelay) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_carrierdelay(self): - r"""Return the manual carrier delay (in seconds) of the interface as a python float. If there is no explicit carrier delay, return 0.0""" - cd_seconds = self.re_match_iter_typed( - r"^\s*carrier-delay\s+(\d+)$", result_type=float, default=0.0 - ) - cd_msec = self.re_match_iter_typed( - r"^\s*carrier-delay\s+msec\s+(\d+)$", result_type=float, default=0.0 - ) - - if cd_seconds > 0.0: - return cd_seconds - elif cd_msec > 0.0: - return cd_msec / 1000.0 - else: - return 0.0 - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_clock_rate(self): - return bool(self.manual_clock_rate) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_clock_rate(self): - r"""Return the clock rate of the interface as a python integer. If there is no explicit clock rate, return 0""" - retval = self.re_match_iter_typed( - r"^\s*clock\s+rate\s+(\d+)$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_mtu(self): - ## Due to the diverse platform defaults, this should be the - ## only mtu information I plan to support - r"""Returns a integer value for the manual MTU configured on an - :class:`~models_cisco.IOSIntfLine` object. Interfaces without a - manual MTU configuration return 0. - - Returns - ------- - int - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 18,21 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' mtu 4470', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.manual_mtu - 0 - >>> obj = parse.find_objects('^interface\sATM')[0] - >>> obj.manual_mtu - 4470 - >>> - """ - retval = self.re_match_iter_typed( - r"^\s*mtu\s+(\d+)$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_mpls_mtu(self): - ## Due to the diverse platform defaults, this should be the - ## only mtu information I plan to support - retval = self.re_match_iter_typed( - r"^\s*mpls\s+mtu\s+(\d+)$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_ip_mtu(self): - ## Due to the diverse platform defaults, this should be the - ## only mtu information I plan to support - retval = self.re_match_iter_typed( - r"^\s*ip\s+mtu\s+(\d+)$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_speed(self): - retval = self.re_match_iter_typed( - r"^\s*speed\s+(\d+)$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_duplex(self): - retval = self.re_match_iter_typed( - r"^\s*duplex\s+(\S.+)$", result_type=str, default="" - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_mtu(self): - return bool(self.manual_mtu) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_mpls_mtu(self): - return bool(self.manual_mpls_mtu) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_ip_mtu(self): - return bool(self.manual_ip_mtu) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def is_shutdown(self): - retval = self.re_match_iter_typed( - r"^\s*(shut\S*)\s*$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_vrf(self): - return bool(self.vrf) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def vrf(self): - retval = self.re_match_iter_typed( - r"^\s*(ip\s+)*vrf\sforwarding\s(\S+)$", result_type=str, group=2, default="" - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip_addr(self): - return self.ipv4_addr - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4_addr(self): - r"""Return a string with the interface's IPv4 address, or '' if there is none""" - retval = self.re_match_iter_typed( - r"^\s+ip\s+address\s+(\d+\.\d+\.\d+\.\d+)\s+\d+\.\d+\.\d+\.\d+\s*$", - result_type=str, - default="", - ) - condition1 = self.re_match_iter_typed( - r"^\s+ip\s+address\s+(dhcp)\s*$", result_type=str, default="" - ) - if condition1.lower() == "dhcp": - return "" - else: - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4_netmask(self): - r"""Return a string with the interface's IPv4 netmask, or '' if there is none""" - retval = self.re_match_iter_typed( - r"^\s+ip\s+address\s+\d+\.\d+\.\d+\.\d+\s+(\d+\.\d+\.\d+\.\d+)\s*$", - result_type=str, - default="", - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4_masklength(self): - r"""Return an integer with the interface's IPv4 mask length, or 0 if there is no IP address on the interace""" - ipv4_addr_object = self.ipv4_addr_object - if ipv4_addr_object != self.default_ipv4_addr_object: - return ipv4_addr_object.prefixlen - return 0 - - # This method is on BaseIOSIntfLine() - @abstractmethod - @logger.catch(reraise=True) - def is_abbreviated_as(self, val): - r"""Test whether `val` is a good abbreviation for the interface""" - if val.lower() in self.abbvs: - return True - return False - - # This method is on BaseIOSIntfLine() - @abstractmethod - @logger.catch(reraise=True) - def in_ipv4_subnet(self, ipv4network=None, strict=False): - r"""Accept an argument for the :class:`~ccp_util.IPv4Obj` to be - considered, and return a boolean for whether this interface is within - the requested :class:`~ccp_util.IPv4Obj`. - - Parameters - ---------- - ipv4network : :class:`~ccp_util.IPv4Obj` - An object to compare against IP addresses configured on this :class:`~models_cisco.IOSIntfLine` object. - - Returns - ------- - bool - If there is an ip address, or None if there is no ip address. - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 21,23 - - >>> from ciscoconfparse.ccp_util import IPv4Obj - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface Serial1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... '!', - ... 'interface ATM2/0', - ... ' no ip address', - ... '!', - ... 'interface ATM2/0.100 point-to-point', - ... ' ip address 1.1.1.5 255.255.255.252', - ... ' pvc 0/100', - ... ' vbr-nrt 704 704', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sSerial')[0] - >>> obj - - >>> obj.in_ipv4_subnet(IPv4Obj('1.1.1.0/24', strict=False)) - True - >>> obj.in_ipv4_subnet(IPv4Obj('2.1.1.0/24', strict=False)) - False - >>> - """ - if self.ipv4_addr_object.empty is True: - return False - elif ipv4network is None: - return False - elif isinstance(ipv4network, IPv4Obj) and ipv4network.empty is True: - return False - elif isinstance(ipv4network, IPv4Obj): - intf_ipv4obj = self.ipv4_addr_object - if isinstance(intf_ipv4obj, IPv4Obj): - try: - # Return a boolean for whether the interface is in that - # network and mask - return intf_ipv4obj in ipv4network - except Exception as eee: - error = f"FATAL: {self}.in_ipv4_subnet(ipv4network={ipv4network}) is invalid: {eee}" - logger.error(error) - raise ValueError(error) - else: - error = f"{self}.ipv4_addr_object must be an instance of IPv4Obj, but it is {type(intf_ipv4obj)}" - logger.error(error) - raise ValueError(error) - else: - return None - - # This method is on BaseIOSIntfLine() - @abstractmethod - @logger.catch(reraise=True) - def in_ipv4_subnets(self, subnets=None): - r"""Accept a set or list of ccp_util.IPv4Obj objects, and return a boolean for whether this interface is within the requested subnets.""" - if subnets is None: - raise ValueError( - "A python list or set of ccp_util.IPv4Obj objects must be supplied" - ) - for subnet in subnets: - if subnet.empty is True: - continue - tmp = self.in_ipv4_subnet(ipv4network=subnet) - if self.ipv4_addr_object in subnet: - return tmp - return tmp - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_no_icmp_unreachables(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## Interface must have an IP addr to respond - if self.ipv4_addr == "": - return False - - retval = self.re_match_iter_typed( - r"^\s*no\sip\s(unreachables)\s*$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_no_icmp_redirects(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## Interface must have an IP addr to respond - if self.ipv4_addr == "": - return False - - retval = self.re_match_iter_typed( - r"^\s*no\sip\s(redirects)\s*$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_no_ip_proxyarp(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - r"""Return a boolean for whether no ip proxy-arp is configured on the - interface. - - Returns - ------- - bool - - Examples - -------- - This example illustrates use of the method. - - .. code-block:: python - :emphasize-lines: 12 - - >>> from ciscoconfparse.ccp_util import IPv4Obj - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/0', - ... ' ip address 1.1.1.1 255.255.255.252', - ... ' no ip proxy-arp', - ... '!', - ... ] - >>> parse = CiscoConfParse(config, factory=True) - >>> obj = parse.find_objects('^interface\sFast')[0] - >>> obj.has_no_ip_proxyarp - True - >>> - """ - - ## Interface must have an IP addr to respond - if self.ipv4_addr == "": - return False - - ## By default, Cisco IOS answers proxy-arp - ## By default, Nexus disables proxy-arp - ## By default, IOS-XR disables proxy-arp - retval = self.re_match_iter_typed( - r"^\s*no\sip\s(proxy-arp)\s*$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_pim_dense_mode(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## Interface must have an IP addr to run PIM - if self.ipv4_addr == "": - return False - - retval = self.re_match_iter_typed( - r"^\s*(ip\spim\sdense-mode)\s*$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_pim_sparse_mode(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## Interface must have an IP addr to run PIM - if self.ipv4_addr == "": - return False - - retval = self.re_match_iter_typed( - r"^\s*(ip\spim\ssparse-mode)\s*$", result_type=bool, default=False - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_pim_sparsedense_mode(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## Interface must have an IP addr to run PIM - if self.ipv4_addr == "": - return False - - for _obj in self.children: - if _obj.text.strip().split()[0:3] == ["ip", "pim", "sparse-dense-mode"]: - return True - return False - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_arp_timeout(self): - r"""Return an integer with the current interface ARP timeout, if there isn't one set, return 0. If there is no IP address, return -1""" - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## Interface must have an IP addr to respond - if self.ipv4_addr == "": - return -1 - - ## By default, Cisco IOS defaults to 4 hour arp timers - ## By default, Nexus defaults to 15 minute arp timers - retval = self.re_match_iter_typed( - r"^\s*arp\s+timeout\s+(\d+)\s*$", result_type=int, default=0 - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_helper_addresses(self): - r"""Return a True if the intf has helper-addresses; False if not""" - if len(self.ip_helper_addresses) > 0: - return True - return False - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip_helper_addresses(self): - r"""Return a list of dicts with IP helper-addresses. Each helper-address is in a dictionary. The dictionary is in this format: - - Examples - -------- - - .. code-block:: python - :emphasize-lines: 11 - - >>> from ciscoconfparse import CiscoConfParse - >>> config = [ - ... '!', - ... 'interface FastEthernet1/1', - ... ' ip address 1.1.1.1 255.255.255.0', - ... ' ip helper-address 172.16.20.12', - ... ' ip helper-address 172.19.185.91', - ... '!', - ... ] - >>> parse = CiscoConfParse(config) - >>> obj = parse.find_objects('^interface\sFastEthernet1/1$')[0] - >>> obj.ip_helper_addresses - [{'addr': '172.16.20.12', 'vrf': '', 'global': False}, {'addr': '172.19.185.91', 'vrf': '', 'global': False}] - >>>""" - retval = list() - for child in self.children: - if "helper-address" in child.text: - addr = child.re_match_typed( - r"ip\s+helper-address\s.*?(\d+\.\d+\.\d+\.\d+)" - ) - global_addr = child.re_match_typed( - r"ip\s+helper-address\s+(global)", result_type=bool, default=False - ) - vrf = child.re_match_typed( - r"ip\s+helper-address\s+vrf\s+(\S+)", default="" - ) - retval.append({"addr": addr, "vrf": vrf, "global": bool(global_addr)}) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def is_switchport(self): - for _obj in self.children: - if _obj.text.strip().split()[0] == "switchport": - return True - return False - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_switch_access(self): - for _obj in self.children: - if _obj.text.strip().split()[0:3] == ["switchport", "mode", "access"]: - return True - return False - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_switch_trunk_encap(self): - return bool(self.manual_switch_trunk_encap) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def manual_switch_trunk_encap(self): - for _obj in self.children: - _parts = _obj.text.strip().split() - if len(_parts) == 4 and _parts[0:3] == ["switchport", "trunk", "encap"]: - return _parts[3] - return "" - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_switch_trunk(self): - for _obj in self.children: - if _obj.text.strip().split()[0:3] == ["switchport", "mode", "trunk"]: - return True - return False - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_switch_portsecurity(self): - if not self.is_switchport: - return False - ## IMPORTANT: Cisco IOS will not enable port-security on the port - ## unless 'switch port-security' (with no other options) - ## is in the configuration - for _obj in self.children: - if _obj.text.strip().split()[0:2] == ["switchport", "port-security"]: - return True - return False - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_switch_stormcontrol(self): - if not self.is_switchport: - return False - for _obj in self.children: - if _obj.text.strip().split()[0:1] == ["storm-control"]: - return True - return False - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_dtp(self): - if not self.is_switchport: - return False - - ## Not using self.re_match_iter_typed, because I want to - ## be sure I build the correct API for regex_match is False, and - ## default value is True - for obj in self.children: - switch = obj.re_match(r"^\s*(switchport\snoneg\S*)\s*$") - if (switch is not None): - return False - return True - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def access_vlan(self): - r"""Return an integer with the access vlan number. Return 1, if the switchport has no explicit vlan configured; return 0 if the port isn't a switchport""" - if self.is_switchport: - default_val = 1 - else: - default_val = 0 - - for _obj in self.children: - if _obj.text.strip().split()[0:3] == ["switchport", "access", "vlan"]: - return int(_obj.text.strip().split()[3]) - return default_val - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def trunk_vlans_allowed(self): - r"""Return a CiscoRange() with the list of allowed vlan numbers (as int). Return 0 if the port isn't a switchport in trunk mode""" - - # The default value for retval... - if self.is_switchport and not self.has_manual_switch_access: - retval = CiscoRange(result_type=int) - else: - return 0 - - - # Default to allow allow all vlans... - vdict = {"allowed": "1-4094"} - - ## Iterate over switchport trunk statements - for obj in self.children: - split_line = [ii for ii in obj.text.split() if ii.strip() != ""] - length_split_line = len(split_line) - - ## For every child object, check whether the vlan list is modified - allowed_str = obj.re_match_typed( - # switchport trunk allowed vlan - r"^\s+switchport\s+trunk\s+allowed\s+vlan\s+(all|none|\d[\d\-\,\s]*)$", - default="_nomatch_", - result_type=str, - ).lower() - if allowed_str != "_nomatch_": - if vdict.get("allowed", "_no_allowed_") != "_no_allowed_": - # Replace the default allow of 1-4094... - vdict["allowed"] = allowed_str - elif vdict.get("allowed", None) is None: - # Specify an initial list of vlans... - vdict["allowed"] = allowed_str - elif allowed_str != "none" and allowed_str != "all": - # handle **double allowed** statements here... - vdict["allowed"] += f",{allowed_str}" - else: - raise NotImplementedError("Unexpected command: `{obj.text}`") - - add_str = obj.re_match_typed( - r"^\s+switchport\s+trunk\s+allowed\s+vlan\s+add\s+(\d[\d\-\,\s]*)$", - default="_nomatch_", - result_type=str, - ).lower() - if add_str != "_nomatch_": - if vdict.get("add", None) is None: - vdict["add"] = add_str - else: - vdict["add"] += f",{add_str}" - - exc_str = obj.re_match_typed( - r"^\s+switchport\s+trunk\s+allowed\s+vlan\s+except\s+(\d[\d\-\,\s]*)$", - default="_nomatch_", - result_type=str, - ).lower() - if exc_str != "_nomatch_": - if vdict.get("except", None) is None: - vdict["except"] = exc_str - else: - vdict["except"] += f",{exc_str}" - - rem_str = obj.re_match_typed( - r"^\s+switchport\s+trunk\s+allowed\s+vlan\s+remove\s+(\d[\d\-\,\s]*)$", - default="_nomatch_", - result_type=str, - ).lower() - if rem_str != "_nomatch_": - if vdict.get("remove", None) is None: - vdict["remove"] = rem_str - else: - vdict["remove"] += f",{rem_str}" - - ## Analyze each vdict in sequence and apply to retval sequentially - if isinstance(vdict.get("allowed", None), str): - if vdict.get("allowed") == "all": - if len(retval) != 4094: - retval = CiscoRange(f"1-{MAX_VLAN}", result_type=int) - elif vdict.get("allowed") == "none": - retval = CiscoRange(result_type=int) - elif vdict.get("allowed") != "_nomatch_": - retval = CiscoRange(vdict["allowed"], result_type=int) - - for key, _value in vdict.items(): - _value = _value.strip() - if _value == "": - continue - elif _value != "_nomatch_": - ## allowed in the key overrides previous values - if key=="allowed": - retval = CiscoRange(result_type=int) - if _value.lower() == "none": - continue - elif _value.lower() == "all": - retval = CiscoRange(text=f"1-{MAX_VLAN}", result_type=int) - elif _value == "_nomatch_": - for ii in _value.split(","): - if "-" in _value: - for jj in CiscoRange(_value, result_type=int): - retval.append(int(jj), ignore_errors=True) - else: - retval.append(int(ii), ignore_errors=True) - elif isinstance(re.search(r"^\d[\d\-\,]*", _value), re.Match): - for ii in _value.split(","): - if "-" in _value: - for jj in CiscoRange(_value, result_type=int): - retval.append(int(jj), ignore_errors=True) - else: - retval.append(int(ii), ignore_errors=True) - else: - error = f"Could not derive a vlan range for {_value}" - logger.error(error) - raise InvalidCiscoEthernetVlan(error) - - elif key=="add": - for ii in _value.split(","): - if "-" in _value: - for jj in CiscoRange(_value, result_type=int): - retval.append(int(jj), ignore_errors=True) - else: - retval.append(int(ii), ignore_errors=True) - elif key=="except": - retval = CiscoRange(text=f"1-{MAX_VLAN}", result_type=int) - for ii in _value.split(","): - if "-" in _value: - for jj in CiscoRange(_value, result_type=int): - retval.remove(int(jj), ignore_errors=True) - else: - retval.remove(int(ii), ignore_errors=True) - elif key=="remove": - for ii in _value.split(","): - if "-" in _value: - for jj in CiscoRange(text=_value, result_type=int): - # Use ignore_errors to ignore missing elements... - retval.remove(int(jj), ignore_errors=True) - else: - # Use ignore_errors to ignore missing elements... - retval.remove(int(ii), ignore_errors=True) - else: - error = f"{key} is an invalid Cisco switched dot1q ethernet trunk action." - logger.error(error) - raise InvalidCiscoEthernetTrunkAction(error) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def native_vlan(self): - r"""Return an integer with the native vlan number. Return 1, if the switchport has no explicit native vlan configured; return 0 if the port isn't a switchport""" - if self.is_switchport: - default_val = 1 - else: - default_val = 0 - for _obj in self.children: - _parts = _obj.text.strip().split() - if len(_parts) == 5 and _parts[0:4] == ["switchport", "trunk", "native", "vlan"]: - # return the vlan integer from 'switchport trunk native vlan 911' - return int(_parts[4]) - return default_val - - ##------------- CDP - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_manual_disable_cdp(self): - for _obj in self.children: - _parts = _obj.text.strip().split() - if len(_parts) == 3 and _parts[0:3] == ["no", "cdp", "enable",]: - return True - return False - - ##------------- EoMPLS - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_xconnect(self): - return bool(self.xconnect_vc) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def xconnect_vc(self): - retval = self.re_match_iter_typed( - r"^\s*xconnect\s+\S+\s+(\d+)\s+\S+", result_type=int, default=0 - ) - return retval - - ##------------- HSRP - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_hsrp(self): - return bool(self.hsrp_ip_addr) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_ip_addr(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - if self.ipv4_addr == "": - return "" - - retval = self.re_match_iter_typed( - r"^\s*standby\s+(\d+\s+)*ip\s+(\S+)", group=2, result_type=str, default="" - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_ip_mask(self): - ## NOTE: I have no intention of checking self.is_shutdown here - ## People should be able to check the sanity of interfaces - ## before they put them into production - - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - if self.ipv4_addr == "": - return "" - retval = self.re_match_iter_typed( - r"^\s*standby\s+(?P\d+\s+)*ip\s+\S+\s+(?P\S+)\s*$", - groupdict = {"mask": str}, - default="", - ) - return retval["mask"] - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_group(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - retval = self.re_match_iter_typed( - r"^\s*standby\s+(?P\d+)\s+ip\s+(?P\S+)", - groupdict={"group": int}, - default=-1 - ) - return retval["group"] - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_priority(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - if not self.has_ip_hsrp: - return 0 # Return this if there is no hsrp on the interface - retval = self.re_match_iter_typed( - r"^\s*standby\s+(?P\d+\s+)*priority\s+(?P\d+)", - groupdict={"group": int, "priority": int}, - default=100, - ) - return retval["priority"] - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_hello_timer(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - - # FIXME: handle msec timers... - retval = self.re_match_iter_typed( - r"^\s*standby\s+(\d+\s+)*timers\s+(\d+)\s+\d+", - group=2, - result_type=float, - default=0.0, - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_hold_timer(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - - # FIXME: this should be a float (in case of msec timers) - retval = self.re_match_iter_typed( - r"^\s*standby\s+(\d+\s+)*timers\s+\d+\s+(\d+)", - group=2, - result_type=float, - default=0.0, - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_hsrp_track(self): - return bool(self.hsrp_track) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_track(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - retval = self.re_match_iter_typed( - r"^\s*standby\s+(\d+\s+)*track\s(\S+.+?)\s+\d+\s*", - group=2, - result_type=str, - default="", - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_hsrp_usebia(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - retval = self.re_match_iter_typed( - r"^\s*standby\s+(\d+\s+)*(use-bia)", - group=2, - result_type=bool, - default=False, - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_hsrp_preempt(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - retval = self.re_match_iter_typed( - r"^\s*standby\s+(\d+\s+)*(use-bia)", - group=2, - result_type=bool, - default=False, - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_authentication_md5_keychain(self): - ## For API simplicity, I always assume there is only one hsrp - ## group on the interface - retval = self.re_match_iter_typed( - r"^\s*standby\s+(\d+\s+)*authentication\s+md5\s+key-chain\s+(\S+)", - group=2, - result_type=str, - default="", - ) - return retval - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_hsrp_authentication_md5(self): - keychain = self.hsrp_authentication_md5_keychain - return bool(keychain) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def hsrp_authentication_cleartext(self): - pass - - ##------------- MAC ACLs - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_mac_accessgroup_in(self): - if not self.is_switchport: - return False - return bool(self.mac_accessgroup_in) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_mac_accessgroup_out(self): - if not self.is_switchport: - return False - return bool(self.mac_accessgroup_out) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def mac_accessgroup_in(self): - retval = self.re_match_iter_typed( - r"^\s*mac\saccess-group\s+(?P\S+)\s+in\s*$", - groupdict={"group_number": str}, - default="" - ) - return retval["group_number"] - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def mac_accessgroup_out(self): - retval = self.re_match_iter_typed( - r"^\s*mac\saccess-group\s+(?P\S+)\s+out\s*$", - groupdict={"group_number": str}, - default="" - ) - return retval["group_number"] - - ##------------- IPv4 ACLs - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_accessgroup_in(self): - return bool(self.ipv4_accessgroup_in) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ip_accessgroup_out(self): - return bool(self.ipv4_accessgroup_out) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ipv4_accessgroup_in(self): - return bool(self.ipv4_accessgroup_in) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def has_ipv4_accessgroup_out(self): - return bool(self.ipv4_accessgroup_out) - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip_accessgroup_in(self): - return self.ipv4_accessgroup_in - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ip_accessgroup_out(self): - return self.ipv4_accessgroup_out - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4_accessgroup_in(self): - """Return the name of the inbound IPv4 ACL on the interface""" - raise NotImplementedError() - - # This method is on BaseIOSIntfLine() - @property - @abstractmethod - @logger.catch(reraise=True) - def ipv4_accessgroup_out(self): - """Return the name of the outbound IPv4 ACL on the interface""" - raise NotImplementedError() - - @abstractmethod - @logger.catch(reraise=True) - def manual_exectimeout_minutes(self): - """Return the VTY timeout minutes on the VTY line""" - raise NotImplementedError() - - @abstractmethod - @logger.catch(reraise=True) - def manual_exectimeout_seconds(self): - """Return the VTY timeout seconds on the VTY line""" - raise NotImplementedError() - - -if False: - ## - ##------------- IOS Interface Object - ## - - - class IOSIntfLine(BaseIOSIntfLine): - # This method is on IOSIntfLine() - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - r"""Accept an IOS line number and initialize family relationship - attributes - - Warnings - -------- - All :class:`~models_cisco.IOSIntfLine` methods are still considered beta-quality, until this notice is removed. The behavior of APIs on this object could change at any time. - """ - super(IOSIntfLine, self).__init__(*args, **kwargs) - self.feature = "interface" - - # This method is on IOSIntfLine() - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - intf_regex = re.search(r"^interface\s+(?P\S+.+)", line.strip()) - if isinstance(intf_regex, re.Match): - interface = intf_regex.groupdict()["interface"] - return True - else: - return False - - ## - ##------------- IOS Interface Globals - ## - - - @property - @abstractmethod - @logger.catch(reraise=True) - def has_cdp_disabled(self): - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def has_intf_logging_def(self): - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def has_stp_portfast_def(self): - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def has_stp_portfast_bpduguard_def(self): - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def has_stp_mode_rapidpvst(self): - raise NotImplementedError() - - @property - @abstractmethod - @logger.catch(reraise=True) - def hostname(self): - raise NotImplementedError() - - -## -##------------- Base IOS Route line object -## - - -class BaseIOSRouteLine(BaseCfgLine): - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - super(BaseIOSRouteLine, self).__init__(*args, **kwargs) - - @logger.catch(reraise=True) - def __repr__(self): - return "<%s # %s '%s' info: '%s'>" % ( - self.classname, - self.linenum, - self.network_object, - self.routeinfo, - ) - - @property - @logger.catch(reraise=True) - def routeinfo(self): - ### Route information for the repr string - if self.tracking_object_name: - return ( - self.nexthop_str - + " AD: " - + str(self.admin_distance) - + " Track: " - + self.tracking_object_name - ) - else: - return self.nexthop_str + " AD: " + str(self.admin_distance) - - @property - @logger.catch(reraise=True) - def vrf(self): - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def address_family(self): - ## ipv4, ipv6, etc - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def network(self): - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def netmask(self): - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def admin_distance(self): - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def nexthop_str(self): - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def tracking_object_name(self): - raise NotImplementedError - - - @property - @logger.catch(reraise=True) - def vrf(self): - if (self.route_info["vrf"] is not None): - return self.route_info["vrf"] - else: - return "" - - @property - @logger.catch(reraise=True) - def address_family(self): - ## ipv4, ipv6, etc - return self._address_family - - @property - @logger.catch(reraise=True) - def network(self): - if self._address_family == "ip": - return self.route_info["prefix"] - elif self._address_family == "ipv6": - retval = self.re_match_typed( - r"^ipv6\s+route\s+(vrf\s+)*(\S+?)\/\d+", - group=2, - result_type=str, - default="", - ) - return retval - - @property - @logger.catch(reraise=True) - def netmask(self): - if self._address_family == "ip": - return self.route_info["netmask"] - elif self._address_family == "ipv6": - return str(self.network_object.netmask) - - @property - @logger.catch(reraise=True) - def masklen(self): - if self._address_family == "ip": - return self.network_object.prefixlen - elif self._address_family == "ipv6": - masklen_str = self.route_info["masklength"] or "128" - return int(masklen_str) - - @property - @logger.catch(reraise=True) - def network_object(self): - try: - if self._address_family == "ip": - return IPv4Obj("%s/%s" % (self.network, self.netmask), strict=False) - elif self._address_family == "ipv6": - return IPv6Obj("%s/%s" % (self.network, self.masklen)) - except BaseException: - logger.critical("Found _address_family = '{}''".format(self._address_family)) - return None - - @property - @logger.catch(reraise=True) - def nexthop_str(self): - if self._address_family == "ip": - if self.next_hop_interface: - return self.next_hop_interface + " " + self.next_hop_addr - else: - return self.next_hop_addr - elif self._address_family == "ipv6": - retval = self.re_match_typed( - r"^ipv6\s+route\s+(vrf\s+)*\S+\s+(\S+)", - group=2, - result_type=str, - default="", - ) - return retval - - @property - @logger.catch(reraise=True) - def next_hop_interface(self): - if self._address_family == "ip": - if self.route_info["nh_intf"]: - return self.route_info["nh_intf"] - else: - return "" - elif self._address_family == "ipv6": - if self.route_info["nh_intf"]: - return self.route_info["nh_intf"] - else: - return "" - - @property - @logger.catch(reraise=True) - def next_hop_addr(self): - if self._address_family == "ip": - return self.route_info["nh_addr"] or "" - elif self._address_family == "ipv6": - return self.route_info["nh_addr1"] or self.route_info["nh_addr2"] or "" - - @property - @logger.catch(reraise=True) - def global_next_hop(self): - if self._address_family == "ip" and bool(self.vrf): - return bool(self.route_info["global"]) - elif self._address_family == "ip" and not bool(self.vrf): - return True - elif self._address_family == "ipv6": - ## ipv6 uses nexthop_vrf - raise ValueError( - "[FATAL] ipv6 doesn't support a global_next_hop for '{0}'".format( - self.text - ) - ) - else: - raise ValueError( - "[FATAL] Could not identify global next-hop for '{0}'".format(self.text) - ) - - @property - @logger.catch(reraise=True) - def nexthop_vrf(self): - if self._address_family == "ipv6": - return self.route_info["nexthop_vrf"] or "" - else: - raise ValueError( - "[FATAL] ip doesn't support a global_next_hop for '{0}'".format( - self.text - ) - ) - - @property - @logger.catch(reraise=True) - def admin_distance(self): - if self.route_info["ad"]: - return int(self.route_info["ad"]) - else: - return 1 - - @property - @logger.catch(reraise=True) - def multicast(self): - r"""Return whether the multicast keyword was specified""" - return bool(self.route_info["mcast"]) - - @property - @logger.catch(reraise=True) - def unicast(self): - ## FIXME It's unclear how to implement this... - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def route_name(self): - if self.route_info["name"]: - return self.route_info["name"] - else: - return "" - - @property - @logger.catch(reraise=True) - def permanent(self): - if self._address_family == "ip": - if self.route_info["permanent"]: - return bool(self.route_info["permanent"]) - else: - return False - elif self._address_family == "ipv6": - raise NotImplementedError - - @property - @logger.catch(reraise=True) - def tracking_object_name(self): - if bool(self.route_info["track"]): - return self.route_info["track"] - else: - return "" - - @property - @logger.catch(reraise=True) - def tag(self): - return self.route_info["tag"] or "" - - -################################ -################################ Groups ############################### -################################ - -## -##------------- IOS TACACS+ Group -## -class IOSAaaGroupServerLine(BaseCfgLine): - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - super(IOSAaaGroupServerLine, self).__init__(*args, **kwargs) - self.feature = "aaa group server" - - REGEX = r"^aaa\sgroup\sserver\s(?P\S+)\s(?P\S+)\s*$" - mm = re.search(REGEX, self.text) - if (mm is not None): - groups = mm.groupdict() - self.protocol = groups.get("protocol", "") - self.group = groups.get("group", "") - else: - raise ValueError - - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - if re.search(r"^aaa\sgroup\sserver", line): - return True - return False - - @property - @logger.catch(reraise=True) - def vrf(self): - return self.re_match_iter_typed( - r"^\s+(ip\s+)*vrf\s+forwarding\s+(\S+)", - group=2, - result_type=str, - default="", - ) - - @property - @logger.catch(reraise=True) - def source_interface(self): - return self.re_match_iter_typed( - r"^\s+ip\s+tacacs\s+source-interface\s+(\S.+?\S)\s*$", - group=1, - result_type=str, - default="", - ) - - @property - @logger.catch(reraise=True) - def server_private(self, re=re): - retval = set([]) - rgx_priv = re.compile(r"^\s+server-private\s+(\S+)\s") - for cobj in self.children: - mm = rgx_priv.search(cobj.text) - if (mm is not None): - retval.add(mm.group(1)) # This is the server's ip - return retval - - -## -##------------- IOS AAA Login Authentication Lines -## - -class IOSAaaLoginAuthenticationLine(BaseCfgLine): - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - super(IOSAaaLoginAuthenticationLine, self).__init__(*args, **kwargs) - self.feature = "aaa authentication login" - - regex = r"^aaa\sauthentication\slogin\s(\S+)\sgroup\s(\S+)(.+?)$" - self.list_name = self.re_match_typed( - regex, group=1, result_type=str, default="" - ) - self.group = self.re_match_typed(regex, group=2, result_type=str, default="") - methods_str = self.re_match_typed(regex, group=3, result_type=str, default="") - self.methods = methods_str.strip().split(r"\s") - - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - if re.search(r"^aaa\sauthentication\slogin", line): - return True - return False - -## -##------------- IOS AAA Enable Authentication Lines -## - -class IOSAaaEnableAuthenticationLine(BaseCfgLine): - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - super(IOSAaaEnableAuthenticationLine, self).__init__(*args, **kwargs) - self.feature = "aaa authentication enable" - - regex = r"^aaa\sauthentication\senable\s(\S+)\sgroup\s(\S+)(.+?)$" - self.list_name = self.re_match_typed( - regex, group=1, result_type=str, default="" - ) - self.group = self.re_match_typed(regex, group=2, result_type=str, default="") - methods_str = self.re_match_typed(regex, group=3, result_type=str, default="") - self.methods = methods_str.strip().split(r"\s") - - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - if re.search(r"^aaa\sauthentication\senable", line): - return True - return False - -## -##------------- IOS AAA Commands Authorization Lines -## - -class IOSAaaCommandsAuthorizationLine(BaseCfgLine): - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - super(IOSAaaCommandsAuthorizationLine, self).__init__(*args, **kwargs) - self.feature = "aaa authorization commands" - - regex = r"^aaa\sauthorization\scommands\s(\d+)\s(\S+)\sgroup\s(\S+)(.+?)$" - self.level = self.re_match_typed(regex, group=1, result_type=int, default=0) - self.list_name = self.re_match_typed( - regex, group=2, result_type=str, default="" - ) - self.group = self.re_match_typed(regex, group=3, result_type=str, default="") - methods_str = self.re_match_typed(regex, group=4, result_type=str, default="") - self.methods = methods_str.strip().split(r"\s") - - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - if re.search(r"^aaa\sauthorization\scommands", line): - return True - return False - -## -##------------- IOS AAA Commands Accounting Lines -## - -class IOSAaaCommandsAccountingLine(BaseCfgLine): - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - super(IOSAaaCommandsAccountingLine, self).__init__(*args, **kwargs) - self.feature = "aaa accounting commands" - - regex = r"^aaa\saccounting\scommands\s(\d+)\s(\S+)\s(none|stop\-only|start\-stop)\sgroup\s(\S+)$" - self.level = self.re_match_typed(regex, group=1, result_type=int, default=0) - self.list_name = self.re_match_typed( - regex, group=2, result_type=str, default="" - ) - self.record_type = self.re_match_typed( - regex, group=3, result_type=str, default="" - ) - self.group = self.re_match_typed(regex, group=4, result_type=str, default="") - - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - if re.search(r"^aaa\saccounting\scommands", line): - return True - return False - -## -##------------- IOS AAA Exec Accounting Lines -## - -class IOSAaaExecAccountingLine(BaseCfgLine): - @logger.catch(reraise=True) - def __init__(self, *args, **kwargs): - super(IOSAaaExecAccountingLine, self).__init__(*args, **kwargs) - self.feature = "aaa accounting exec" - - regex = r"^aaa\saccounting\sexec\s(\S+)\s(none|stop\-only|start\-stop)\sgroup\s(\S+)$" - self.list_name = self.re_match_typed( - regex, group=1, result_type=str, default="" - ) - self.record_type = self.re_match_typed( - regex, group=2, result_type=str, default="" - ) - self.group = self.re_match_typed(regex, group=3, result_type=str, default="") - - @classmethod - @logger.catch(reraise=True) - def is_object_for(cls, all_lines, line, re=re): - if re.search(r"^aaa\saccounting\sexec", line): - return True - return False