From 9bb420ecb592c359c8cfe04d55579d79abaf1df9 Mon Sep 17 00:00:00 2001 From: mpenning Date: Tue, 14 Nov 2023 19:04:15 -0600 Subject: [PATCH] Vastly speed up large CiscoRange() operations --- ciscoconfparse/ccp_util.py | 95 +++++++++++----- ciscoconfparse/ciscoconfparse.py | 21 ++-- ciscoconfparse/models_cisco.py | 185 +++++++++++++++---------------- tests/test_Ccp_Util.py | 5 +- tests/test_Models_Cisco.py | 18 +-- 5 files changed, 177 insertions(+), 147 deletions(-) diff --git a/ciscoconfparse/ccp_util.py b/ciscoconfparse/ccp_util.py index d5fb39e..5d5f06c 100644 --- a/ciscoconfparse/ccp_util.py +++ b/ciscoconfparse/ccp_util.py @@ -3016,7 +3016,7 @@ def __init__(self, interface_name=None, interface_dict=None, debug=False): if isinstance(interface_name, str): if debug is True: logger.info(f"CiscoIOSInterface(interface_name='{interface_name}') was called") - elif isinstance(interface_name, CiscoIOSInterface): + elif isinstance(interface_name, (CiscoIOSInterface, CiscoIOSXRInterface)): if debug is True: logger.info(f"CiscoIOSInterface(interface_name={interface_name}) {type(interface_name)} was called") # Re-parse the @@ -3051,7 +3051,7 @@ def __init__(self, interface_name=None, interface_dict=None, debug=False): logger.critical(error) raise InvalidCiscoInterface(error) else: - error = f"Could not create a CiscoIOSInterface() instance" + error = f"Could not create a CiscoIOSInterface() or CiscoIOSXRInterface instance" logger.critical(error) raise InvalidCiscoInterface(error) @@ -4855,7 +4855,7 @@ def __init__(self, text="", result_type=str, empty=False, default_iter_attr='por raise InvalidCiscoRange(error) # Ensure that result_type is in the set of valid_result_types... - valid_result_types = {str, int, float, None} + valid_result_types = {str, int, float, None, CiscoIOSInterface, CiscoIOSXRInterface} if not result_type in valid_result_types: error = f'CiscoRange(text="{text}", result_type={result_type}) [text: {type(text)}] is not a valid result_type. Choose from {valid_result_types}' logger.critical(error) @@ -4876,7 +4876,11 @@ def __init__(self, text="", result_type=str, empty=False, default_iter_attr='por self.range_str = "" if isinstance(text, str) or empty is False: if result_type is None: - self._list = self.parse_cisco_interfaces(text, debug=debug) + self._list = self.parse_cisco_interfaces(text, result_type=CiscoIOSInterface, debug=debug) + elif result_type is CiscoIOSInterface: + self._list = self.parse_cisco_interfaces(text, result_type=CiscoIOSInterface, debug=debug) + elif result_type is CiscoIOSXRInterface: + self._list = self.parse_cisco_interfaces(text, result_type=CiscoIOSXRInterface, debug=debug) elif result_type is int: self._list = self.parse_integers(text, debug=debug) elif result_type is float: @@ -4939,7 +4943,7 @@ def parse_integers(self, text, debug=False): def parse_strings(self, text, debug=False): """Parse text input to CiscoRange(), such as CiscoRange('1-5,7', result_type=None). '1-5,7 will be parsed. By default, CiscoIOSInterface() instances are used when CiscoRange(result_type=None) is parsed.' An error is raised if the CiscoRange() cannot be parsed""" self.result_type = str - return self.parse_cisco_interfaces(text=text, debug=debug) + return self.parse_cisco_interfaces(text=text, result_type=self.result_type, debug=debug) # This method is on CiscoRange() @logger.catch(reraise=True) @@ -4949,12 +4953,19 @@ def parse_floats(self, text, debug=False): # This method is on CiscoRange() @logger.catch(reraise=True) - def parse_cisco_interfaces(self, text, debug=False): + def parse_cisco_interfaces(self, text, result_type, debug=False): """Parse text input to CiscoRange(), such as CiscoRange('Eth1/1-5,7', result_type=None). 'Eth1/1-5,7 will be parsed. By default, CiscoIOSInterface() objects are used when CiscoRange(result_type=None) is parsed.' An error is raised if the CiscoRange() cannot be parsed""" self.result_type = None range_str = "" expanded_interfaces = [] csv_parts = text.split(",") + + if result_type is CiscoIOSXRInterface: + _result_type = CiscoIOSXRInterface + else: + # Default to CiscoIOSInterface for **everything else** + _result_type = CiscoIOSInterface + for idx, _csv_part in enumerate(csv_parts): if debug is True: @@ -4966,9 +4977,9 @@ def parse_cisco_interfaces(self, text, debug=False): ################################################################## if idx == 0: # Set the begin_obj... - begin_obj = CiscoIOSInterface(_csv_part.split("-")[0], debug=debug) + begin_obj = _result_type(_csv_part.split("-")[0]) self.begin_obj = begin_obj - self.this_obj = CiscoIOSInterface(interface_dict=begin_obj.as_dict()) + self.this_obj = _result_type(interface_dict=begin_obj.as_dict(), debug=debug) intf_dict = begin_obj.as_dict() ############################################################## @@ -4984,7 +4995,7 @@ def parse_cisco_interfaces(self, text, debug=False): # Rebuild begin_obj with the interface_class if isinstance(_interface_class, str): intf_dict["interface_class"] = _interface_class - begin_obj = CiscoIOSInterface(interface_dict=intf_dict) + begin_obj = _result_type(interface_dict=intf_dict) self.begin_obj = begin_obj ################################################################## @@ -5011,15 +5022,15 @@ def parse_cisco_interfaces(self, text, debug=False): if idx > 0: if self.iterate_attribute == 'channel' and isinstance(begin_obj.channel, int): - self.this_obj.channel = CiscoIOSInterface(_csv_part.split("-")[0].strip(), debug=debug).channel + self.this_obj.channel = _result_type(_csv_part.split("-")[0].strip(), debug=debug).channel elif self.iterate_attribute == 'subinterface' and isinstance(begin_obj.subinterface, int): - self.this_obj.subinterface = CiscoIOSInterface(_csv_part.split("-")[0].strip(), debug=debug).subinterface + self.this_obj.subinterface = _result_type(_csv_part.split("-")[0].strip(), debug=debug).subinterface elif self.iterate_attribute == 'port' and isinstance(begin_obj.port, int): - self.this_obj.port = CiscoIOSInterface(_csv_part.split("-")[0].strip(), debug=debug).port + self.this_obj.port = _result_type(_csv_part.split("-")[0].strip(), debug=debug).port elif self.iterate_attribute == 'card' and isinstance(begin_obj.card, int): - self.this_obj.card = CiscoIOSInterface(_csv_part.split("-")[0].strip(), debug=debug).card + self.this_obj.card = _result_type(_csv_part.split("-")[0].strip(), debug=debug).card elif self.iterate_attribute == 'slot' and isinstance(begin_obj.card, int): - self.this_obj.slot = CiscoIOSInterface(_csv_part.split("-")[0].strip(), debug=debug).slot + self.this_obj.slot = _result_type(_csv_part.split("-")[0].strip(), debug=debug).slot else: raise NotImplementedError() @@ -5042,7 +5053,7 @@ def parse_cisco_interfaces(self, text, debug=False): if "-" in _csv_part: if len(_csv_part.split("-")) == 2: # Append a whole range of interfaces... - obj = CiscoIOSInterface(_csv_part.split("-")[0].strip(), debug=debug) + obj = _result_type(_csv_part.split("-")[0].strip(), debug=debug) begin_ordinal = getattr(obj, self.iterate_attribute) # parse end_ordinal from 'Eth1/2-4 multipoint' # ref: https://stackoverflow.com/a/1450900 @@ -5276,6 +5287,31 @@ def __setitem__(self, ii, val): else: return self._list[ii] + def __add__(self, other): + if isinstance(other, CiscoRange): + self._list.extend(other._list) + self._list = sorted(set(self._list)) + return self + else: + error = f'`{other}` must be a CiscoRange() instance; the received argument was {type(other)} instead of a CiscoRange()' + logger.error(error) + raise InvalidCiscoRange(error) + + def __sub__(self, other): + if isinstance(other, CiscoRange): + for ii in other._list: + try: + self._list.remove(ii) + except ValueError: + # Skip the item if it does not exist... + pass + return self + else: + error = f'`{other}` must be a CiscoRange() instance; the received argument was {type(other)} instead of a CiscoRange()' + logger.error(error) + raise InvalidCiscoRange(error) + + # This method is on CiscoRange() @logger.catch(reraise=True) def attribute_sort(self, target_list=None, attribute="sort_list", reverse=False): @@ -5291,8 +5327,8 @@ def attribute_sort(self, target_list=None, attribute="sort_list", reverse=False) else: if len(target_list) > 0: if isinstance(target_list, list): - if isinstance(target_list[0], CiscoIOSInterface): - # Sort CiscoIOSInterface() members + if isinstance(target_list[0], (CiscoIOSInterface, CiscoIOSXRInterface)): + # Sort CiscoIOSInterface() or CiscoIOSXRInterface members new_list = sorted(target_list, key=lambda x: getattr(x, attribute), reverse=reverse) elif isinstance(target_list[0], (int, float)): # Sort int or float members @@ -5398,8 +5434,11 @@ def remove(self, arg, ignore_errors=False, debug=False): logger.error(error) raise MismatchedType(error) elif result_type is None: - # These should be CiscoIOSInterface() types... - new_list = [ii for ii in list_before if ii != arg] + # These are CiscoIOSInterface() or CiscoIOSXRInterface() + new_list = [CiscoIOSInterface(ii) for ii in list_before if ii != arg] + elif isinstance(result_type, (CiscoIOSInterface, CiscoIOSXRInterface)): + # These are CiscoIOSInterface() or CiscoIOSXRInterface() + new_list = [result_type(ii) for ii in list_before if ii != arg] else: try: new_list = [result_type(ii) for ii in list_before if result_type(ii) != result_type(arg)] @@ -5461,6 +5500,8 @@ def as_list(self, result_type="auto"): return set() elif result_type is None: return [CiscoIOSInterface(ii) for ii in retval] + elif isinstance(result_type, (CiscoIOSInterface, CiscoIOSXRInterface)): + return [result_type(ii) for ii in retval] elif result_type is str: return [str(ii) for ii in retval] elif result_type is int: @@ -5468,7 +5509,7 @@ def as_list(self, result_type="auto"): elif result_type is float: return [float(ii) for ii in retval] else: - error = f"CiscoRange().as_list(result_type={result_type}) is not valid. Choose from {['auto', None, int, str, float]}. result_type: None will return CiscoIOSInterface() objects." + error = f"CiscoRange().as_list(result_type={result_type}) is not valid. Choose from {['auto', None, int, str, float, CiscoIOSInterface, CiscoIOSXRInterface]}. result_type: None will return CiscoIOSInterface() objects." logger.critical(error) raise ValueError(error) except AttributeError as eee: @@ -5492,6 +5533,8 @@ def as_set(self, result_type="auto"): return list() elif result_type is None: return set([CiscoIOSInterface(ii) for ii in retval]) + elif isinstance(result_type, (CiscoIOSInterface, CiscoIOSXRInterface)): + return set([result_type(ii) for ii in retval]) elif result_type is str: return set([str(ii) for ii in retval]) elif result_type is int: @@ -5522,10 +5565,10 @@ def as_compressed_str(self, debug=False): retval = list() # Handle CiscoIOSInterface() instances... - if self.member_type is CiscoIOSInterface: + if isinstance(self.member_type, (CiscoIOSInterface, CiscoIOSXRInterface)): # Build a magic attribute dict so we can intelligently prepend slot/card/port/etc... magic_string = "3141592653591892234109876543212345678" - this_obj = CiscoIOSInterface(self.text.split(",")[0]) + this_obj = self.member_type(self.text.split(",")[0]) magic_dict = this_obj.as_dict() for attr_name in ("channel", "subinterface", "port", "card", "slot",): if magic_dict[attr_name] is not None: @@ -5533,17 +5576,17 @@ def as_compressed_str(self, debug=False): magic_dict[attr_name] = int(magic_string) break if debug is True: - logger.info(f"CiscoRange() calling CiscoIOSInterface(interface_dict={magic_dict}).as_compressed_str()") - obj = CiscoIOSInterface(interface_dict=magic_dict, debug=debug) + logger.info(f"CiscoRange() calling {self.member_type}(interface_dict={magic_dict}).as_compressed_str()") + obj = self.member_type(interface_dict=magic_dict, debug=debug) if debug is True: - logger.success(f" CiscoRange() call to CiscoIOSInterface().as_compressed_str() with `interface_dict` parameter succeeded") + logger.success(f" CiscoRange() call to {self.member_type}().as_compressed_str() with `interface_dict` parameter succeeded") prefix_str = str(obj).replace(magic_string, "") prefix_str_len = len(prefix_str) # Build a list of the relevant string iteration pieces... input_str = [] for _, component in enumerate(self.as_list()): - input_str.append(getattr(CiscoIOSInterface(component), self.iterate_attribute)) + input_str.append(getattr(self.member_type(component), self.iterate_attribute)) # Handle str() instances... elif self.member_type is str: prefix_str = "" diff --git a/ciscoconfparse/ciscoconfparse.py b/ciscoconfparse/ciscoconfparse.py index adb334d..1feaa42 100644 --- a/ciscoconfparse/ciscoconfparse.py +++ b/ciscoconfparse/ciscoconfparse.py @@ -166,6 +166,10 @@ "junos", ) +ALL_BRACE_SYNTAX = { + "junos", +} + @logger.catch(reraise=True) def get_version_number(): @@ -1338,11 +1342,7 @@ def find_interface_objects(self, intfspec, exactmatch=True): raise ValueError(err_text) retval = list() - if self.syntax in ( - "ios", - "nxos", - "iosxr", - ): + if self.syntax not in ALL_BRACE_SYNTAX: if exactmatch is True: for obj in self.find_objects("^interface"): if intfspec.lower() in obj.abbvs: @@ -3661,14 +3661,7 @@ def sync_diff( continue if remove_lines is True and action == "remove": - if _syntax in set( - { - "ios", - "nxos", - "iosxr", - "asa", - } - ): + if _syntax not in ALL_BRACE_SYNTAX: uu = re.search(uncfgspec, command) remove_cmd = indent * " " + "no " + uu.group(0).strip() # 'no no ' will become ''... @@ -5506,7 +5499,7 @@ def bootstrap_obj_init_ng(self, text_list=None, debug=0): # # Build the banner_re regexp... at this point ios # and nxos share the same method... - if syntax=="ios" or syntax=="nxos" or syntax=="iosxr": + if syntax not in ALL_BRACE_SYNTAX: banner_re = self._build_banner_re_ios() self._banner_mark_regex(banner_re) diff --git a/ciscoconfparse/models_cisco.py b/ciscoconfparse/models_cisco.py index 5d3b7f9..9dbe4aa 100644 --- a/ciscoconfparse/models_cisco.py +++ b/ciscoconfparse/models_cisco.py @@ -2197,132 +2197,125 @@ def trunk_vlans_allowed(self): return 0 + _all_vlans = "1-4094" + _max_number_vlans = 4094 # Default to allow allow all vlans... - vdict = {"allowed": "1-4094"} + vdict = { + "allowed": _all_vlans, + "add": None, + "except": None, + "remove": None, + } ## 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}" + if obj.text.split()[0:5] == ["switchport", "trunk", "allowed", "vlan", "add"]: + 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["add"] is None: + vdict["add"] = add_str + else: + vdict["add"] += f",{add_str}" + + elif obj.text.split()[0:5] == ["switchport", "trunk", "allowed", "vlan", "except"]: + 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["except"] is None: + vdict["except"] = exc_str + else: + vdict["except"] += f",{exc_str}" + + elif obj.text.split()[0:5] == ["switchport", "trunk", "allowed", "vlan", "remove"]: + 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["remove"] is None: + vdict["remove"] = rem_str + else: + vdict["remove"] += f",{rem_str}" + + elif obj.text.split()[0:4] == ["switchport", "trunk", "allowed", "vlan"]: + ## 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 allowed_str == "none": + # Replace the default allow of 1-4094... + vdict["allowed"] = "" + elif allowed_str == "all": + # Specify an initial list of vlans... + vdict["allowed"] = _all_vlans + else: + # handle **double allowed** statements here... + if vdict["allowed"] == _all_vlans: + vdict["allowed"] = f"{allowed_str}" + elif vdict["allowed"] == "": + vdict["allowed"] = f"{allowed_str}" + else: + vdict["allowed"] += f",{allowed_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: + if isinstance(vdict["allowed"], str): + if vdict["allowed"] == _all_vlans: + if len(retval) != _max_number_vlans: retval = CiscoRange(f"1-{MAX_VLAN}", result_type=int) - elif vdict.get("allowed") == "none": + elif vdict["allowed"] == "": retval = CiscoRange(result_type=int) - elif vdict.get("allowed") != "_nomatch_": + elif vdict["allowed"] != "_nomatch_": retval = CiscoRange(vdict["allowed"], result_type=int) - for key, _value in vdict.items(): - _value = _value.strip() + print("----") + for key in ["allowed", "add", "except", "remove"]: + _value = vdict[key] + print(f"KEY: {key}, VALUE: {_value}") + + if isinstance(_value, str): + _value = _value.strip() + elif _value is None: + # There is nothing to be done if _value is None... + continue + if _value == "": continue elif _value != "_nomatch_": ## allowed in the key overrides previous values if key=="allowed": + # When considering 'allowed', reset retval to be empty... 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) + elif isinstance(re.search(r"^\d[\d\-\,\s]*", _value), re.Match): + retval = retval + CiscoRange(_value, result_type=int) 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) + retval = retval + CiscoRange(_value, result_type=int) + elif key == "except" or key == "remove": + retval = retval - CiscoRange(_value, result_type=int) else: error = f"{key} is an invalid Cisco switched dot1q ethernet trunk action." logger.error(error) diff --git a/tests/test_Ccp_Util.py b/tests/test_Ccp_Util.py index cbba4d4..fc9099f 100755 --- a/tests/test_Ccp_Util.py +++ b/tests/test_Ccp_Util.py @@ -44,7 +44,8 @@ from ciscoconfparse.ccp_util import dns_lookup, reverse_dns_lookup, collapse_addresses from ciscoconfparse.ccp_util import IPv6Obj, IPv4Obj, L4Object, ip_factory from ciscoconfparse.ccp_util import _RGX_IPV4ADDR, _RGX_IPV6ADDR -from ciscoconfparse.ccp_util import CiscoIOSInterface, CiscoRange +from ciscoconfparse.ccp_util import CiscoIOSInterface, CiscoIOSXRInterface +from ciscoconfparse.ccp_util import CiscoRange import pytest from loguru import logger @@ -814,7 +815,7 @@ def test_CiscoRange_06(): uut_str = "1/1-3,4,5" # the CiscoRange() result_type None is a CiscoIOSInterface() type with a # port attribute... - assert CiscoRange(uut_str, result_type=None).as_set(result_type=str) == result_correct + assert CiscoRange(uut_str, result_type=CiscoIOSInterface).as_set(result_type=str) == result_correct assert CiscoRange(uut_str).iterate_attribute == "port" diff --git a/tests/test_Models_Cisco.py b/tests/test_Models_Cisco.py index 7a6d062..8e49399 100755 --- a/tests/test_Models_Cisco.py +++ b/tests/test_Models_Cisco.py @@ -315,7 +315,7 @@ def testVal_IOSIntfLine_trunk_vlan_allowed_03(): def testVal_IOSIntfLine_trunk_vlan_allowed_04(): - lines = [ + lines_01 = [ "!", "interface GigabitEthernet 1/1", " switchport mode trunk", @@ -324,9 +324,10 @@ def testVal_IOSIntfLine_trunk_vlan_allowed_04(): " switchport trunk native vlan 911", "!", ] - cfg = CiscoConfParse(lines, factory=True) - intf_obj = cfg.find_objects("^interface")[0] - assert intf_obj.trunk_vlans_allowed.as_set(result_type=int) == {1} + cfg_01 = CiscoConfParse(lines_01, factory=True) + intf_obj = cfg_01.find_objects("^interface")[0] + vlans_allowed_set = intf_obj.trunk_vlans_allowed.as_set(result_type=int) + assert vlans_allowed_set == {1} def testVal_IOSIntfLine_trunk_vlan_allowed_05(): @@ -334,14 +335,14 @@ def testVal_IOSIntfLine_trunk_vlan_allowed_05(): "!", "interface GigabitEthernet 1/1", " switchport mode trunk", - " switchport trunk allowed vlan all", - " switchport trunk allowed vlan except 2-4094", + " switchport trunk allowed vlan 2,4,6,911", + " switchport trunk allowed vlan except 2,4,6", " switchport trunk native vlan 911", "!", ] cfg = CiscoConfParse(lines, factory=True) intf_obj = cfg.find_objects("^interface")[0] - assert intf_obj.trunk_vlans_allowed.as_set(result_type=int) == {1,} + assert intf_obj.trunk_vlans_allowed.as_set(result_type=int) == {911,} def testVal_IOSIntfLine_trunk_vlan_allowed_06(): @@ -367,14 +368,13 @@ def testVal_IOSIntfLine_trunk_vlan_allowed_07(): switchport mode trunk switchport trunk allowed vlan none switchport trunk allowed vlan add 1-20 - ! except 1 implicitly allows vlans 2-4094 on the trunk switchport trunk allowed vlan except 1 switchport trunk allowed vlan remove 20 ! """ cfg = CiscoConfParse(config.splitlines(), factory=True) intf_obj = cfg.find_objects("^interface")[0] - assert intf_obj.trunk_vlans_allowed == CiscoRange("2-19,21-4094", result_type=int) + assert intf_obj.trunk_vlans_allowed == CiscoRange("2-19", result_type=int) def testVal_IOSIntfLine_trunk_vlan_allowed_08():