diff --git a/ciscoconfparse/ccp_abc.py b/ciscoconfparse/ccp_abc.py index c95c291b..92a39b19 100644 --- a/ciscoconfparse/ccp_abc.py +++ b/ciscoconfparse/ccp_abc.py @@ -29,7 +29,6 @@ DEFAULT_TEXT = "__undefined__" - # # ------------- Config Line ABC # diff --git a/ciscoconfparse/ciscoconfparse.py b/ciscoconfparse/ciscoconfparse.py index 72a4936d..4f16d8fc 100644 --- a/ciscoconfparse/ciscoconfparse.py +++ b/ciscoconfparse/ciscoconfparse.py @@ -173,6 +173,7 @@ def get_version_number(): return version +@logger.catch(reraise=True) def enforce_valid_types(var, var_types=None, error_str=None): assert isinstance(var_types, tuple) if not isinstance(var, var_types): @@ -812,6 +813,7 @@ def _check_ccp_input_good(self, config=None, logger=None, linesplit_rgx=r"\r*\n+ # do NOT wrap this method in logger.catch() - github issue #249 ######################################################################### @property + @logger.catch(reraise=True) def openargs(self): """Fix Py3.5 deprecation of universal newlines - Ref Github #114; also see https://softwareengineering.stackexchange.com/q/298677/23144.""" if sys.version_info >= ( @@ -825,6 +827,7 @@ def openargs(self): # This method is on CiscoConfParse() @property + @logger.catch(reraise=True) def ioscfg(self): """Return a list containing all text configuration statements.""" ## I keep ioscfg to emulate legacy ciscoconfparse behavior @@ -840,6 +843,7 @@ def ioscfg(self): # This method is on CiscoConfParse() @property + @logger.catch(reraise=True) def objs(self): """CiscoConfParse().objs is an alias for the CiscoConfParse().ConfigObjs property; it returns a ConfigList() of config-line objects.""" if self.ConfigObjs is None: @@ -3794,6 +3798,7 @@ def __init__( # FIXME - I think nxos is not going to work as-expected while using `build_ios_diffs()` self.build_ios_diffs() + @logger.catch(reraise=True) def parse_hdiff_configs(self): if self.debug > 1: @@ -3822,6 +3827,7 @@ def parse_hdiff_configs(self): ignore_blank_lines=self.ignore_blank_lines, ) + @logger.catch(reraise=True) def build_diff_obj_lists(self): """Assign the `diff_side` attribute to parse_before and parse_after *CfgLine() instances""" assert isinstance(self.parse_before, CiscoConfParse) @@ -4507,6 +4513,7 @@ def __init__( self._network_cache = {} # This method is on ConfigList() + @logger.catch(reraise=True) def __repr__(self): return """""".format( self.syntax, @@ -4514,38 +4521,47 @@ def __repr__(self): self._list, ) + @logger.catch(reraise=True) def __iter__(self): return iter(self._list) # This method is on ConfigList() + @logger.catch(reraise=True) def __lt__(self, other): return self._list < self.__cast(other) # This method is on ConfigList() + @logger.catch(reraise=True) def __le__(self, other): return self._list < self.__cast(other) # This method is on ConfigList() + @logger.catch(reraise=True) def __eq__(self, other): return self._list == self.__cast(other) # This method is on ConfigList() + @logger.catch(reraise=True) def __gt__(self, other): return self._list > self.__cast(other) # This method is on ConfigList() + @logger.catch(reraise=True) def __ge__(self, other): return self._list >= self.__cast(other) # This method is on ConfigList() + @logger.catch(reraise=True) def __cast(self, other): return other._list if isinstance(other, ConfigList) else other # This method is on ConfigList() + @logger.catch(reraise=True) def __len__(self): return len(self._list) # This method is on ConfigList() + @logger.catch(reraise=True) def __getitem__(self, ii): if isinstance(ii, slice): return self.__class__(self._list[ii]) @@ -4553,16 +4569,19 @@ def __getitem__(self, ii): return self._list[ii] # This method is on ConfigList() + @logger.catch(reraise=True) def __setitem__(self, ii, val): self._list[ii] = val # This method is on ConfigList() + @logger.catch(reraise=True) def __delitem__(self, ii): del self._list[ii] #self._bootstrap_from_text() self._list = self._bootstrap_obj_init_ng(self.ioscfg, debug=self.debug) # This method is on ConfigList() + @logger.catch(reraise=True) def __add__(self, other): if isinstance(other, ConfigList): return self.__class__(self._list + other._list) @@ -4571,6 +4590,7 @@ def __add__(self, other): return self.__class__(self._list + list(other)) # This method is on ConfigList() + @logger.catch(reraise=True) def __radd__(self, other): if isinstance(other, ConfigList): return self.__class__(other._list + self._list) @@ -4579,6 +4599,7 @@ def __radd__(self, other): return self.__class__(list(other) + self._list) # This method is on ConfigList() + @logger.catch(reraise=True) def __iadd__(self, other): if isinstance(other, ConfigList): self._list += other._list @@ -4589,16 +4610,19 @@ def __iadd__(self, other): return self # This method is on ConfigList() + @logger.catch(reraise=True) def __mul__(self, val): return self.__class__(self._list * val) __rmul__ = __mul__ + @logger.catch(reraise=True) def __imul__(self, val): self._list *= val return self # This method is on ConfigList() + @logger.catch(reraise=True) def __copy__(self): inst = self.__class__.__new__(self.__class__) inst.__dict__.update(self.__dict__) @@ -4607,21 +4631,25 @@ def __copy__(self): return inst # This method is on ConfigList() + @logger.catch(reraise=True) def __str__(self): return self.__repr__() # This method is on ConfigList() + @logger.catch(reraise=True) def __enter__(self): # Add support for with statements... # FIXME: *with* statements dont work yield from self._list # This method is on ConfigList() + @logger.catch(reraise=True) def __exit__(self, *args, **kwargs): # FIXME: *with* statements dont work self._list[0].confobj.CiscoConfParse.atomic() # This method is on ConfigList() + @logger.catch(reraise=True) def __getattribute__(self, arg): """Call arg on ConfigList() object, and if that fails, call arg from the ccp_ref attribute""" # Try a method call on ASAConfigList() @@ -4646,6 +4674,7 @@ def __getattribute__(self, arg): # This method is on ConfigList() @junos_unsupported + @logger.catch(reraise=True) def append(self, val): if self.debug >= 1: logger.debug(" ConfigList().append(val={}) was called.".format(val)) @@ -4653,39 +4682,47 @@ def append(self, val): self._list.append(val) # This method is on ConfigList() + @logger.catch(reraise=True) def pop(self, ii=-1): return self._list.pop(ii) # This method is on ConfigList() + @logger.catch(reraise=True) def remove(self, val): self._list.remove(val) # This method is on ConfigList() + @logger.catch(reraise=True) def clear(self): self._list.clear() # This method is on ConfigList() + @logger.catch(reraise=True) def copy(self): return self.__class__(self) # This method is on ConfigList() + @logger.catch(reraise=True) def count(self, val): return self._list.count(val) # This method is on ConfigList() + @logger.catch(reraise=True) def index(self, val, *args): return self._list.index(val, *args) # This method is on ConfigList() + @logger.catch(reraise=True) def reverse(self): self._list.reverse() # This method is on ConfigList() - # def sort(self, /, *args, **kwds): + @logger.catch(reraise=True) def sort(self, _unknown_arg, *args, **kwds): self._list.sort(*args, **kwds) # This method is on ConfigList() + @logger.catch(reraise=True) def extend(self, other): if isinstance(other, ConfigList): self._list.extend(other._list) @@ -4693,6 +4730,7 @@ def extend(self, other): self._list.extend(other) # This method is on ConfigList() + @logger.catch(reraise=True) def has_line_with(self, linespec): # https://stackoverflow.com/a/16097112/667301 matching_conftext = list( @@ -4705,6 +4743,7 @@ def has_line_with(self, linespec): # This method is on ConfigList() @junos_unsupported + @logger.catch(reraise=True) def insert_before_deprecated(self, exist_val, new_val, atomic=False): """ Insert new_val before all occurances of exist_val. @@ -4739,6 +4778,7 @@ def insert_before_deprecated(self, exist_val, new_val, atomic=False): ############################################################################## # This method is on ConfigList() + @logger.catch(reraise=True) def insert_before(self, exist_val, new_val, atomic=False): """ Insert new_val before all occurances of exist_val. @@ -4842,6 +4882,7 @@ def insert_before(self, exist_val, new_val, atomic=False): # This method is on ConfigList() @junos_unsupported + @logger.catch(reraise=True) def insert_after(self, exist_val="", new_val="", atomic=False, new_val_indent=-1): """ Insert new_val after all occurances of exist_val. @@ -4954,6 +4995,7 @@ def insert_after(self, exist_val="", new_val="", atomic=False, new_val_indent=-1 # This method is on ConfigList() @junos_unsupported + @logger.catch(reraise=True) def insert(self, ii, val): if not isinstance(ii, int): raise ValueError @@ -4989,6 +5031,7 @@ def insert(self, ii, val): self.reassign_linenums() # This method is on ConfigList() + @logger.catch(reraise=True) def config_hierarchy(self): """Walk this configuration and return the following tuple at each parent 'level': (list_of_parent_sibling_objs, list_of_nonparent_sibling_objs) @@ -5008,6 +5051,7 @@ def config_hierarchy(self): return parent_siblings, nonparent_siblings # This method is on ConfigList() + @logger.catch(reraise=True) def _banner_mark_regex(self, regex): """ Use the regex input parameter to identify all banner parent @@ -5109,6 +5153,7 @@ def _banner_mark_regex(self, regex): break # This method is on ConfigList() + @logger.catch(reraise=True) def _macro_mark_children(self, macro_parent_idx_list): """ Set the blank_line_keep attribute for all banner parent / child objs. @@ -5136,6 +5181,7 @@ def _macro_mark_children(self, macro_parent_idx_list): finished = True # This method is on ConfigList() + @logger.catch(reraise=True) def _maintain_bootstrap_parent_cache( self, parents_cache, parent, indent, max_indent, is_config_line ): @@ -5161,6 +5207,7 @@ def _maintain_bootstrap_parent_cache( return parents_cache, parent + @logger.catch(reraise=True) def _build_bootstrap_parent_child( self, retval, parents_cache, parent, idx, indent, obj, debug, ): @@ -5200,6 +5247,7 @@ def _build_bootstrap_parent_child( # This method is on ConfigList() + @logger.catch(reraise=True) def _bootstrap_obj_init_ng(self, text_list=None, debug=0): """ Accept a text list, and format into a list of *CfgLine() objects. @@ -5297,6 +5345,7 @@ def _bootstrap_obj_init_ng(self, text_list=None, debug=0): return retval # This method is on ConfigList() + @logger.catch(reraise=True) def _build_banner_re_ios(self): """Return a banner regexp for IOS (and at this point, NXOS).""" banner_str = { @@ -5316,6 +5365,7 @@ def _build_banner_re_ios(self): return banner_re # This method is on ConfigList() + @logger.catch(reraise=True) def _add_child_to_parent(self, _list, idx, indent, parentobj, childobj): ## parentobj could be None when trying to add a child that should not ## have a parent @@ -5354,18 +5404,21 @@ def _add_child_to_parent(self, _list, idx, indent, parentobj, childobj): pass # This method is on ConfigList() + @logger.catch(reraise=True) def iter_with_comments(self, begin_index=0): for idx, obj in enumerate(self._list): if idx >= begin_index: yield obj # This method is on ConfigList() + @logger.catch(reraise=True) def iter_no_comments(self, begin_index=0): for idx, obj in enumerate(self._list): if (idx >= begin_index) and (not obj.is_comment): yield obj # This method is on ConfigList() + @logger.catch(reraise=True) def reassign_linenums(self): # Call this after any insertion or deletion for idx, obj in enumerate(self._list): @@ -5373,11 +5426,13 @@ def reassign_linenums(self): # This method is on ConfigList() @property + @logger.catch(reraise=True) def all_parents(self): return [obj for obj in self._list if obj.has_children] # This method is on ConfigList() @property + @logger.catch(reraise=True) def last_index(self): return self.__len__() - 1 @@ -5387,6 +5442,7 @@ def last_index(self): # This method was on ASAConfigList(); now tentatively on ConfigList() @property + @logger.catch(reraise=True) def names(self): """Return a dictionary of name to address mappings""" assert self.syntax == "asa" @@ -5401,6 +5457,7 @@ def names(self): # This method was on ASAConfigList(); now tentatively on ConfigList() @property + @logger.catch(reraise=True) def object_group_network(self): """Return a dictionary of name to object-group network mappings""" assert self.syntax == "asa" @@ -5414,6 +5471,7 @@ def object_group_network(self): # This method was on ASAConfigList(); now tentatively on ConfigList() @property + @logger.catch(reraise=True) def access_list(self): """Return a dictionary of ACL name to ACE (list) mappings""" assert self.syntax == "asa" @@ -5437,19 +5495,23 @@ def access_list(self): class DiffObject(object): """This object should be used at every level of hierarchy""" + @logger.catch(reraise=True) def __init__(self, level, nonparents, parents): self.level = level self.nonparents = nonparents self.parents = parents + @logger.catch(reraise=True) def __repr__(self): return "".format(self.level) class CiscoPassword(object): + @logger.catch(reraise=True) def __init__(self, ep=""): self.ep = ep + @logger.catch(reraise=True) def decrypt(self, ep=""): """Cisco Type 7 password decryption. Converted from perl code that was written by jbash [~at~] cisco.com; enhancements suggested by @@ -5535,6 +5597,7 @@ def decrypt(self, ep=""): return dp +@logger.catch(reraise=True) def ConfigLineFactory(text="", comment_delimiter="!", syntax="ios"): """A factory method to assign a custom *CfgLine() object based on the contents of the input text parameter and input syntax parameter.""" # Complicted & Buggy diff --git a/ciscoconfparse/models_asa.py b/ciscoconfparse/models_asa.py index 94370d95..4032f769 100644 --- a/ciscoconfparse/models_asa.py +++ b/ciscoconfparse/models_asa.py @@ -1,6 +1,6 @@ r""" models_asa.py - Parse, Query, Build, and Modify IOS-style configurations - Copyright (C) 2021 David Michael Pennington + Copyright (C) 2021,2023 David Michael Pennington Copyright (C) 2020-2021 David Michael Pennington at Cisco Systems Copyright (C) 2019 David Michael Pennington at ThousandEyes Copyright (C) 2014-2019 David Michael Pennington at Samsung Data Services @@ -41,6 +41,8 @@ from ciscoconfparse.ccp_util import L4Object from ciscoconfparse.ccp_util import IPv4Obj +from loguru import logger + ## ##------------- ASA Configuration line object ## @@ -81,6 +83,7 @@ class ASACfgLine(BaseCfgLine): """ + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Accept an ASA line number and initialize family relationship attributes""" @@ -90,11 +93,13 @@ def __init__(self, *args, **kwargs): self._mm_results = None @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): ## Default object, for now return True @property + @logger.catch(reraise=True) def is_intf(self): # Includes subinterfaces intf_regex = r"^interface\s+(\S+.+)" @@ -103,6 +108,7 @@ def is_intf(self): return False @property + @logger.catch(reraise=True) def is_subintf(self): intf_regex = r"^interface\s+(\S+?\.\d+)" if self.re_match(intf_regex): @@ -110,6 +116,7 @@ def is_subintf(self): return False @property + @logger.catch(reraise=True) def is_virtual_intf(self): intf_regex = r"^interface\s+(Loopback|Tunnel|Virtual-Template|Port-Channel)" if self.re_match(intf_regex): @@ -117,6 +124,7 @@ def is_virtual_intf(self): return False @property + @logger.catch(reraise=True) def is_loopback_intf(self): intf_regex = r"^interface\s+(\Soopback)" if self.re_match(intf_regex): @@ -124,6 +132,7 @@ def is_loopback_intf(self): return False @property + @logger.catch(reraise=True) def is_ethernet_intf(self): intf_regex = r"^interface\s+(.*?\Sthernet)" if self.re_match(intf_regex): @@ -144,11 +153,13 @@ def is_ethernet_intf(self): class BaseASAIntfLine(ASACfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.ifindex = None # Optional, for user use self.default_ipv4_addr_object = IPv4Obj("0.0.0.1/32", strict=False) + @logger.catch(reraise=True) def __repr__(self): if not self.is_switchport: if self.ipv4_addr_object == self.default_ipv4_addr_object: @@ -168,15 +179,18 @@ def __repr__(self): self.name, ) + @logger.catch(reraise=True) def reset(self, atomic=True): # Insert build_reset_string() before this line... self.insert_before(self.build_reset_string(), atomic=atomic) + @logger.catch(reraise=True) def build_reset_string(self): # ASA interfaces are defaulted like this... raise NotImplementedError @property + @logger.catch(reraise=True) def verbose(self): if not self.is_switchport: return ( @@ -205,12 +219,14 @@ def verbose(self): ) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): return False ##------------- Basic interface properties @property + @logger.catch(reraise=True) def name(self): """Return a string, such as 'GigabitEthernet0/1'""" if not self.is_intf: @@ -220,17 +236,20 @@ def name(self): return name @property + @logger.catch(reraise=True) def port(self): """Return the interface's port number""" return self.ordinal_list[-1] @property + @logger.catch(reraise=True) def port_type(self): """Return Loopback, GigabitEthernet, etc...""" port_type_regex = r"^interface\s+([A-Za-z\-]+)" return self.re_match(port_type_regex, group=1, default="") @property + @logger.catch(reraise=True) def ordinal_list(self): """Return a list of numbers representing card, slot, port for this interface. If you call ordinal_list on GigabitEthernet2/25.100, you'll get this python list 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. @@ -246,6 +265,7 @@ def ordinal_list(self): return [] @property + @logger.catch(reraise=True) def description(self): retval = self.re_match_iter_typed( r"^\s*description\s+(\S.+)$", result_type=str, default="" @@ -253,6 +273,7 @@ def description(self): return retval @property + @logger.catch(reraise=True) def manual_delay(self): retval = self.re_match_iter_typed( r"^\s*delay\s+(\d+)$", result_type=int, default=0 @@ -260,6 +281,7 @@ def manual_delay(self): return retval @property + @logger.catch(reraise=True) def ipv4_addr_object(self): """Return a ccp_util.IPv4Obj object representing the address on this interface; if there is no address, return IPv4Obj('0.0.0.1/32')""" try: @@ -268,6 +290,7 @@ def ipv4_addr_object(self): return self.default_ipv4_addr_object @property + @logger.catch(reraise=True) def ipv4_standby_addr_object(self): """Return a ccp_util.IPv4Obj object representing the standby address on this interface; if there is no address, return IPv4Obj('0.0.0.1/32')""" try: @@ -276,11 +299,13 @@ def ipv4_standby_addr_object(self): return self.default_ipv4_addr_object @property + @logger.catch(reraise=True) def ipv4_network_object(self): """Return an ccp_util.IPv4Obj object representing the subnet on this interface; if there is no address, return ccp_util.IPv4Obj('0.0.0.1/32')""" return self.ip_network_object @property + @logger.catch(reraise=True) def ip_network_object(self): try: return IPv4Obj( @@ -294,6 +319,7 @@ def ip_network_object(self): raise ValueError(err_text) @property + @logger.catch(reraise=True) def has_autonegotiation(self): if not self.is_ethernet_intf: return False @@ -307,6 +333,7 @@ def has_autonegotiation(self): raise ValueError @property + @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 @@ -314,6 +341,7 @@ def has_manual_speed(self): return retval @property + @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 @@ -321,6 +349,7 @@ def has_manual_duplex(self): return retval @property + @logger.catch(reraise=True) def is_shutdown(self): retval = self.re_match_iter_typed( r"^\s*(shut\S*)\s*$", result_type=bool, default=False @@ -328,10 +357,12 @@ def is_shutdown(self): return retval @property + @logger.catch(reraise=True) def ip_addr(self): return self.ipv4_addr @property + @logger.catch(reraise=True) def ipv4_addr(self): """Return a string with the interface's IPv4 address, or '' if there is none""" retval = self.re_match_iter_typed( @@ -342,6 +373,7 @@ def ipv4_addr(self): return retval @property + @logger.catch(reraise=True) def ipv4_standby_addr(self): """Return a string with the interface's IPv4 address, or '' if there is none""" retval = self.re_match_iter_typed( @@ -352,6 +384,7 @@ def ipv4_standby_addr(self): return retval @property + @logger.catch(reraise=True) def ipv4_netmask(self): """Return a string with the interface's IPv4 netmask, or '' if there is none""" retval = self.re_match_iter_typed( @@ -362,6 +395,7 @@ def ipv4_netmask(self): return retval @property + @logger.catch(reraise=True) def ipv4_masklength(self): """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 @@ -369,6 +403,7 @@ def ipv4_masklength(self): return ipv4_addr_object.prefixlen return 0 + @logger.catch(reraise=True) def in_ipv4_subnet(self, ipv4network=IPv4Obj("0.0.0.0/32", strict=False)): """Accept two string arguments for network and netmask, and return a boolean for whether this interface is within the requested subnet. Return None if there is no address on the interface""" if not (str(self.ipv4_addr_object.ip) == "0.0.0.1"): @@ -384,6 +419,7 @@ def in_ipv4_subnet(self, ipv4network=IPv4Obj("0.0.0.0/32", strict=False)): else: return None + @logger.catch(reraise=True) def in_ipv4_subnets(self, subnets=None): """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: @@ -397,6 +433,7 @@ def in_ipv4_subnets(self, subnets=None): return tmp @property + @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 @@ -412,6 +449,7 @@ def has_ip_pim_sparse_mode(self): return retval @property + @logger.catch(reraise=True) def is_switchport(self): retval = self.re_match_iter_typed( r"^\s*(switchport)\s*", result_type=bool, default=False @@ -419,6 +457,7 @@ def is_switchport(self): return retval @property + @logger.catch(reraise=True) def has_manual_switch_access(self): retval = self.re_match_iter_typed( r"^\s*(switchport\smode\s+access)\s*$", result_type=bool, default=False @@ -426,10 +465,12 @@ def has_manual_switch_access(self): return retval @property + @logger.catch(reraise=True) def has_manual_switch_trunk_encap(self): return bool(self.manual_switch_trunk_encap) @property + @logger.catch(reraise=True) def has_manual_switch_trunk(self): retval = self.re_match_iter_typed( r"^\s*(switchport\s+mode\s+trunk)\s*$", result_type=bool, default=False @@ -437,6 +478,7 @@ def has_manual_switch_trunk(self): return retval @property + @logger.catch(reraise=True) def access_vlan(self): """Return an integer with the access vlan number. Return 0, if the port has no explicit vlan configured.""" retval = self.re_match_iter_typed( @@ -454,6 +496,7 @@ def access_vlan(self): class ASAName(ASACfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Accept an ASA line number and initialize family relationship attributes""" @@ -468,12 +511,14 @@ def __init__(self, *args, **kwargs): self.addr = self._mm_results["addr"] @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if "name " in line[0:5].lower(): return True return False @property + @logger.catch(reraise=True) def result_dict(self): mm_r = self._mm_results retval = dict() @@ -490,12 +535,14 @@ def result_dict(self): class ASAObjNetwork(ASACfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Accept an ASA line number and initialize family relationship attributes""" super().__init__(*args, **kwargs) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if "object network " in line[0:15].lower(): return True @@ -508,12 +555,14 @@ def is_object_for(cls, line="", re=re): class ASAObjService(ASACfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Accept an ASA line number and initialize family relationship attributes""" super().__init__(*args, **kwargs) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if "object service " in line[0:15].lower(): return True @@ -533,6 +582,7 @@ def is_object_for(cls, line="", re=re): class ASAObjGroupNetwork(ASACfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Accept an ASA line number and initialize family relationship attributes""" @@ -543,12 +593,14 @@ def __init__(self, *args, **kwargs): ) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if "object-group network " in line[0:21].lower(): return True return False @property + @logger.catch(reraise=True) def hash_children(self): ## Manually override the BaseCfgLine method since this recurses through ## children @@ -556,12 +608,14 @@ def hash_children(self): return hash(tuple(self.network_strings)) # network_strings recurses... @property + @logger.catch(reraise=True) def network_count(self): ## Return the number of discrete network objects covered by this group ## FIXME: Implement port_count for ASAObjGroupService return len(self.network_strings) @property + @logger.catch(reraise=True) def network_strings(self): """Return a list of strings which represent the address space allowed by this object-group""" @@ -612,6 +666,7 @@ def network_strings(self): return retval @property + @logger.catch(reraise=True) def networks(self): """Return a list of IPv4Obj objects which represent the address space allowed by This object-group""" @@ -647,6 +702,7 @@ def networks(self): class ASAObjGroupService(ASACfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Accept an ASA line number and initialize family relationship attributes""" @@ -671,17 +727,20 @@ def __init__(self, *args, **kwargs): self.L4Objects_are_directional = False @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if "object-group service " in line[0:21].lower(): return True return False + @logger.catch(reraise=True) def __repr__(self): return "".format( self.name, self.protocol_type ) @property + @logger.catch(reraise=True) def ports(self): """Return a list of objects which represent the protocol and ports allowed by this object-group""" retval = list() @@ -764,12 +823,14 @@ def ports(self): class ASAIntfLine(BaseASAIntfLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Accept an ASA line number and initialize family relationship attributes""" super().__init__(*args, **kwargs) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): intf_regex = r"^interface\s+(\S+.+)" if re.search(intf_regex, line): @@ -783,14 +844,17 @@ def is_object_for(cls, line="", re=re): class ASAIntfGlobal(BaseCfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.feature = "interface global" + @logger.catch(reraise=True) def __repr__(self): return "<{} # {} '{}'>".format(self.classname, self.linenum, self.text) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if re.search("^mtu", line): return True @@ -803,20 +867,24 @@ def is_object_for(cls, line="", re=re): class ASAHostnameLine(BaseCfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.feature = "hostname" + @logger.catch(reraise=True) def __repr__(self): return "<{} # {} '{}'>".format(self.classname, self.linenum, self.hostname) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if re.search("^hostname", line): return True return False @property + @logger.catch(reraise=True) def hostname(self): retval = self.re_match_typed(r"^hostname\s+(\S+)", result_type=str, default="") return retval @@ -828,9 +896,11 @@ def hostname(self): class BaseASARouteLine(BaseCfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + @logger.catch(reraise=True) def __repr__(self): return "<{} # {} '{}' info: '{}'>".format( self.classname, @@ -840,6 +910,7 @@ def __repr__(self): ) @property + @logger.catch(reraise=True) def routeinfo(self): ### Route information for the repr string if self.tracking_object_name: @@ -854,31 +925,38 @@ def routeinfo(self): return self.nexthop_str + " AD: " + str(self.admin_distance) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): return False @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 @@ -889,6 +967,7 @@ def tracking_object_name(self): class ASARouteLine(BaseASARouteLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if "ipv6" in self.text: @@ -897,12 +976,14 @@ def __init__(self, *args, **kwargs): self.feature = "ip route" @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): if re.search(r"^(ip|ipv6)\s+route\s+\S", line): return True return False @property + @logger.catch(reraise=True) def address_family(self): ## ipv4, ipv6, etc retval = self.re_match_typed( @@ -911,6 +992,7 @@ def address_family(self): return retval @property + @logger.catch(reraise=True) def network(self): if self.address_family == "ip": retval = self.re_match_typed( @@ -923,6 +1005,7 @@ def network(self): return retval @property + @logger.catch(reraise=True) def netmask(self): if self.address_family == "ip": retval = self.re_match_typed( @@ -935,6 +1018,7 @@ def netmask(self): return retval @property + @logger.catch(reraise=True) def network_object(self): try: if self.address_family == "ip": @@ -945,6 +1029,7 @@ def network_object(self): return None @property + @logger.catch(reraise=True) def nexthop_str(self): if self.address_family == "ip": retval = self.re_match_typed( @@ -960,11 +1045,13 @@ def nexthop_str(self): return retval @property + @logger.catch(reraise=True) def admin_distance(self): retval = self.re_match_typed(r"(\d+)$", group=1, result_type=int, default=1) return retval @property + @logger.catch(reraise=True) def tracking_object_name(self): retval = self.re_match_typed( r"^ip(v6)*\s+route\s+.+?track\s+(\S+)", group=2, result_type=str, default="" @@ -1117,6 +1204,7 @@ def tracking_object_name(self): class ASAAclLine(ASACfgLine): + @logger.catch(reraise=True) def __init__(self, *args, **kwargs): """Provide attributes on Cisco ASA Access-Lists""" super().__init__(*args, **kwargs) @@ -1136,6 +1224,7 @@ def __init__(self, *args, **kwargs): raise ValueError("[FATAL] ASAAclLine() cannot parse text:'{}'".format(text)) @classmethod + @logger.catch(reraise=True) def is_object_for(cls, line="", re=re): # if _RE_ACLOBJECT.search(line): if "access-list " in line[0:12].lower(): @@ -1143,6 +1232,7 @@ def is_object_for(cls, line="", re=re): return False @property + @logger.catch(reraise=True) def src_addr_method(self): mm_r = self._mm_results if mm_r["action0"] and (mm_r["action0"] == "remark"): @@ -1177,6 +1267,7 @@ def src_addr_method(self): ) @property + @logger.catch(reraise=True) def dst_addr_method(self): mm_r = self._mm_results if mm_r["action0"] and (mm_r["action0"] == "remark"): @@ -1210,6 +1301,7 @@ def dst_addr_method(self): ) @property + @logger.catch(reraise=True) def acl_protocol_dict(self): mm_r = self._mm_results retval = dict() @@ -1243,6 +1335,7 @@ def acl_protocol_dict(self): ) @property + @logger.catch(reraise=True) def result_dict(self): mm_r = self._mm_results retval = dict() diff --git a/ciscoconfparse/models_cisco.py b/ciscoconfparse/models_cisco.py index cf988c1c..6963c870 100644 --- a/ciscoconfparse/models_cisco.py +++ b/ciscoconfparse/models_cisco.py @@ -834,20 +834,6 @@ def ipv4_addr_object(self): logger.warning("intf='{}' ipv4_addr='{}' ipv4_netmask='{}'".format(self.name, self.ipv4_addr, self.ipv4_netmask)) return self.default_ipv4_addr_object - if False: - if self.ipv4_addr == "dhcp": - logger.critical("DHCP CONDITION 1") - raise DynamicAddressException - elif self.ipv4_addr == "" or self.ipv4_netmask == "": - logger.critical("DHCP CONDITION 2 -> RETURN") - #raise ValueError("Cannot parse ipv4 address from interface {}".format(self.name)) - return IPv4Obj("0.0.0.1/32", strict=False) - - try: - return IPv4Obj("%s/%s" % (self.ipv4_addr, self.ipv4_netmask)) - except DynamicAddressException as e: - raise ValueError(e) - @property @logger.catch(reraise=True) def ipv4_network_object(self): @@ -1076,9 +1062,6 @@ def ipv4_addr(self): ) if condition1.lower() == "dhcp": return "" - if False: - error = "Cannot parse address from a dhcp interface: {0}".format(self.name) - raise DynamicAddressException(error) else: return retval diff --git a/ciscoconfparse/models_junos.py b/ciscoconfparse/models_junos.py index 1c8e3dc0..3a7be21e 100644 --- a/ciscoconfparse/models_junos.py +++ b/ciscoconfparse/models_junos.py @@ -1,6 +1,6 @@ r""" models_junos.py - Parse, Query, Build, and Modify Junos-style configurations - Copyright (C) 2021-2022 David Michael Pennington + Copyright (C) 2021-2023 David Michael Pennington Copyright (C) 2020-2021 David Michael Pennington at Cisco Systems Copyright (C) 2019 David Michael Pennington at ThousandEyes Copyright (C) 2015-2019 David Michael Pennington at Samsung Data Services @@ -34,8 +34,6 @@ from ciscoconfparse.ccp_abc import BaseCfgLine from ciscoconfparse.ccp_util import IPv4Obj - - ## ##------------- Junos Configuration line object ## diff --git a/ciscoconfparse/protocol_values.py b/ciscoconfparse/protocol_values.py index d83581f7..730134c3 100644 --- a/ciscoconfparse/protocol_values.py +++ b/ciscoconfparse/protocol_values.py @@ -2,7 +2,7 @@ r""" protocol_values.py - Parse, Query, Build, and Modify IOS-style configurations - Copyright (C) 2021 David Michael Pennington + Copyright (C) 2021,2023 David Michael Pennington Copyright (C) 2020-2021 David Michael Pennington at Cisco Systems Copyright (C) 2019 David Michael Pennington at ThousandEyes Copyright (C) 2014-2019 David Michael Pennington at Samsung Data Services