From 5f71a5b8a8cf221fcb350003f13b753c89939b93 Mon Sep 17 00:00:00 2001 From: David Barroso Date: Sat, 4 Feb 2017 18:04:30 -0800 Subject: [PATCH] Adapted to more general API (#135) * Replace list() with [] and dict() with {} I don't like them anymore :( * Various improvements for get_route_to Also fix #109 * Version 0.5.3 * empty inactive_reason rather than None * Consistent expected output as well * Group neighbors without peer-group under the '_' key Painful stuff here. @itdependsnetworks owes me a beer for that :D * Fix previously wrong mock * Remove too generic Exception * Testcase for #119 * Adapted to more general API * Adding napalm-yang to requirements * Renaming file so py.test doesn't try to run it as a test --- napalm_eos/eos.py | 202 +++++++++--------- .../parsers/interfaces.yaml} | 6 + .../translators/interfaces.yaml} | 0 oc_example.py | 72 +++++++ oc_test.py | 49 ----- requirements.txt | 1 + setup.py | 2 +- .../expected_result.json | 66 ++++++ ...w_running_config___section_router_bgp.text | 18 ++ .../normal/expected_result.json | 2 +- .../normal/expected_result.json | 2 +- 11 files changed, 271 insertions(+), 149 deletions(-) rename napalm_eos/{openconfig_mappings.yaml => yang_mappings/parsers/interfaces.yaml} (95%) rename napalm_eos/{openconfig_translation.yaml => yang_mappings/translators/interfaces.yaml} (100%) create mode 100644 oc_example.py delete mode 100644 oc_test.py create mode 100644 test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/expected_result.json create mode 100644 test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/show_running_config___section_router_bgp.text diff --git a/napalm_eos/eos.py b/napalm_eos/eos.py index a615c62..1cf9a36 100644 --- a/napalm_eos/eos.py +++ b/napalm_eos/eos.py @@ -128,7 +128,7 @@ def _load_config(self, filename=None, config=None, replace=True): else: self.config_session = 'napalm_{}'.format(datetime.now().microsecond) - commands = list() + commands = [] commands.append('configure session {}'.format(self.config_session)) if replace: @@ -183,7 +183,7 @@ def compare_config(self): def commit_config(self): """Implementation of NAPALM method commit_config.""" - commands = list() + commands = [] commands.append('copy startup-config flash:rollback-0') commands.append('configure session {}'.format(self.config_session)) commands.append('commit') @@ -195,7 +195,7 @@ def commit_config(self): def discard_config(self): """Implementation of NAPALM method discard_config.""" if self.config_session is not None: - commands = list() + commands = [] commands.append('configure session {}'.format(self.config_session)) commands.append('abort') self.device.run_commands(commands) @@ -203,7 +203,7 @@ def discard_config(self): def rollback(self): """Implementation of NAPALM method rollback.""" - commands = list() + commands = [] commands.append('configure replace flash:rollback-0') commands.append('write memory') self.device.run_commands(commands) @@ -238,14 +238,14 @@ def get_facts(self): } def get_interfaces(self): - commands = list() + commands = [] commands.append('show interfaces') output = self.device.run_commands(commands)[0] - interfaces = dict() + interfaces = {} for interface, values in output['interfaces'].items(): - interfaces[interface] = dict() + interfaces[interface] = {} if values['lineProtocolStatus'] == 'up': interfaces[interface]['is_up'] = True @@ -268,15 +268,15 @@ def get_interfaces(self): return interfaces def get_lldp_neighbors(self): - commands = list() + commands = [] commands.append('show lldp neighbors') output = self.device.run_commands(commands)[0]['lldpNeighbors'] - lldp = dict() + lldp = {} for n in output: if n['port'] not in lldp.keys(): - lldp[n['port']] = list() + lldp[n['port']] = [] lldp[n['port']].append( { @@ -329,7 +329,7 @@ def get_re_group(res, key, default=None): ['show ip ' + NEIGHBOR_FILTER, 'show ipv6 ' + NEIGHBOR_FILTER], encoding='text') - bgp_counters = defaultdict(lambda: dict(peers=dict())) + bgp_counters = defaultdict(lambda: dict(peers={})) for summary in output_summary_cmds: """ Json output looks as follows @@ -497,13 +497,13 @@ def extract_temperature_data(data): def get_lldp_neighbors_detail(self, interface=''): - lldp_neighbors_out = dict() + lldp_neighbors_out = {} - filters = list() + filters = [] if interface: filters.append(interface) - commands = list() + commands = [] commands.append( 'show lldp neighbors {filters} detail'.format( filters=' '.join(filters) @@ -522,7 +522,7 @@ def get_lldp_neighbors_detail(self, interface=''): # it is provided a list of neighbors per interface for neighbor in interface_neighbors: if interface not in lldp_neighbors_out.keys(): - lldp_neighbors_out[interface] = list() + lldp_neighbors_out[interface] = [] capabilities = neighbor.get('systemCapabilities') capabilities_list = list(capabilities.keys()) capabilities_list.sort() @@ -545,7 +545,7 @@ def get_lldp_neighbors_detail(self, interface=''): return lldp_neighbors_out def cli(self, commands): - cli_output = dict() + cli_output = {} if type(commands) is not list: raise TypeError('Please enter a valid list of commands!') @@ -632,10 +632,36 @@ def get_bgp_config(self, group='', neighbor=''): list: [] } + def default_group_dict(local_as): + group_dict = {} + group_dict.update({ + key: _DATATYPE_DEFAULT_.get(_PROPERTY_TYPE_MAP_.get(prop)) + for prop, key in _GROUP_FIELD_MAP_.items() + }) + group_dict.update({ + 'prefix_limit': {}, + 'neighbors': {}, + 'local_as': local_as + }) # few more default values + return group_dict + + def default_neighbor_dict(local_as): + neighbor_dict = {} + neighbor_dict.update({ + key: _DATATYPE_DEFAULT_.get(_PROPERTY_TYPE_MAP_.get(prop)) + for prop, key in _PEER_FIELD_MAP_.items() + }) # populating with default values + neighbor_dict.update({ + 'prefix_limit': {}, + 'local_as': local_as, + 'authentication_key': u'' + }) # few more default values + return neighbor_dict + def parse_options(options, default_value=False): if not options: - return dict() + return {} config_property = options[0] field_name = _PROPERTY_FIELD_MAP_.get(config_property) @@ -644,11 +670,13 @@ def parse_options(options, default_value=False): if not field_type: # no type specified at all => return empty dictionary - return dict() + return {} if not default_value: if len(options) > 1: - field_value = field_type(options[1]) + field_value = napalm_base.helpers.convert(field_type, + options[1], + _DATATYPE_DEFAULT_.get(field_type)) else: if field_type is bool: field_value = True @@ -673,22 +701,22 @@ def parse_options(options, default_value=False): field_name = 'export_policy' return {field_name: field_value} - return dict() + return {} - bgp_config = dict() + bgp_config = {} - commands = list() + commands = [] commands.append('show running-config | section router bgp') bgp_conf = self.device.run_commands(commands, encoding='text')[0].get('output', '\n\n') - bgp_conf_lines = bgp_conf.splitlines()[2:] + bgp_conf_lines = bgp_conf.splitlines() - bgp_neighbors = dict() + bgp_neighbors = {} if not group: - neighbor = '' + neighbor = '' # noqa - last_peer_group = '' local_as = 0 + bgp_neighbors = {} for bgp_conf_line in bgp_conf_lines: default_value = False bgp_conf_line = bgp_conf_line.strip() @@ -711,18 +739,10 @@ def parse_options(options, default_value=False): IPAddress(group_or_neighbor) # if passes the test => it is an IP Address, thus a Neighbor! peer_address = group_or_neighbor - + if peer_address not in bgp_neighbors: + bgp_neighbors[peer_address] = default_neighbor_dict(local_as) if options[0] == 'peer-group': - last_peer_group = options[1] - - # if looking for a specific group - if group and last_peer_group != group: - continue - - # or even more. a specific neighbor within a group - if neighbor and peer_address != neighbor: - continue - # skip all other except the target + bgp_neighbors[peer_address]['__group'] = options[1] # in the config, neighbor details are lister after # the group is specified for the neighbor: @@ -736,20 +756,8 @@ def parse_options(options, default_value=False): # that way we avoid one more loop to # match the neighbors with the group they belong to # directly will apend the neighbor in the neighbor list of the group at the end - if last_peer_group not in bgp_neighbors.keys(): - bgp_neighbors[last_peer_group] = dict() - if peer_address not in bgp_neighbors[last_peer_group]: - bgp_neighbors[last_peer_group][peer_address] = dict() - bgp_neighbors[last_peer_group][peer_address].update({ - key: _DATATYPE_DEFAULT_.get(_PROPERTY_TYPE_MAP_.get(prop)) - for prop, key in _PEER_FIELD_MAP_.items() - }) # populating with default values - bgp_neighbors[last_peer_group][peer_address].update({ - 'prefix_limit': {}, - 'local_as': local_as, - 'authentication_key': u'' - }) # few more default values - bgp_neighbors[last_peer_group][peer_address].update( + + bgp_neighbors[peer_address].update( parse_options(options, default_value) ) except AddrFormatError: @@ -759,33 +767,24 @@ def parse_options(options, default_value=False): if group and group_name != group: continue if group_name not in bgp_config.keys(): - bgp_config[group_name] = dict() - bgp_config[group_name].update({ - key: _DATATYPE_DEFAULT_.get(_PROPERTY_TYPE_MAP_.get(prop)) - for prop, key in _GROUP_FIELD_MAP_.items() - }) - bgp_config[group_name].update({ - 'prefix_limit': {}, - 'neighbors': {}, - 'local_as': local_as - }) # few more default values + bgp_config[group_name] = default_group_dict(local_as) bgp_config[group_name].update( parse_options(options, default_value) ) - except Exception: - # for other kind of exception pass to next line - continue - for group, peers in bgp_neighbors.items(): - if group not in bgp_config.keys(): - continue - bgp_config[group]['neighbors'] = peers + for peer, peer_details in bgp_neighbors.items(): + peer_group = peer_details.pop('__group', None) + if not peer_group: + peer_group = '_' + if peer_group not in bgp_config: + bgp_config[peer_group] = default_group_dict(local_as) + bgp_config[peer_group]['neighbors'][peer] = peer_details return bgp_config def get_arp_table(self): - arp_table = list() + arp_table = [] commands = ['show arp'] @@ -822,7 +821,7 @@ def get_ntp_servers(self): for ntp_peer in ntp_config if ntp_peer.get('ntppeer', '')} def get_ntp_stats(self): - ntp_stats = list() + ntp_stats = [] REGEX = ( '^\s?(\+|\*|x|-)?([a-zA-Z0-9\.+-:]+)' @@ -832,7 +831,7 @@ def get_ntp_stats(self): '\s+([0-9\.]+)\s?$' ) - commands = list() + commands = [] commands.append('show ntp associations') # output = self.device.run_commands(commands) @@ -869,7 +868,7 @@ def get_ntp_stats(self): def get_interfaces_ip(self): - interfaces_ip = dict() + interfaces_ip = {} interfaces_ipv4_out = self.device.run_commands(['show ip interface'])[0]['interfaces'] try: @@ -881,14 +880,14 @@ def get_interfaces_ip(self): raise for interface_name, interface_details in interfaces_ipv4_out.items(): - ipv4_list = list() + ipv4_list = [] if interface_name not in interfaces_ip.keys(): - interfaces_ip[interface_name] = dict() + interfaces_ip[interface_name] = {} if u'ipv4' not in interfaces_ip.get(interface_name): - interfaces_ip[interface_name][u'ipv4'] = dict() + interfaces_ip[interface_name][u'ipv4'] = {} if u'ipv6' not in interfaces_ip.get(interface_name): - interfaces_ip[interface_name][u'ipv6'] = dict() + interfaces_ip[interface_name][u'ipv6'] = {} iface_details = interface_details.get('interfaceAddress', {}) if iface_details.get('primaryIp', {}).get('address') != '0.0.0.0': @@ -916,14 +915,14 @@ def get_interfaces_ip(self): } for interface_name, interface_details in interfaces_ipv6_out.items(): - ipv6_list = list() + ipv6_list = [] if interface_name not in interfaces_ip.keys(): - interfaces_ip[interface_name] = dict() + interfaces_ip[interface_name] = {} if u'ipv4' not in interfaces_ip.get(interface_name): - interfaces_ip[interface_name][u'ipv4'] = dict() + interfaces_ip[interface_name][u'ipv4'] = {} if u'ipv6' not in interfaces_ip.get(interface_name): - interfaces_ip[interface_name][u'ipv6'] = dict() + interfaces_ip[interface_name][u'ipv6'] = {} ipv6_list.append( { @@ -954,7 +953,7 @@ def get_interfaces_ip(self): def get_mac_address_table(self): - mac_table = list() + mac_table = [] commands = ['show mac address-table'] @@ -987,7 +986,7 @@ def get_mac_address_table(self): return mac_table def get_route_to(self, destination='', protocol=''): - routes = dict() + routes = {} if protocol.lower() == 'direct': protocol = 'connected' @@ -1014,13 +1013,13 @@ def get_route_to(self, destination='', protocol=''): for prefix, route_details in routes_out.items(): if prefix not in routes.keys(): - routes[prefix] = list() - route_protocol = route_details.get('routeType').upper() + routes[prefix] = [] + route_protocol = route_details.get('routeType') preference = route_details.get('preference', 0) route = { - 'current_active': False, - 'last_active': False, + 'current_active': True, + 'last_active': True, 'age': 0, 'next_hop': u'', 'protocol': route_protocol, @@ -1028,10 +1027,14 @@ def get_route_to(self, destination='', protocol=''): 'preference': preference, 'inactive_reason': u'', 'routing_table': u'default', - 'selected_next_hop': False, + 'selected_next_hop': True, 'protocol_attributes': {} } - if protocol == 'bgp': + if protocol == 'bgp' or route_protocol.lower() in ('ebgp', 'ibgp'): + nexthop_interface_map = {} + for next_hop in route_details.get('vias'): + nexthop_ip = napalm_base.helpers.ip(next_hop.get('nexthopAddr')) + nexthop_interface_map[nexthop_ip] = next_hop.get('interface') metric = route_details.get('metric') command = 'show ip{ipv} bgp {destination} detail'.format( ipv=ipv, @@ -1054,10 +1057,13 @@ def get_route_to(self, destination='', protocol=''): last_active = active_route # should find smth better communities = bgp_route_details.get('routeDetail', {}).get('communityList', []) preference2 = bgp_route_details.get('weight') + inactive_reason = bgp_route_details.get('reasonNotBestpath', '') bgp_route.update({ 'current_active': active_route, + 'inactive_reason': inactive_reason, 'last_active': last_active, 'next_hop': next_hop, + 'outgoing_interface': nexthop_interface_map.get(next_hop), 'selected_next_hop': active_route, 'protocol_attributes': { 'metric': metric, @@ -1072,6 +1078,11 @@ def get_route_to(self, destination='', protocol=''): }) routes[prefix].append(bgp_route) else: + if route_details.get('routeAction') in ('drop',): + route['next_hop'] = 'NULL' + if route_details.get('routingDisabled') is True: + route['last_active'] = False + route['current_active'] = False for next_hop in route_details.get('vias'): route_next_hop = route.copy() if next_hop.get('nexthopAddr') is None: @@ -1089,7 +1100,8 @@ def get_route_to(self, destination='', protocol=''): } ) routes[prefix].append(route_next_hop) - + if route_details.get('vias') == []: # empty list + routes[prefix].append(route) return routes def get_snmp_information(self): @@ -1139,7 +1151,7 @@ def _sshkey_type(sshkey): return u'ssh_dsa', py23_compat.text_type(sshkey) return u'ssh_rsa', u'' - users = dict() + users = {} commands = ['show user-account'] user_items = self.device.run_commands(commands)[0].get('users', {}) @@ -1521,15 +1533,15 @@ def get_network_instances(self, name=''): raw_output = self.device.run_commands(commands, encoding='text')[0].get('output', '') output = napalm_base.helpers.textfsm_extractor(self, 'vrf', raw_output) - vrfs = dict() - all_vrf_interfaces = dict() + vrfs = {} + all_vrf_interfaces = {} for vrf in output: if (vrf.get('route_distinguisher', '') == "" or vrf.get('route_distinguisher', '') == 'None'): vrf['route_distinguisher'] = u'' else: vrf['route_distinguisher'] = py23_compat.text_type(vrf['route_distinguisher']) - interfaces = dict() + interfaces = {} for interface_raw in vrf.get('interfaces', []): interface = interface_raw.split(',') for line in interface: @@ -1631,7 +1643,3 @@ def ping(self, destination, source=c.PING_SOURCE, ttl=c.PING_TTL, timeout=c.PING }) ping_dict['success'].update({'results': results_array}) return ping_dict - - def _oc_all_config(self): - return self.device.run_commands(["show running-config all"], - encoding="text")[0]["output"] diff --git a/napalm_eos/openconfig_mappings.yaml b/napalm_eos/yang_mappings/parsers/interfaces.yaml similarity index 95% rename from napalm_eos/openconfig_mappings.yaml rename to napalm_eos/yang_mappings/parsers/interfaces.yaml index 1d5d79b..09d94f3 100644 --- a/napalm_eos/openconfig_mappings.yaml +++ b/napalm_eos/yang_mappings/parsers/interfaces.yaml @@ -1,4 +1,10 @@ --- +_model: napalm_yang.oc_if.Interfaces() +_execute: + config: + cli: + - show running-config all + interfaces: interface: _block_capture: "(?Pinterface (?P(Ethernet|Management|Loopback|Port-Channel)\\d+)\n(?:.|\n)*?^!$)" diff --git a/napalm_eos/openconfig_translation.yaml b/napalm_eos/yang_mappings/translators/interfaces.yaml similarity index 100% rename from napalm_eos/openconfig_translation.yaml rename to napalm_eos/yang_mappings/translators/interfaces.yaml diff --git a/oc_example.py b/oc_example.py new file mode 100644 index 0000000..ed440b2 --- /dev/null +++ b/oc_example.py @@ -0,0 +1,72 @@ +from napalm_eos.eos import EOSDriver + +import napalm_yang + +import pprint + + +eos_configuration = { + 'hostname': '127.0.0.1', + 'username': 'vagrant', + 'password': 'vagrant', + 'optional_args': {'port': 12443} +} + + +d = EOSDriver(**eos_configuration) +d.open() + +# Get current interfaces configuration +running = d.parse_config("interfaces") + +# Print the exact model as defined by OC +# This is mostly informative, as quick reference +print(running.model_to_text()) + +# We can get a representation of the data in text +print(running.data_to_text()) + +# Or as a dict +pprint.pprint(running.data_to_dict()) + +# We can also translate the object backto native configuration +print(d.translate_model(running, "interfaces")) + +# Let's change some configuration +candidate = d.parse_config("interfaces") +candidate.interfaces.interface["Management1"].config.description("Connected to oob1:et2") +candidate.interfaces.interface["Ethernet2"].config.description("Connected to spine") +candidate.interfaces.interface["Port-Channel1"].config.description("Connected to blah") +candidate.interfaces.interface["Loopback1"].config.enabled(False) + +# Let's create a new loopback interface +candidate.interfaces.interface.new_element("Loopback0") +candidate.interfaces.interface["Loopback0"].name("Loopback0") +candidate.interfaces.interface["Loopback0"].config.name("Loopback0") +candidate.interfaces.interface["Loopback0"].config.description("loopback0") +candidate.interfaces.interface["Loopback0"].config.enabled(True) +candidate.interfaces.interface["Loopback0"].config.mtu(1500) +candidate.interfaces.interface["Loopback0"].hold_time.config.up(0) +candidate.interfaces.interface["Loopback0"].hold_time.config.down(0) +candidate.interfaces.interface["Loopback0"].config.type_(napalm_yang.ianaift.Softwareloopback) + +# Let's see a diff of the running and the candidate configuration +pprint.pprint(running.diff(candidate)) + +# Let's turn this into native configuration +new_config = d.translate_model(candidate, "interfaces") +print(new_config) + + +# Load it into the device +d.load_merge_candidate(config=new_config) + +# See the diff matches our expectations +print(d.compare_config()) + +# Let's commit the configuration now +d.commit_config() + +# if now get a new running and candidate config, let's compare it with out previous candidate +running = d.parse_config("interfaces") +pprint.pprint(running.diff(candidate)) diff --git a/oc_test.py b/oc_test.py deleted file mode 100644 index eaf0597..0000000 --- a/oc_test.py +++ /dev/null @@ -1,49 +0,0 @@ -from napalm_eos.eos import EOSDriver - - -def print_data(name, data, indentation=""): - meta = data["_meta"] - mode = "rw" if meta["config"] else "ro" - key = "* [{}]".format(meta.get("key", "")) if meta.get("key", "") else "" - print("{}+-- {} {}{}".format(indentation, mode, name, key)) - indentation = indentation + "| " - - for attr, attr_data in data.items(): - if attr == "_meta": - continue - elif attr == "list": - for e, d in attr_data.items(): - print_data(e, d, indentation) - elif "value" in attr_data.keys(): - sm = attr_data["_meta"] - - if sm["type"] == "Enumeration": - try: - value = "{} ({})".format(attr_data["value"], attr_data["enum_value"]) - except: - raise Exception(attr_data) - else: - value = attr_data["value"] - - mandatory = "" if sm["mandatory"] else "?" - body = "{}+-- {} {}{}".format(indentation, mode, attr, mandatory) - spacing = " " * (60 - len(body)) - print("{}{}{}".format(body, spacing, value)) - else: - print_data(attr, attr_data, indentation) - - -eos_configuration = { - 'hostname': '127.0.0.1', - 'username': 'vagrant', - 'password': 'vagrant', - 'optional_args': {'port': 12443} -} - - -d = EOSDriver(**eos_configuration) -d.open() -d.oc_populate_interfaces() -print_data("interfaces", d.interfaces.data_representation()) -print("==========") -print(d.translate_yang_model(d.interfaces)) diff --git a/requirements.txt b/requirements.txt index d0a46f6..33bf86c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ napalm_base>=0.19.0 pyeapi +-e git+https://github.com/napalm-automation/napalm-yang.git@develop#egg=napalm-yang diff --git a/setup.py b/setup.py index b7223b4..1e38e59 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="napalm-eos", - version="0.5.2", + version="0.5.3", packages=find_packages(), author="David Barroso, Mircea Ulinic", author_email="dbarrosop@dravetech.com, mircea@cloudflare.com", diff --git a/test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/expected_result.json b/test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/expected_result.json new file mode 100644 index 0000000..295fde3 --- /dev/null +++ b/test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/expected_result.json @@ -0,0 +1,66 @@ +{ + "_": { + "multipath": false, + "multihop_ttl": 0, + "apply_groups": [], + "export_policy": "", + "import_policy": "", + "remove_private_as": false, + "local_as": 13335, + "local_address": "", + "type": "", + "remote_as": 0, + "prefix_limit": {}, + "description": "", + "neighbors": { + "192.168.0.1": { + "route_reflector_client": false, + "nhs": false, + "authentication_key": "", + "export_policy": "export-policy", + "import_policy": "import-policy", + "local_as": 13335, + "local_address": "", + "remote_as": 32934, + "prefix_limit": {}, + "description": "" + }, + "2001:db8::0:1": { + "route_reflector_client": false, + "nhs": false, + "authentication_key": "", + "export_policy": "export-policy", + "import_policy": "import-policy", + "local_as": 13335, + "local_address": "", + "remote_as": 8403, + "prefix_limit": {}, + "description": "" + }, + "172.17.17.1": { + "route_reflector_client": false, + "nhs": false, + "authentication_key": "", + "export_policy": "export-policy", + "import_policy": "import-policy", + "local_as": 13335, + "local_address": "", + "remote_as": 13414, + "prefix_limit": {}, + "description": "" + }, + "2001:db8::0:2": { + "route_reflector_client": false, + "nhs": false, + "authentication_key": "", + "export_policy": "export-policy", + "import_policy": "import-policy", + "local_as": 13335, + "local_address": "", + "remote_as": 54113, + "prefix_limit": {}, + "description": "" + } + } + } +} diff --git a/test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/show_running_config___section_router_bgp.text b/test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/show_running_config___section_router_bgp.text new file mode 100644 index 0000000..9d8540f --- /dev/null +++ b/test/unit/mocked_data/test_get_bgp_config/iss199_bgp_neighbors_without_peer_group/show_running_config___section_router_bgp.text @@ -0,0 +1,18 @@ +router bgp 13335 + maximum-paths 32 + neighbor 192.168.0.1 remote-as 32934 + neighbor 192.168.0.1 maximum-routes 100 + neighbor 192.168.0.1 route-map import-policy in + neighbor 192.168.0.1 route-map export-policy out + neighbor 172.17.17.1 remote-as 13414 + neighbor 172.17.17.1 maximum-routes 500 + neighbor 172.17.17.1 route-map import-policy in + neighbor 172.17.17.1 route-map export-policy out + neighbor 2001:db8::0:1 remote-as 8403 + neighbor 2001:db8::0:1 maximum-routes 500 + neighbor 2001:db8::0:1 route-map import-policy in + neighbor 2001:db8::0:1 route-map export-policy out + neighbor 2001:db8::0:2 remote-as 54113 + neighbor 2001:db8::0:2 route-map import-policy in + neighbor 2001:db8::0:2 route-map export-policy out +! diff --git a/test/unit/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/unit/mocked_data/test_get_bgp_config/normal/expected_result.json index eb4367c..de52578 100644 --- a/test/unit/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/unit/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1 +1 @@ -{"IPv6-PEERS-GROUP-NAME": {"neighbors": {"2001:db8::0:2": {"export_policy": "", "prefix_limit": {}, "import_policy": "", "local_as": 0, "route_reflector_client": false, "nhs": false, "local_address": "", "remote_as": 54113, "authentication_key": "", "description": ""}, "2001:db8::0:1": {"export_policy": "", "prefix_limit": {}, "import_policy": "", "local_as": 0, "route_reflector_client": false, "nhs": false, "local_address": "", "remote_as": 8403, "authentication_key": "", "description": ""}}, "export_policy": "reject-all", "multipath": false, "prefix_limit": {}, "import_policy": "reject-all", "local_as": 0, "multihop_ttl": 0, "apply_groups": [], "remote_as": 0, "remove_private_as": true, "local_address": "", "type": "", "description": ""}, "IPv4-PEERS-GROUP-NAME": {"neighbors": {"192.168.0.1": {"export_policy": "", "prefix_limit": {}, "import_policy": "", "local_as": 0, "route_reflector_client": false, "nhs": false, "local_address": "", "remote_as": 32934, "authentication_key": "", "description": ""}, "172.17.17.1": {"export_policy": "", "prefix_limit": {}, "import_policy": "", "local_as": 0, "route_reflector_client": false, "nhs": false, "local_address": "", "remote_as": 13414, "authentication_key": "", "description": ""}}, "export_policy": "4-public-peer-anycast-out", "multipath": false, "prefix_limit": {}, "import_policy": "reject-all", "local_as": 0, "multihop_ttl": 0, "apply_groups": [], "remote_as": 0, "remove_private_as": true, "local_address": "", "type": "", "description": ""}} +{"IPv4-PEERS-GROUP-NAME": {"local_address": "", "description": "", "type": "", "local_as": 13335, "apply_groups": [], "multihop_ttl": 0, "remove_private_as": true, "remote_as": 0, "import_policy": "reject-all", "export_policy": "4-public-peer-anycast-out", "neighbors": {"172.17.17.1": {"local_address": "", "authentication_key": "", "description": "", "nhs": false, "local_as": 13335, "route_reflector_client": false, "remote_as": 13414, "import_policy": "", "export_policy": "", "prefix_limit": {}}, "192.168.0.1": {"local_address": "", "authentication_key": "", "description": "", "nhs": false, "local_as": 13335, "route_reflector_client": false, "remote_as": 32934, "import_policy": "", "export_policy": "", "prefix_limit": {}}}, "prefix_limit": {}, "multipath": false}, "IPv6-PEERS-GROUP-NAME": {"local_address": "", "description": "", "type": "", "local_as": 13335, "apply_groups": [], "multihop_ttl": 0, "remove_private_as": true, "remote_as": 0, "import_policy": "reject-all", "export_policy": "reject-all", "neighbors": {"2001:db8::0:2": {"local_address": "", "authentication_key": "", "description": "", "nhs": false, "local_as": 13335, "route_reflector_client": false, "remote_as": 54113, "import_policy": "", "export_policy": "", "prefix_limit": {}}, "2001:db8::0:1": {"local_address": "", "authentication_key": "", "description": "", "nhs": false, "local_as": 13335, "route_reflector_client": false, "remote_as": 8403, "import_policy": "", "export_policy": "", "prefix_limit": {}}}, "prefix_limit": {}, "multipath": false}} diff --git a/test/unit/mocked_data/test_get_route_to/normal/expected_result.json b/test/unit/mocked_data/test_get_route_to/normal/expected_result.json index 3b112ad..c67e70a 100644 --- a/test/unit/mocked_data/test_get_route_to/normal/expected_result.json +++ b/test/unit/mocked_data/test_get_route_to/normal/expected_result.json @@ -1 +1 @@ -{"1.0.4.0/24": [{"protocol": "EBGP", "inactive_reason": "", "last_active": true, "age": 0, "routing_table": "default", "next_hop": "192.168.0.1", "outgoing_interface": "", "preference": 200, "current_active": true, "selected_next_hop": true, "protocol_attributes": {"local_preference": 50, "remote_as": 43515, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "preference2": 0, "metric": 0, "local_as": 13335, "as_path": "1299 15169 43515", "remote_address": "192.168.0.1"}}]} +{"1.0.4.0/24": [{"next_hop": "192.168.0.1", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "default", "protocol_attributes": {"remote_as": 43515, "as_path": "1299 15169 43515", "local_preference": 50, "remote_address": "192.168.0.1", "preference2": 0, "metric": 0, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "local_as": 13335}, "outgoing_interface": "Port-Channel2", "last_active": true, "inactive_reason": "", "age": 0}]}