def get_ospf_segment_routing_lb_srlb_base_and_range(device, process_id, router_id): """ Gets 'SRLB Base' and 'SRLB Range' values Args: device ('obj'): Device to use process_id ('str'): Ospf process_id router_id ('str'): Which router_id entry to use Returns: if can filter down to one result: (('int'): SRLB Base value, ('dict'): Output from parser) Raises: None """ try: output = device.parse("show ip ospf segment-routing local-block") except SchemaEmptyParserError: return None, None reqs_base = R([ "instance", process_id, "areas", "(?P<area>.*)", "router_id", router_id, "srlb_base", "(?P<srlb_base>.*)", ]) found_base = find(output, reqs_base, filter_=False, all_keys=True) if not found_base: return None, None reqs_range = R([ "instance", process_id, "areas", "(?P<area>.*)", "router_id", router_id, "srlb_range", "(?P<srlb_range>.*)", ]) found_range = find(output, reqs_range, filter_=False, all_keys=True) if not found_range: return None, None return found_base[0][0], found_range[0][0]
def get_ospf_router_id(device, vrf, address_family, instance): """ Returns router-id for ospf Args: device ('obj'): device to run on vrf ('str'): vrf name address_family ('str'): address family instance ('str'): instance value Returns: str: single router id None: if empty Raises: None """ try: out = device.parse("show ip protocols") except (SchemaEmptyParserError): return None reqs = R([ 'protocols', 'ospf', 'vrf', vrf, 'address_family', address_family, 'instance', instance, 'router_id', '(?P<router_id>.*)' ]) found = find([out], reqs, filter_=False, all_keys=True) if not found: return None key_list = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) return key_list.pop()['router_id']
def find_value(self, ops, values, r, path, **kwargs): # get the values for group_keys for key in values: sub_key = list(values[key].keys())[0] if sub_key: values = values[key] else: values = {key: values[key][sub_key]} keys = [] # find required info from ops obj for r_obj in r: ret = find([ops], r_obj, filter_=False) if not ret: # Could not find anything satisfying return {} ret = GroupKeys.group_keys(ret_num=values, source=ret, reqs=path) # To Modify to support more than 1 conf object key = {} for v in values: if v not in ret[0]: raise Exception("'{v} could not be found in previously " "learnt keys".format(v=v)) key[v] = ret[0][v] keys.append(key) # TODO: To modify for multiple conf object return keys return keys
def get_hardware_slot_state(device, slot): """ Get slot state Args: device (`obj`): Device object slot (`str`): Slot Returns: state (`str`): Slot state None Raises: None """ log.info("Getting slot {} state on device {}".format(slot, device.name)) try: out = device.parse("show platform") except SchemaEmptyParserError: return None reqs = R([ "slot", str(slot), "(?P<type>.*)", "(?P<name>.*)", "state", "(?P<state>.*)", ]) found = find([out], reqs, filter_=False, all_keys=True) if found: keys = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) return keys[0]["state"] else: return None
def _verify_finds_root_interface(ops, requirements, **kwargs): '''Triggers in this file specified verify method. This is to check only 1 interface change to root after change the priority to highest ''' log.info(banner("check only One interface change to root for each vlan")) ret = find([ops], R(requirements), filter_=False) if not ret: raise Exception( 'There is no Root interfaces after changing the priority') group_keys = GroupKeys.group_keys(reqs=[requirements], ret_num={}, source=ret) vlan_dict = {} for item in group_keys: vlan_dict.setdefault(item['vlan'], {}).setdefault(item['interface'], {}) for vlan in vlan_dict: if len(vlan_dict[vlan].keys()) != 1: raise Exception( 'Expect ONE Root interface for vlan {v} but got {i}'.format( v=vlan, i=list(vlan_dict[vlan].keys()))) else: log.info('Find ONE ROOT interface {i} for vlan {v}'.format(i=list( vlan_dict[vlan].keys())[0], v=vlan))
def _modify_ops_snapshot(self, original, current, path): # First does path exists in original, except the value r = R(path[:-1] + ['(.*)']) ret = find([original], r, filter_=False) if not ret: raise Exception("'{p}' does not exists on original " "snapshot".format(p=path)) self._modify_value(current, path[:-1], ret[0][0])
def check_issu_state(cls, device, slot, expected_state, attempt=3, sleep=5): ''' Check if the ISSU state is in the expected state Args: device (`obj`): Device Object. expected_state (`str`): Acceptable ISSU states are: - loadversion - runversion - acceptversion - commitversion slot (`str`): Slot for which we need to check ISSU state attempt (`int`): Attempt numbers when learn the feature. sleep (`int`): The sleep time. Returns: None Raises: AssertionError: 'expected_state' is not as expected Exception: Cannot parse 'show issu state detail' output No output form 'show issu state detail' Unable to execute 'show issu state detail' Example: >>> check_issu_state(device=uut, slot='R1', expected_state='commitversion') ''' assert expected_state in [ 'loadversion', 'runversion', 'acceptversion', 'commitversion' ] lookup = Lookup.from_device(device) for i in range(attempt): try: issu_dict = lookup.parser.show_issu.\ ShowIssuStateDetail(device=device).parse() rs = R(['slot', slot, 'last_operation', expected_state]) ret = find([issu_dict], rs, filter_=False, all_keys=True) if ret: break except SchemaEmptyParserError as e: raise Exception( "No output or unable to parse 'show issu state " "detail'", from_exception=e) except Exception as e: raise Exception("Unable to execute 'show issu state detail'", from_exception=e) time.sleep(sleep) else: raise AssertionError("FAIL: ISSU state not '{}' - this is " "unexpected".format(expected_state))
def _modify_ops_snapshot(original, current, path): # First does path exists in original, except the value r = R(path[:-1] + ['(.*)']) ret = find([original], r, filter_=False) if not ret: raise ValueError( "'{p}' does not exist on original snapshot " "as per the original trigger requirement".format(p=path)) _modify_value(current, path[:-1], ret[0][0])
def check_parsed_key(self, key, output, step): keys = str_to_list(key) with step.start("Verify that '{k}' is in the " "output".format(k=key)) as step: reqs = R(list(keys)) found = find([output], reqs, filter_=False, all_keys=True) if not found: step.failed("Could not find '{k}'".format(k=key)) else: log.info("Found {f}".format(f=found))
def check_feature_status(cls, device, expect, feature_name, abstract, attempt=3, sleep=5): ''' Check if the feature is disabled/enabled Args: device (`obj`): Device Object. abstract (`obj`): Abstract Lookup Object. expect (`str`): Feature status. Only accept 'disabled' and 'enabled' feature_name (`str`): Feature namne. sleep_time (`int`): The sleep time. attempt (`int`): Attempt numbers when learn the feature. Returns: None Raises: AssertionError: 'expect' is not 'disabled' or 'enabled' Or the status is not same as expect value SyntaxError: Cannot parse show feature output Example: >>> check_feature_status(device=uut, expect='disabled', feature_name='bgp',abstract=abstract) ''' assert expect in ['disabled', 'enabled'] for i in range(attempt): try: ret = abstract.parser.show_feature.ShowFeature(device=device) ret = ret.parse() except Exception as e: raise SyntaxError("Cannot parse command 'show " "feature'") from e ret = find([ret], R([ 'feature', feature_name, 'instance', '(.*)', 'state', expect ]), filter_=False) if ret: break time.sleep(sleep) else: raise AssertionError('{n} is failed to {s}'.format(n=feature_name, s=expect))
def get_ospf_interfaces_with_neighbor(ops, neighbor): '''Get OSPF interfaces by given neighbor''' # find the neighbors on uut connected to the helper device reqs = [[ 'info', 'vrf', '(?P<vrf>.*)', 'address_family', '(?P<af>.*)', 'instance', '(?P<instance>.*)', 'areas', '(?P<areas>.*)', 'interfaces', '(?P<interfaces>.*)', 'neighbors', neighbor, '(?P<neighbors_info>.*)' ]] rs_uut = [R(i) for i in reqs] ret_uut = find([ops], *rs_uut, filter_=False) return GroupKeys.group_keys(ret_num={}, source=ret_uut, reqs=reqs)
def get_hardware_rp_slot(device, state="standby", max_time=90, check_interval=30): """ Get RP slot from device Args: device (`obj`): Device object state (`str`): RP state max_time (`int`): max wait time check_interval (`int`): check interval Returns: result (`str`): RP slot in required state None Raises: None """ log.info("Finding {st} RP on device {dev}".format(st=state, dev=device.name)) reqs = R([ "slot", "(?P<slot>.*)", "(?P<type>.*)", "(?P<name>.*)", "state", "(?P<state>.*)", ]) timeout = Timeout(max_time, check_interval) while timeout.iterate(): try: out = device.parse("show platform") except SchemaEmptyParserError: timeout.sleep() continue found = find([out], reqs, filter_=False, all_keys=True) keys = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) for key in keys: if "R" in key["slot"] and state in key["state"]: log.info( "Found {st} RP {key[name]} on slot {key[slot]}".format( st=state, key=key)) return key["slot"] timeout.sleep() return None
def get_hardware_sfp_slot_dict(device, sfp_descr=".*"): """ Get SFP slot dict Args: device (`obj`): Device object sfp_descr (`str`): SFP descr Returns: sfp_slot_dict (`dict`): SFP slot dict example: { '1/1/6':{'slot': '1', 'subslot': '1 transceiver 6', 'lc': 'ASR1000-SIP10', 'pid': 'SFP-GE-S', 'descr': 'GE SX'}} Raises: None """ log.info("Getting inventory on {}".format(device.name)) keys = [] try: out = device.parse("show inventory") except SchemaEmptyParserError: return keys reqs = R([ "slot", "(?P<slot>.*)", "lc", "(?P<lc>.*)", "subslot", "(?P<subslot>.*)", "(?P<pid>.*)", "descr", "(?P<descr>" + sfp_descr + ")", ]) found = find([out], reqs, filter_=False, all_keys=True) if found: keys = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) sfp_slot_dict = {} p = re.compile(r"(?<=\d)( +\w+ )(?=\d)") for sfp in keys: slot = sfp["slot"] + "/" + re.sub(p, "/", sfp["subslot"]) sfp_slot_dict.update({slot: sfp}) return sfp_slot_dict
def _verify_find(self, ops, requirements, missing=False, all_keys=False, **kwargs): '''Verify the ops response to the requirements''' if not requirements: return rs = [R(requirement) for requirement in requirements] ret = find([ops], *rs, filter_=False, all_keys=all_keys) # If missing is True, then we expect it to be missing, aka ret empty if not ret and not missing: raise Exception("'{req}' does not exists in " "'{o}'".format(req=requirements, o=ops)) if ret and missing: # It should be missing raise Exception("'{req}' exists in " "'{o}' and it should not " "exists".format(req=requirements, o=ops))
def is_type_10_opaque_area_link_states_originated(device): """ Verifies if Type 10 opaque area link states are originated from command 'show ip ospf database opaque-area self-originate' Args: device (`obj`): Device to be executed command Raises: None Returns True False """ try: out = device.parse('show ip ospf database opaque-area self-originate') except (SchemaEmptyParserError): return False reqs = R( [ 'vrf', '(?P<vrf>.*)', 'address_family', '(?P<af>.*)', 'instance', '(?P<instance>.*)', 'areas', '(?P<areas>.*)', 'database', 'lsa_types', '(?P<lsa_types>.*)', 'lsa_type', '(?P<lsa_type>.*)' ] ) found = find([out], reqs, filter_=False, all_keys=True) if not found: return False key_list = GroupKeys.group_keys( reqs=reqs.args, ret_num={}, source=found, all_keys=True ) return key_list.pop()['lsa_type'] == 10
def verify_ntp_synchronized_alias(self, device, alias=None): '''Verify that NTP is synchronized on this device verify NTP is synchronized on device "<device>" ''' ops = self.genie_ops_on_device_alias('ntp', device, alias) rs = [ R([ 'info', 'clock_state', 'system_status', 'associations_address', '(?P<neighbors>.*)' ]) ] output = find([ops], *rs, filter_=False, all_keys=True) if not output: self.builtin.fail( "{} does not have NTP synchronized".format(device))
def is_issu_in_state(device, slot, expected_state, max_time=1200, interval=30): """ Verify if ISSU is in state for a specific slot Args: device ('obj'): Device object slot ('str'): Slot for which we need to check ISSU state expected_state ('str'): Acceptable ISSU states are: - loadversion - runversion - acceptversion - commitversion max_time ('int'): Max time checking issu state interval ('int': Interval checking Raise: None Return True False """ assert expected_state in [ "loadversion", "runversion", "acceptversion", "commitversion", ] rs = R(["slot", slot, "last_operation", expected_state]) timeout = Timeout(max_time=max_time, interval=interval) while timeout.iterate(): try: output = device.parse("show issu state detail") except SchemaEmptyParserError: timeout.sleep() continue ret = find([output], rs, filter_=False, all_keys=True) if ret: return True timeout.sleep() return False
def get_ntp_outgoing_interface(device, system_peer): """ Get the interface which is used to communicate with NTP system peer Args: device (`obj`): Device object system_peer (`str`): System peer ip Returns: interface (`str`): Interface name """ try: out = device.parse("show ip cef {}".format(system_peer)) except SchemaEmptyParserError as e: log.error("Command 'show ip cef {}' " "did not return any results".format(system_peer)) return None reqs = R([ "vrf", "(?P<vrf>.*)", "address_family", "(?P<af>.*)", "prefix", "(?P<ip>.*)", "nexthop", "(?P<nexthop>.*)", "outgoing_interface", "(?P<intf>.*)", "(?:.*)", ]) found = find([out], reqs, filter_=False, all_keys=True) if found: keys = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) else: log.error("No interface was found") return None interface = keys[0]["intf"] return interface
def get_ready_rps_lcs(ops): '''Get ready RPs/LCs from platform ops''' reqs = [ [ 'slot', 'rp', '(?P<rp>.*)', 'state', '(?P<state>ok, active|ok, standby|Ready)' ], # ['slot', 'lc', '(?P<lc>.*)','state', 'ok'], [ 'slot', 'oc', '(?P<oc>.*)', 'state', '(?P<oc_state>ok, active|ok, standby|ok|ps, fail)' ] ] rs = [R(i) for i in reqs] ret = find([ops], *rs, filter_=False, all_keys=True) return GroupKeys.group_keys(ret_num={}, source=ret, reqs=reqs, all_keys=True)
def get_ospf_router_id(device, vrf='(.*)', address_family='(.*)', instance='(.*)'): """ Get ospf router-id - show ip protocols Args: device ('obj'): device to run on vrf ('str'): vrf name address_family ('str'): address family instance ('str'): instance value Returns: str: single router id None: if empty Raises: None """ log.info("Getting OSPF router-id") router_id = None cmd = 'show ip protocols' try: out = device.parse(cmd) except Exception as e: log.error("Failed to parse '{}':\n{}".format(cmd, e)) return router_id reqs = R(['protocols', 'ospf', 'vrf', vrf, 'address_family', address_family, 'instance', instance, 'router_id', '(?P<router_id>.*)']) found = find([out], reqs, filter_=False, all_keys=True) if found: key_list = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) return key_list.pop()['router_id'] else: log.error("No ospf router id was found") return router_id
def is_platform_slot_in_state(device, slot, state="ok, active", max_time=1200, interval=120): """ Verify if slot is in state Args: device ('obj'): Device object slot ('str'): Slot number state ('str'): State being checked max_time ('int'): Max time checking interval ('int'): Interval checking Return: True False Raises: None """ log.info("Verifying state of slot {slot}".format(slot=slot)) timeout = Timeout(max_time=max_time, interval=interval) rs = R(["slot", slot, "rp", "(?P<val2>.*)", "state", state]) while timeout.iterate(): try: output = device.parse("show platform") except SchemaEmptyParserError: timeout.sleep() continue ret = find([output], rs, filter_=False, all_keys=True) if ret: log.info("Slot {slot} reached state '{state}'".format(slot=slot, state=state)) return True timeout.sleep() return False
def get_interface_qlimit_bytes(device, interface): """ Get interface qlimit in bytes Args: device (`obj`): Device object interface (`str`): Interface name Returns: None qlimit_bytes (`int`): Interface qlimit_bytes Raises: None """ try: out = device.parse( "show platform hardware qfp active infrastructure bqs " "queue output default interface {interface}".format( interface=interface)) except SchemaEmptyParserError: return reqs = R([ interface, "index", "(?P<index>.*)", "software_control_info", "qlimit_bytes", "(?P<qlimit>.*)", ]) found = find([out], reqs, filter_=False, all_keys=True) if found: keys = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) return keys[0]["qlimit"] else: return
def get_hardware_all_fans_speed(device): """ Get fan speed for all fans Args: device (`obj`): Device object Returns: fans (`list`): Fans info Raises: None """ fans = [] p = re.compile(r"Fan +Speed +(?P<speed>.*)%") try: out = device.parse("show environment | include Fan") except (SchemaEmptyParserError, SubCommandFailure) as e: return fans reqs = R([ "slot", "(?P<slot>.*)", "sensor", "(?P<sensor>.*)", "state", "(?P<state>.*)", ]) found = find([out], reqs, filter_=False, all_keys=True) if found: fans = GroupKeys.group_keys(reqs=reqs.args, ret_num={}, source=found, all_keys=True) for fan in fans: fan["speed"] = int(p.search(fan["state"]).groupdict()["speed"]) log.info("Found fan on {fan[slot]} with Speed {fan[speed]}%".format( fan=fan)) return fans
def verify_hardware_spa_exist(device, spa, max_time=300, check_interval=30): """ Verify spa exists Args: device (`obj`): Device object spa (`str`): spa slot max_time (`int`): max time check_interval (`int`): check interval Returns: result(`bool`): verify result Raises: None """ slots = spa.split("/") reqs = R([ "slot", slots[0], "(?P<type>.*)", "(?P<name>.*)", "subslot", slots[1], "(?P<sub_dict>.*)", ]) timeout = Timeout(max_time, check_interval) while timeout.iterate(): try: out = device.parse("show platform") except SchemaEmptyParserError: timeout.sleep() continue found = find([out], reqs, filter_=False, all_keys=True) if found: return True timeout.sleep() return False
def get_ospf_router_id(ops): '''Get OSPF router-id from ospf ops''' # Create R object to contain the required interface ops attributes path # find router_id rs_rd_helper = R([ 'info', 'vrf', '(?P<vrf>.*)', 'address_family', '(?P<af>.*)', 'instance', '(?P<instance>.*)', 'router_id', '(?P<router_id>.*)' ]) # use find object to find required interfaces and ip address # returned value is like # [('10.2.2.2', ['info', 'vrf', 'default', 'address_family', 'ipv4', 'instance', '1', 'router_id'])] ret_rd_helper = find([ops], rs_rd_helper, filter_=False) if not ret_rd_helper: return None # call function to get dict of {key: value} ret = GroupKeys.group_keys(ret_num={}, source=ret_rd_helper, reqs=rs_rd_helper.args) # return the values return ret
def verify_ntp_synchronized_server_alias(self, server, device, alias=None): '''Verify that a specific server is the synchronized ntp server verify "1.1.1.1" is synchronized ntp server on device "<device>" ''' ops = self.genie_ops_on_device_alias('ntp', device, alias) rs = [ R([ 'info', 'clock_state', 'system_status', 'associations_address', '(?P<neighbors>.*)' ]) ] output = find([ops], *rs, filter_=False, all_keys=True) if not output: self.builtin.fail( "No synchronized server could be found! Was " "expected '{}' to be synchronized".format(server)) if not output[0][0] == server: self.builtin.fail("Expected synchronized server to be '{}', but " "found '{}'".format(server, output[0][0]))
def get_platform_standby_rp(device, max_time=1200, interval=120): """ Get standby router slot on device Args: device ('obj'): Device object max_time ('int'): Max time in seconds retrieving router information interval ('int'): Interval in seconds retrieving router information Raise: None Return: Integer: Number of RP """ log.info("Getting standby slot") rs = R( ["slot", "(?P<val1>.*)", "rp", "(?P<val2>.*)", "state", "ok, standby"]) timeout = Timeout(max_time=max_time, interval=interval) while timeout.iterate(): try: output = device.parse("show platform") except SchemaEmptyParserError: timeout.sleep() continue ret = find([output], rs, filter_=False, all_keys=True) if ret: standby_rp = ret[0][1][1] srp = re.search("(?P<srp>(\d))", standby_rp).groupdict()["srp"] if srp: log.info("Standby RP on '{dev}' is: '{standby_rp}'".format( dev=device.name, standby_rp=standby_rp)) return srp timeout.sleep() return None
def verify_ops_or_logic(ops, **kwargs): origin_req = [] if not kwargs.get('mapping'): return # poluate the path reqs = kwargs['mapping']._populate_path(kwargs.get('requires', []), ops.device, keys=kwargs['mapping'].keys) # print out message log.info('Check if output match any of following requirements\n{}'\ .format('\n'.join([str(re) for re in reqs]))) # check if one of the requires suite for the ops output for req in kwargs.get('requires', []): # find if requirement matches for current ops req = kwargs['mapping']._populate_path([req], ops.device, keys=kwargs['mapping'].keys) rs = [R(i) for i in req] ret = find([ops], *rs, filter_=False, all_keys=True) if not ret: log.info('Not found requirement:\n{}'.format(req)) continue # update the requires in mapping object to # modify the original ops with right requirement origin_req = kwargs['local_reqs']['list'] origin_req.extend(req) log.info('Found the requirement:\n{}'.format(req)) break else: raise Exception( 'Failed to find match for any of following requirements\n{}'. format('\n'.join([str(re) for re in reqs])))
def get_ospf_interfaces(ops): '''Get OSPF interfaces by given neighbor''' # Create R object to contain the required interface ops attributes path # find any ospf 'up' interface reqs = [[ 'info', 'vrf', '(?P<vrf>.*)', 'address_family', '(?P<af>.*)', 'instance', '(?P<instance>.*)', 'areas', '(?P<areas>.*)', 'interfaces', '(?P<interfaces>.*)', 'state', '(?P<state>(dr|bdr|dr_other|point_to_point))' ], [ 'info', 'vrf', '(?P<vrf>.*)', 'address_family', '(?P<af>.*)', 'instance', '(?P<instance>.*)', 'areas', '(?P<areas>.*)', 'interfaces', '(?P<interfaces>.*)', 'cost', '(?P<cost>.*)' ]] rs = [R(i) for i in reqs] ret = find([ops], *rs, filter_=False, all_keys=True) return GroupKeys.group_keys(ret_num={}, source=ret, reqs=reqs, all_keys=True)
def learn_routing(device, address_family, paths, ops_container=[], ret_container={}): '''Dynamic learn routing information by using the paths that specified, and store the data into dictionary. Args: Mandatory: device (`obj`): Device object address_family (`str`) : Value of address_family, could be ipv4/ipv6 paths (`list`) : Ops paths to look for the desired routing values Optional: ops_container (`list`): Container to store the learned ops, in case multiple learning ret_container (`dict`) : Container to store the learned routes to let parent update on it Returns: None. Instead of returned values, it will store the learned information in the container to let parent update on it. The container values for ret_container looks like below 10.9.1.0/24: { 10.9.1.2: {'R5': {route: 10.9.1.0/24, intf: Vlan99, vrf: default}}, 10.9.1.1: {'R1': {route: 10.9.1.0/24, intf: Vlan99, vrf: default}}, } 10.9.1.0/24: { 10.9.1.2: {'R5': {route: 10.9.1.0/24, intf: GigabitEthernet1/0/4, vrf: test2}}, 10.9.1.1: {'R5': {route: 10.9.1.0/24, intf: Vlan99, vrf: test1}}, } Raises: Exception: Routing ops cannot sucessfully learned ''' log.info(banner("learn routing info on device {}".format(device.name))) # get ip and vrf routing_ops = ops.routing.iosxe.routing.Routing(device) # learn the routing ops try: routing_ops.learn() except Exception as e: raise Exception('cannot learn routing ops: {}'.format(e)) ops_container[device.name] = routing_ops log.info(banner("Get routing groups from device {}".format(device.name))) rs = [R(p) for p in paths] ret = find([routing_ops], *rs, filter_=False, all_keys=True) if ret: groups = GroupKeys.group_keys(reqs=paths, ret_num={}, source=ret, all_keys=True) if groups: # learn interfaces ip if 'ipv4' in address_family: ip_out = ShowIpInterfaceBrief(device).parse() else: ip_out = ShowIpv6Interface(device).parse() for keys in groups: # find interface ip if 'ipv4' in address_family: intf_r = [ R([ 'interface', keys['intf'], 'ip_address', '(?P<ip>.*)' ]) ] else: intf_r = [ R([ keys['intf'], 'ipv6', '(?P<ip_addr>.*)', 'ip', '(?P<ip>.*)' ]), R([ keys['intf'], 'ipv6', '(?P<ip_addr>.*)', NotExists('origin') ]) ] ip = find([ip_out], *intf_r, filter_=False) if ip: ip = ip[0][0] ret_container.setdefault(keys['route'], {}).\ setdefault(ip, {}).update({device.name: keys})