From 4abe545101f47fa20ec1a6da0b81c2b394b819b6 Mon Sep 17 00:00:00 2001 From: Vivek Vashist Date: Wed, 13 Jul 2022 20:00:55 +0930 Subject: [PATCH 01/76] Fix minor typo --- napalm/base/utils/string_parsers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napalm/base/utils/string_parsers.py b/napalm/base/utils/string_parsers.py index c7dd8f376..830ec1d65 100644 --- a/napalm/base/utils/string_parsers.py +++ b/napalm/base/utils/string_parsers.py @@ -50,7 +50,7 @@ def colon_separated_string_to_dict( dictionary[line_data[0].strip()] = None else: raise Exception( - "Something went wrong parsing the colo separated string {}".format(line) + "Something went wrong parsing the colon separated string {}".format(line) ) return dictionary From 1581e3a92058ef3573386434b4defc8b39dd58e9 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 17 Oct 2022 13:52:23 -0700 Subject: [PATCH 02/76] Fix linting --- napalm/base/utils/string_parsers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/napalm/base/utils/string_parsers.py b/napalm/base/utils/string_parsers.py index 830ec1d65..4a029bae1 100644 --- a/napalm/base/utils/string_parsers.py +++ b/napalm/base/utils/string_parsers.py @@ -50,7 +50,9 @@ def colon_separated_string_to_dict( dictionary[line_data[0].strip()] = None else: raise Exception( - "Something went wrong parsing the colon separated string {}".format(line) + "Something went wrong parsing the colon separated string {}".format( + line + ) ) return dictionary From 434cdf1f57adaa5ce8201c40a40bc4d53138cf86 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 17 Oct 2022 13:54:20 -0700 Subject: [PATCH 03/76] Make string a bit more readable --- napalm/base/utils/string_parsers.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/napalm/base/utils/string_parsers.py b/napalm/base/utils/string_parsers.py index 4a029bae1..5e5df5f57 100644 --- a/napalm/base/utils/string_parsers.py +++ b/napalm/base/utils/string_parsers.py @@ -50,9 +50,7 @@ def colon_separated_string_to_dict( dictionary[line_data[0].strip()] = None else: raise Exception( - "Something went wrong parsing the colon separated string {}".format( - line - ) + f"Something went wrong parsing the colon separated string:\n\n{line}" ) return dictionary From 734d5207a38510b519d7a5208d2c12257bc049f7 Mon Sep 17 00:00:00 2001 From: Ludovic Ortega Date: Tue, 25 Oct 2022 00:03:50 +0200 Subject: [PATCH 04/76] [Fix] swap IOS & NXOS-SSH version (#1785) --- docs/support/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/support/index.rst b/docs/support/index.rst index f869f592c..9fa7bd650 100644 --- a/docs/support/index.rst +++ b/docs/support/index.rst @@ -13,7 +13,7 @@ General support matrix ===================== ========== ============= ==================== ================== ============ ============ ============ **Driver Name** eos junos iosxr_netconf iosxr nxos nxos_ssh ios **Structured data** Yes Yes Yes No Yes No No - **Minimum version** 4.15.0F 12.1 7.0 5.1.0 6.1 [#g1]_ 12.4(20)T 6.3.2 + **Minimum version** 4.15.0F 12.1 7.0 5.1.0 6.1 [#g1]_ 6.3.2 12.4(20)T **Backend library** `pyeapi`_ `junos-eznc`_ `ncclient`_ `pyIOSXR`_ `pynxos`_ `netmiko`_ `netmiko`_ **Caveats** :doc:`eos` :doc:`iosxr_netconf` :doc:`nxos` :doc:`nxos` :doc:`ios` ===================== ========== ============= ==================== ================== ============ ============ ============ From 9b66011a4235dcb1982467ee621b9c11c27f6346 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 9 Jan 2023 11:00:03 -0700 Subject: [PATCH 05/76] Fix Netmiko argument processing for EOS-SSH driver (#1750) --- .github/workflows/commit.yaml | 2 +- napalm/eos/eos.py | 100 ++++++++++++++++++++-------------- 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index 508c38172..94de245e9 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -10,7 +10,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.7, 3.8, 3.9, 3.10.0] + python-version: [3.7, 3.8, 3.9, 3.10.9, 3.11] steps: - name: Checkout repository diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index f10290cd6..cb7f025e8 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -33,10 +33,11 @@ # third party libs import pyeapi from pyeapi.eapilib import ConnectionError, EapiConnection -from netmiko import BaseConnection, ConfigInvalidException +from netmiko import ConfigInvalidException # NAPALM base import napalm.base.helpers +from napalm.base.netmiko_helpers import netmiko_args from napalm.base.base import NetworkDriver from napalm.base.utils import string_parsers from napalm.base.exceptions import ( @@ -97,7 +98,8 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) management). * enable_password (True/False): Enable password for privilege elevation * eos_autoComplete (True/False): Allow for shortening of cli commands - * transport (string): pyeapi transport, defaults to eos_transport if set + * transport (string): transport, eos_transport is a fallback for compatibility. + - ssh (uses Netmiko) - socket - http_local - http @@ -123,45 +125,44 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.platform = "eos" self.profile = [self.platform] + self.optional_args = optional_args or {} - self._process_optional_args(optional_args or {}) + self.enablepwd = self.optional_args.pop("enable_password", "") + self.eos_autoComplete = self.optional_args.pop("eos_autoComplete", None) + self.fn0039_config = self.optional_args.pop("eos_fn0039_config", False) - def _process_optional_args(self, optional_args): # Define locking method - self.lock_disable = optional_args.get("lock_disable", False) + self.lock_disable = self.optional_args.pop("lock_disable", False) - self.enablepwd = optional_args.pop("enable_password", "") - self.eos_autoComplete = optional_args.pop("eos_autoComplete", None) # eos_transport is there for backwards compatibility, transport is the preferred method - transport = optional_args.get( - "transport", optional_args.get("eos_transport", "https") + transport = self.optional_args.get( + "transport", self.optional_args.get("eos_transport", "https") ) - self.fn0039_config = optional_args.pop("eos_fn0039_config", False) self.transport = transport + if transport == "ssh": - self.transport_class = "ssh" - init_args = ["port"] + self._process_optional_args_ssh(self.optional_args) else: - # Parse pyeapi transport class - self.transport_class = self._parse_transport(transport) - # ([1:]) to omit self - init_args = inspect.getfullargspec(self.transport_class.__init__)[0][1:] + self._process_optional_args_eapi(self.optional_args) - filter_args = ["host", "username", "password", "timeout", "lock_disable"] + def _process_optional_args_ssh(self, optional_args): + self.transport_class = None + self.netmiko_optional_args = netmiko_args(optional_args) - if transport == "ssh": - self.netmiko_optional_args = { - k: v - for k, v in optional_args.items() - if k in init_args and k not in filter_args - } - else: - init_args.append("enforce_verification") # Not an arg for unknown reason - self.eapi_kwargs = { - k: v - for k, v in optional_args.items() - if k in init_args and k not in filter_args - } + def _process_optional_args_eapi(self, optional_args): + + # Parse pyeapi transport class + self.transport_class = self._parse_transport(self.transport) + + # ([1:]) to omit self + init_args = inspect.getfullargspec(self.transport_class.__init__)[0][1:] + filter_args = ["host", "username", "password", "timeout"] + init_args.append("enforce_verification") # Not an arg for unknown reason + self.eapi_kwargs = { + k: v + for k, v in optional_args.items() + if k in init_args and k not in filter_args + } def _parse_transport(self, transport): if inspect.isclass(transport) and issubclass(transport, EapiConnection): @@ -192,7 +193,8 @@ def open(self): """Implementation of NAPALM method open.""" if self.transport == "ssh": self.device = self._netmiko_open( - "arista_eos", netmiko_optional_args=self.netmiko_optional_args + device_type="arista_eos", + netmiko_optional_args=self.netmiko_optional_args, ) # let's try to determine if we need to use new EOS cli syntax sh_ver = self._run_commands(["show version"]) @@ -205,7 +207,7 @@ def open(self): username=self.username, password=self.password, timeout=self.timeout, - **self.eapi_kwargs + **self.eapi_kwargs, ) if self.device is None: @@ -228,7 +230,7 @@ def open(self): def close(self): """Implementation of NAPALM method close.""" self.discard_config() - if isinstance(self.device, BaseConnection): + if self.transport == "ssh": self._netmiko_close() elif hasattr(self.device.connection, "close") and callable( self.device.connection.close @@ -281,6 +283,27 @@ def _run_commands(self, commands, **kwargs): else: return self.device.run_commands(commands, **kwargs) + def _obtain_lock(self, wait_time=None): + """ + EOS internally creates config sessions when using commit-confirm. + + This can cause issues obtaining the configuration lock: + + cfg-2034--574620864-0 completed + cfg-2034--574620864-1 pending + """ + if wait_time: + start_time = time.time() + while time.time() - start_time < wait_time: + try: + self._lock() + return + except SessionLockedException: + time.sleep(1) + + # One last try + return self._lock() + def _lock(self): sess = self._run_commands(["show configuration sessions"])[0]["sessions"] if [ @@ -384,7 +407,7 @@ def _load_config(self, filename=None, config=None, replace=True): self.config_session = "napalm_{}".format(datetime.now().microsecond) if not self.lock_disable: - self._lock() + self._obtain_lock(wait_time=10) commands = [] commands.append("configure session {}".format(self.config_session)) @@ -520,13 +543,8 @@ def confirm_commit(self): def discard_config(self): """Implementation of NAPALM method discard_config.""" if self.config_session is not None: - commands = ["configure session {}".format(self.config_session), "abort"] - if self.transport == "ssh": - # For some reason when testing with vEOS 4.26.1F this - # doesn't work with the normal wrapper. - self._run_commands(["", commands[0]]) - else: - self.device.run_commands(commands) + commands = [f"configure session {self.config_session} abort"] + self._run_commands(commands, encoding="text") self.config_session = None def rollback(self): From 9606c6e92a8ff258fc1337fc9553407adc3a2b9f Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 16 Feb 2023 15:37:50 -0800 Subject: [PATCH 06/76] Fix ios lldp discovery (rebase) (#1849) Co-authored-by: Carlo Maragno --- napalm/ios/ios.py | 23 ++++++- .../no_mac_support/expected_result.json | 15 ++++ .../no_mac_support/show_lldp_neighbors.txt | 8 +++ .../show_lldp_neighbors_detail.txt | 68 +++++++++++++++++++ 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 6235f5880..6d6f8e540 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -44,6 +44,7 @@ generate_regex_or, sanitize_configs, ) +from netaddr.core import AddrFormatError from napalm.base.netmiko_helpers import netmiko_args # Easier to store these as constants @@ -984,10 +985,26 @@ def get_lldp_neighbors(self): hostname = lldp_entry["remote_system_name"] port = lldp_entry["remote_port"] # Match IOS behaviour of taking remote chassis ID - # When lacking a system name (in show lldp neighbors) + # when lacking a system name (in show lldp neighbors) + + # We can't assume remote_chassis_id or remote_port are MAC Addresses + # See IEEE 802.1AB-2005 and rfc2922, specifically PtopoChassisId if not hostname: - hostname = napalm.base.helpers.mac(lldp_entry["remote_chassis_id"]) - port = napalm.base.helpers.mac(port) + try: + hostname = napalm.base.helpers.mac( + lldp_entry["remote_chassis_id"] + ) + except AddrFormatError: + hostname = lldp_entry["remote_chassis_id"] + + # If port is a mac-address, normalize it. + # The MAC helper library will normalize "15" to "00:00:00:00:00:0F" + if port.count(":") == 5 or port.count("-") == 5 or port.count(".") == 2: + try: + port = napalm.base.helpers.mac(port) + except AddrFormatError: + pass + lldp_dict = {"port": port, "hostname": hostname} lldp[intf_name].append(lldp_dict) diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json new file mode 100644 index 000000000..49bc80227 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json @@ -0,0 +1,15 @@ +{ + "GigabitEthernet9/48": [ + { + "port": "Gi0", + "hostname": "COMPUTER.company.example.com" + } + ] + , + "GigabitEthernet9/8": [ + { + "port": "A1:8B:95:B5:E4:6F", + "hostname": "NICEHOSTNAME" + } + ] +} diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt new file mode 100644 index 000000000..f7074e0d7 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt @@ -0,0 +1,8 @@ + +Capability codes: + (R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device + (W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other + +Device ID Local Intf Hold-time Capability Port ID +ACOMPUTER.company.exGi9/48 120 B Gi0 +NICEHOSTNAME Gi9/8 3601 a18b.95b5.e46f diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt new file mode 100644 index 000000000..5908277d6 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt @@ -0,0 +1,68 @@ +------------------------------------------------ +Local Intf: Gi9/48 +Chassis id: 4a07.d0f3.fbb6 +Port id: Gi0 +Port Description: GigabitEthernet0 +System Name: COMPUTER.company.example.com + +System Description: +Cisco IOS Software, C3600 Software (AP3G2-K9W8-M), Version 15.3(3)JC15, RELEASE SOFTWARE (fc1) +Technical Support: http://www.cisco.com/techsupport +Copyright (c) 1986-2018 by Cisco Systems, Inc. +Compiled Thu 07-Jun-18 16:43 by prod_rel_team + +Time remaining: 95 seconds +System Capabilities: B +Enabled Capabilities: B +Management Addresses: + IP: 10.31.18.65 +Auto Negotiation - supported, enabled +Physical media capabilities: + 1000baseT(FD) + 1000baseT(HD) + 100base-TX(FD) + 100base-TX(HD) + 10base-T(FD) + 10base-T(HD) +Media Attachment Unit type: 30 +Vlan ID: - not advertised +PoE+ Power-via-MDI TLV: + Power Pair: Signal + Power Class: Class 4 + Power Device Type: Type 1 PD + Power Source: PSE + Power Priority: high + Power Requested: 13000 mW + Power Allocated: 13000 mW + +------------------------------------------------ +Local Intf: Gi9/8 +Chassis id: NICEHOSTNAME +Port id: a18b.95b5.e46f +Port Description - not advertised +System Name - not advertised +System Description - not advertised + +Time remaining: 2690 seconds +System Capabilities - not advertised +Enabled Capabilities - not advertised +Management Addresses - not advertised +Auto Negotiation - supported, enabled +Physical media capabilities: + 1000baseT(FD) +Media Attachment Unit type - not advertised +Vlan ID: - not advertised + +MED Information: + + MED Codes: + (NP) Network Policy, (LI) Location Identification + (PS) Power Source Entity, (PD) Power Device + (IN) Inventory + + Inventory information - not advertised + Capabilities: + Device type: Endpoint Class I + Network Policies - not advertised + Power requirements - not advertised + Location - not advertised From 22ae32783884c38c0460dcf541f03120792239b7 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 16 Feb 2023 16:20:39 -0800 Subject: [PATCH 07/76] Pylama was broke and not actually executing pycodestyle (#1850) --- napalm/eos/eos.py | 2 +- setup.cfg | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index cb7f025e8..7187fe368 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -452,7 +452,7 @@ def _load_config(self, filename=None, config=None, replace=True): return None try: - if not any(l == "end" for l in commands): + if not any(cmd == "end" for cmd in commands): commands.append("end") # exit config mode if self.eos_autoComplete is not None: self._run_commands( diff --git a/setup.cfg b/setup.cfg index 272f56d7f..871c4c939 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,11 +5,11 @@ universal = 1 license_file = LICENSE [pylama] -linters = mccabe,pep8,pyflakes +linters = mccabe,pycodestyle,pyflakes ignore = D203,C901,E203 skip = .tox/*,.env/*,.venv/* -[pylama:pep8] +[pylama:pycodestyle] max_line_length = 100 [tool:pytest] From 8b670fec41f02922e77022350d8c2f4a27c3ad80 Mon Sep 17 00:00:00 2001 From: bewing Date: Wed, 15 Mar 2023 11:53:26 -0500 Subject: [PATCH 08/76] remove tox in favor of gh actions/act (#1644) * remove tox in favor of gh actions/act * update testing docs with local testing info --- docs/development/testing_framework.rst | 55 ++++++++++++++++++++------ requirements-dev.txt | 1 - tox.ini | 39 ------------------ 3 files changed, 44 insertions(+), 51 deletions(-) delete mode 100644 tox.ini diff --git a/docs/development/testing_framework.rst b/docs/development/testing_framework.rst index 2b61cc9da..ef5a7ed7f 100644 --- a/docs/development/testing_framework.rst +++ b/docs/development/testing_framework.rst @@ -1,7 +1,7 @@ Testing Framework ----------------- -As napalm consists of multiple drivers and all of them have to provide similar functionality, we have developed a testing framework to provide a consistent test suite for all the drivers. +As NAPALM consists of multiple drivers and all of them have to provide similar functionality, we have developed a testing framework to provide a consistent test suite for all the drivers. Features ________ @@ -42,7 +42,7 @@ By default, the tests are going to be run against mocked data but you can change * ``NAPALM_USERNAME`` * ``NAPALM_PASSWORD`` * ``NAPALM_OPTIONAL_ARGS`` - + Mocking the ``open`` method ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,29 +56,29 @@ Multiple test cases:: (napalm) ➜ napalm-eos git:(test_framework) ✗ ls test/unit/mocked_data/test_get_bgp_neighbors lots_of_peers no_peers normal (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors - ... + ... test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[lots_of_peers] <- ../napalm/napalm.base/test/getters.py PASSED test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[no_peers] <- ../napalm/napalm.base/test/getters.py PASSED test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[normal] <- ../napalm/napalm.base/test/getters.py PASSED - + Missing test cases:: (napalm) ➜ napalm-eos git:(test_framework) ✗ ls test/unit/mocked_data/test_get_bgp_neighbors ls: test/unit/mocked_data/test_get_bgp_neighbors: No such file or directory (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors - ... + ... test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[no_test_case_found] <- ../napalm/napalm.base/test/getters.py FAILED - + ========================================================= FAILURES ========================================================== ___________________________________ TestGetter.test_get_bgp_neighbors[no_test_case_found] ___________________________________ - + cls = , test_case = 'no_test_case_found' - + @functools.wraps(func) def wrapper(cls, test_case): cls.device.device.current_test = func.__name__ cls.device.device.current_test_case = test_case - + try: # This is an ugly, ugly, ugly hack because some python objects don't load # as expected. For example, dicts where integers are strings @@ -87,7 +87,7 @@ Missing test cases:: if test_case == "no_test_case_found": > pytest.fail("No test case for '{}' found".format(func.__name__)) E Failed: No test case for 'test_get_bgp_neighbors' found - + ../napalm/napalm.base/test/getters.py:64: Failed ================================================= 1 failed in 0.12 seconds ================================================== @@ -96,8 +96,41 @@ Method not implemented:: (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_probes_config ... test/unit/test_getters.py::TestGetter::test_get_probes_config[no_test_case_found] <- ../napalm/napalm.base/test/getters.py SKIPPED - + ================================================= 1 skipped in 0.09 seconds ================================================= +Testing Matrix +-------------- + +NAPALM leverages [Github Actions](https://docs.github.com/en/actions) to test and lint code on commits and pull requests. +If you want to test prior to opening a pull request, you can use [nektos/act](https://github.com/nektos/act) and Docker to locally run the tests + +.. code-block:: console + + $ act -j std_tests + [build/std_tests-4] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-3] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-1] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-2] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-5] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-4] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-1] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-3] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-5] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-2] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + + ... + + | --------------------------------------------------------------------- + | TOTAL 9258 1836 80% + | + | ================= 619 passed, 80 skipped, 3 warnings in 19.97s ================= + [build/std_tests-5] ✅ Success - Main Run Tests + [build/std_tests-5] ⭐ Run Post Setup Python 3.11 + [build/std_tests-5] 🐳 docker exec cmd=[node /var/run/act/actions/actions-setup-python@v2/dist/cache-save/index.js] user= workdir= + [build/std_tests-5] ✅ Success - Post Setup Python 3.11 + [build/std_tests-5] 🏁 Job succeeded + + .. _`test_getters.py`: https://github.com/napalm-automation/napalm-eos/blob/a2fc2cf6a98b0851efe4cba907086191b8f1df02/test/unit/test_getters.py .. _`conftest.py`: https://github.com/napalm-automation/napalm-eos/blob/a2fc2cf6a98b0851efe4cba907086191b8f1df02/test/unit/conftest.py diff --git a/requirements-dev.txt b/requirements-dev.txt index c44499733..183e4e88c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,7 +8,6 @@ pytest-json==0.4.0 pyflakes==2.5.0 pylama==8.4.1 mock==4.0.3 -tox==3.25.1 mypy==0.982 types-requests==2.28.0 types-six==1.16.17 diff --git a/tox.ini b/tox.ini deleted file mode 100644 index a6f11697f..000000000 --- a/tox.ini +++ /dev/null @@ -1,39 +0,0 @@ -[tox] -envlist = py3{6,7,8},black,pylama -skip_missing_interpreters = true - -[testenv] -deps = - -rrequirements.txt - -rrequirements-dev.txt -passenv = * - -commands = - py.test --cov=napalm --cov-report term-missing -vs --pylama {posargs} - -[testenv:black] -deps = black==20.8b1 - -basepython = python3.6 -commands = - black --check . - -[testenv:pylama] -deps = - -rrequirements-dev.txt - -basepython = python3.6 -commands = - pylama . - -[testenv:sphinx] -deps = - -rdocs/requirements.txt - -basepython = python3.6 - -commands = - make doctest - -whitelist_externals = - make From 53fc6b9fc18d1d19eebad959682c4f14af44c016 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Mar 2023 18:30:27 -0700 Subject: [PATCH 09/76] Bump types-setuptools from 57.4.18 to 67.5.0.0 (#1860) --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 183e4e88c..6cf55ef80 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,7 +11,7 @@ mock==4.0.3 mypy==0.982 types-requests==2.28.0 types-six==1.16.17 -types-setuptools==57.4.18 +types-setuptools==67.5.0.0 types-PyYAML==6.0.9 ttp==0.9.0 ttp_templates==0.3.0 From 344a01e74452d3e9768fa294e6d79bc51d46eae1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Mar 2023 18:40:04 -0700 Subject: [PATCH 10/76] Bump types-six from 1.16.17 to 1.16.21.6 (#1856) --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 6cf55ef80..278918627 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,7 +10,7 @@ pylama==8.4.1 mock==4.0.3 mypy==0.982 types-requests==2.28.0 -types-six==1.16.17 +types-six==1.16.21.6 types-setuptools==67.5.0.0 types-PyYAML==6.0.9 ttp==0.9.0 From d849a49de6f7447a8742a8af7f708713473cce43 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Mar 2023 18:48:09 -0700 Subject: [PATCH 11/76] Bump types-pyyaml from 6.0.9 to 6.0.12.8 (#1853) --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 278918627..acd331af6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -9,9 +9,9 @@ pyflakes==2.5.0 pylama==8.4.1 mock==4.0.3 mypy==0.982 +types-PyYAML==6.0.12.8 types-requests==2.28.0 types-six==1.16.21.6 types-setuptools==67.5.0.0 -types-PyYAML==6.0.9 ttp==0.9.0 ttp_templates==0.3.0 From a71569df66754427604404ee1bffd96155e89b35 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Mar 2023 19:13:43 -0700 Subject: [PATCH 12/76] Bump ttp-templates from 0.3.0 to 0.3.2 (#1808) --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index acd331af6..ae84ab977 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,4 +14,4 @@ types-requests==2.28.0 types-six==1.16.21.6 types-setuptools==67.5.0.0 ttp==0.9.0 -ttp_templates==0.3.0 +ttp_templates==0.3.2 From 67067e383d990245aecb9c4718224ee8d927f414 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Mar 2023 19:36:20 -0700 Subject: [PATCH 13/76] Bump pytest-cov from 3.0.0 to 4.0.0 (#1779) Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 3.0.0 to 4.0.0. - [Release notes](https://github.com/pytest-dev/pytest-cov/releases) - [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest-cov/compare/v3.0.0...v4.0.0) --- updated-dependencies: - dependency-name: pytest-cov dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index ae84ab977..617cc5d3f 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,7 +3,7 @@ coveralls==3.3.1 ddt==1.5.0 flake8-import-order==0.18.1 pytest==7.1.2 -pytest-cov==3.0.0 +pytest-cov==4.0.0 pytest-json==0.4.0 pyflakes==2.5.0 pylama==8.4.1 From 92b7bab363e44a115a8e49bcf4b022a051d00b7b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 10:18:19 -0700 Subject: [PATCH 14/76] Bump types-requests from 2.28.0 to 2.28.11.15 (#1864) Bumps [types-requests](https://github.com/python/typeshed) from 2.28.0 to 2.28.11.15. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 617cc5d3f..51d90d620 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,7 +10,7 @@ pylama==8.4.1 mock==4.0.3 mypy==0.982 types-PyYAML==6.0.12.8 -types-requests==2.28.0 +types-requests==2.28.11.15 types-six==1.16.21.6 types-setuptools==67.5.0.0 ttp==0.9.0 From 90057c0d1138f5e129b5927cddc1b2e9ddff1a32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 10:54:07 -0700 Subject: [PATCH 15/76] Bump types-six from 1.16.21.6 to 1.16.21.7 (#1865) Bumps [types-six](https://github.com/python/typeshed) from 1.16.21.6 to 1.16.21.7. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-six dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 51d90d620..dfd5ddf20 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -11,7 +11,7 @@ mock==4.0.3 mypy==0.982 types-PyYAML==6.0.12.8 types-requests==2.28.11.15 -types-six==1.16.21.6 +types-six==1.16.21.7 types-setuptools==67.5.0.0 ttp==0.9.0 ttp_templates==0.3.2 From ee32766422b3494ae9afd11160a4b3dde1f271c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 13:01:04 -0700 Subject: [PATCH 16/76] Bump flake8-import-order from 0.18.1 to 0.18.2 (#1867) Bumps [flake8-import-order](https://github.com/PyCQA/flake8-import-order) from 0.18.1 to 0.18.2. - [Release notes](https://github.com/PyCQA/flake8-import-order/releases) - [Changelog](https://github.com/PyCQA/flake8-import-order/blob/master/CHANGELOG.rst) - [Commits](https://github.com/PyCQA/flake8-import-order/compare/0.18.1...0.18.2) --- updated-dependencies: - dependency-name: flake8-import-order dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index dfd5ddf20..524642c3d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,7 +1,7 @@ black==22.6.0 coveralls==3.3.1 ddt==1.5.0 -flake8-import-order==0.18.1 +flake8-import-order==0.18.2 pytest==7.1.2 pytest-cov==4.0.0 pytest-json==0.4.0 From 41322481ecf9b00a147b925c8ab274fda32d3f0e Mon Sep 17 00:00:00 2001 From: Mark Huizer Date: Mon, 20 Mar 2023 21:16:10 +0100 Subject: [PATCH 17/76] add get_network_instances for nxos_ssh, based mostly on nxos version (#1842) --- napalm/nxos_ssh/nxos_ssh.py | 56 +++++++++++++ .../normal/expected_result.json | 36 +++++++++ .../normal/show_vrf_detail___json.txt | 58 ++++++++++++++ .../normal/show_vrf_interface___json.txt | 78 +++++++++++++++++++ 4 files changed, 228 insertions(+) create mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json create mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt create mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index 6c7489014..51aa2c690 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -18,6 +18,7 @@ import ipaddress import re import socket +from collections import defaultdict # import NAPALM Base from napalm.base import helpers @@ -794,6 +795,61 @@ def cli(self, commands, encoding="text"): cli_output[str(command)] = output return cli_output + def get_network_instances(self, name=""): + """ + get_network_instances implementation for NX-OS + """ + + # command 'show vrf detail | json' returns all VRFs with detailed information in JSON format + # format: list of dictionaries with keys such as 'vrf_name' and 'rd' + vrf_table_raw = self._get_command_table( + "show vrf detail | json", "TABLE_vrf", "ROW_vrf" + ) + + # command 'show vrf interface' returns all interfaces including their assigned VRF + # format: list of dictionaries with keys 'if_name', 'vrf_name', 'vrf_id' and 'soo' + intf_table_raw = self._get_command_table( + "show vrf interface | json", "TABLE_if", "ROW_if" + ) + + # create a dictionary with key = 'vrf_name' and value = list of interfaces + vrf_intfs = defaultdict(list) + for intf in intf_table_raw: + vrf_intfs[intf["vrf_name"]].append(str(intf["if_name"])) + + vrfs = {} + for vrf in vrf_table_raw: + vrf_name = str(vrf.get("vrf_name")) + vrfs[vrf_name] = {} + vrfs[vrf_name]["name"] = vrf_name + + # differentiate between VRF type 'DEFAULT_INSTANCE' and 'L3VRF' + if vrf_name == "default": + vrfs[vrf_name]["type"] = "DEFAULT_INSTANCE" + else: + vrfs[vrf_name]["type"] = "L3VRF" + + vrfs[vrf_name]["state"] = {"route_distinguisher": str(vrf.get("rd"))} + + # convert list of interfaces (vrf_intfs[vrf_name]) to expected format + # format = dict with key = interface name and empty values + vrfs[vrf_name]["interfaces"] = {} + vrfs[vrf_name]["interfaces"]["interface"] = dict.fromkeys( + vrf_intfs[vrf_name], {} + ) + + # if name of a specific VRF was passed as an argument + # only return results for this particular VRF + + if name: + if name in vrfs.keys(): + return {str(name): vrfs[name]} + else: + return {} + # else return results for all VRFs + else: + return vrfs + def get_environment(self): """ Get environment facts. diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json new file mode 100644 index 000000000..ca3d2f110 --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json @@ -0,0 +1,36 @@ +{ + "management": { + "name": "management", + "type": "L3VRF", + "state": { + "route_distinguisher": "0:0" + }, + "interfaces": { + "interface": { + "mgmt0": {} + } + } + }, + "default": { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": { + "route_distinguisher": "0:0" + }, + "interfaces": { + "interface": { + "Vlan1": {}, + "Vlan100": {}, + "Vlan101": {}, + "Vlan102": {}, + "Vlan103": {}, + "Vlan104": {}, + "Vlan105": {}, + "loopback1": {}, + "Null0": {}, + "Ethernet1/5": {}, + "Ethernet1/5.1": {} + } + } + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt new file mode 100644 index 000000000..637f62365 --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt @@ -0,0 +1,58 @@ +{ + "TABLE_vrf": { + "ROW_vrf": [ + { + "vrf_name": "default", + "vrf_id": 1, + "vrf_state": "Up", + "vpnid": "unknown", + "rd": "0:0", + "vni": 0, + "max_routes": 0, + "mid_threshold": 0, + "TABLE_tib": { + "ROW_tib": [ + { + "tib_id": 80000001, + "tib_af": "IPv6", + "tib_nonce": 80000001, + "tib_state": "Up" + }, + { + "tib_id": 1, + "tib_af": "IPv4", + "tib_nonce": 1, + "tib_state": "Up" + } + ] + } + }, + { + "vrf_name": "management", + "vrf_id": 2, + "vrf_state": "Up", + "vpnid": "unknown", + "rd": "0:0", + "vni": 0, + "max_routes": 0, + "mid_threshold": 0, + "TABLE_tib": { + "ROW_tib": [ + { + "tib_id": 80000002, + "tib_af": "IPv6", + "tib_nonce": 80000002, + "tib_state": "Up" + }, + { + "tib_id": 2, + "tib_af": "IPv4", + "tib_nonce": 2, + "tib_state": "Up" + } + ] + } + } + ] + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt new file mode 100644 index 000000000..72a325a0d --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt @@ -0,0 +1,78 @@ +{ + "TABLE_if": { + "ROW_if": [ + { + "if_name": "Vlan1", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan100", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan101", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan102", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan103", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan104", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan105", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "loopback1", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Null0", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Ethernet1/5", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Ethernet1/5.1", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "mgmt0", + "vrf_name": "management", + "vrf_id": 2, + "soo": "--" + } + ] + } +} From 4b45fdae802ecb6c9c0ec67979f1a95186abbb93 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 13:24:30 -0700 Subject: [PATCH 18/76] Bump pytest from 7.1.2 to 7.2.2 (#1868) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.1.2 to 7.2.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.1.2...7.2.2) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kirk Byers --- docs/requirements.txt | 2 +- requirements-dev.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index be904df24..96eb8cea6 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,5 +4,5 @@ sphinxcontrib-napoleon==0.7 invoke==1.7.1 jinja2==2.11.3 MarkupSafe==2.0.1 -pytest==7.1.2 +pytest==7.2.2 ansible==4.10.0 diff --git a/requirements-dev.txt b/requirements-dev.txt index 524642c3d..fc6044b93 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,7 +2,7 @@ black==22.6.0 coveralls==3.3.1 ddt==1.5.0 flake8-import-order==0.18.2 -pytest==7.1.2 +pytest==7.2.2 pytest-cov==4.0.0 pytest-json==0.4.0 pyflakes==2.5.0 From e74688f02b17f1b530b1b56604981465e24e401b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 13:42:51 -0700 Subject: [PATCH 19/76] Bump sphinx-rtd-theme from 1.0.0 to 1.2.0 (#1869) Bumps [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) from 1.0.0 to 1.2.0. - [Release notes](https://github.com/readthedocs/sphinx_rtd_theme/releases) - [Changelog](https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst) - [Commits](https://github.com/readthedocs/sphinx_rtd_theme/compare/1.0.0...1.2.0) --- updated-dependencies: - dependency-name: sphinx-rtd-theme dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 96eb8cea6..827820adf 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,5 +1,5 @@ sphinx==1.8.6 -sphinx-rtd-theme==1.0.0 +sphinx-rtd-theme==1.2.0 sphinxcontrib-napoleon==0.7 invoke==1.7.1 jinja2==2.11.3 From d9b35a3de73274c724a502a6a915080b4b888426 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 13:52:34 -0700 Subject: [PATCH 20/76] Bump invoke from 1.7.1 to 2.0.0 (#1870) Bumps [invoke](https://github.com/pyinvoke/invoke) from 1.7.1 to 2.0.0. - [Release notes](https://github.com/pyinvoke/invoke/releases) - [Commits](https://github.com/pyinvoke/invoke/compare/1.7.1...2.0.0) --- updated-dependencies: - dependency-name: invoke dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kirk Byers --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 827820adf..482643959 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,7 +1,7 @@ sphinx==1.8.6 sphinx-rtd-theme==1.2.0 sphinxcontrib-napoleon==0.7 -invoke==1.7.1 +invoke==2.0.0 jinja2==2.11.3 MarkupSafe==2.0.1 pytest==7.2.2 From 458c81dd3cff35d9a72356976c267d52b1536a9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 13:53:07 -0700 Subject: [PATCH 21/76] Bump ddt from 1.5.0 to 1.6.0 (#1871) Bumps [ddt](https://github.com/datadriventests/ddt) from 1.5.0 to 1.6.0. - [Release notes](https://github.com/datadriventests/ddt/releases) - [Commits](https://github.com/datadriventests/ddt/compare/1.5.0...1.6.0) --- updated-dependencies: - dependency-name: ddt dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kirk Byers --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index fc6044b93..c63eb3885 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,6 +1,6 @@ black==22.6.0 coveralls==3.3.1 -ddt==1.5.0 +ddt==1.6.0 flake8-import-order==0.18.2 pytest==7.2.2 pytest-cov==4.0.0 From 2bfee8bf48ae45bfade2a7ae66381f74365fa38d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 13:53:31 -0700 Subject: [PATCH 22/76] Bump mock from 4.0.3 to 5.0.1 (#1872) Bumps [mock](https://github.com/testing-cabal/mock) from 4.0.3 to 5.0.1. - [Release notes](https://github.com/testing-cabal/mock/releases) - [Changelog](https://github.com/testing-cabal/mock/blob/master/CHANGELOG.rst) - [Commits](https://github.com/testing-cabal/mock/compare/4.0.3...5.0.1) --- updated-dependencies: - dependency-name: mock dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kirk Byers --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index c63eb3885..0f526a300 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ pytest-cov==4.0.0 pytest-json==0.4.0 pyflakes==2.5.0 pylama==8.4.1 -mock==4.0.3 +mock==5.0.1 mypy==0.982 types-PyYAML==6.0.12.8 types-requests==2.28.11.15 From b0a5fb082aa2267d555cd809982434352eaffb75 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:13:24 -0700 Subject: [PATCH 23/76] Bump types-setuptools from 67.5.0.0 to 67.6.0.5 (#1873) Bumps [types-setuptools](https://github.com/python/typeshed) from 67.5.0.0 to 67.6.0.5. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-setuptools dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kirk Byers --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 0f526a300..6006eb50b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,6 +12,6 @@ mypy==0.982 types-PyYAML==6.0.12.8 types-requests==2.28.11.15 types-six==1.16.21.7 -types-setuptools==67.5.0.0 +types-setuptools==67.6.0.5 ttp==0.9.0 ttp_templates==0.3.2 From ec2c4edc6e73728617fc502edd713cca88ba2331 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 09:01:40 -0700 Subject: [PATCH 24/76] Bump pyflakes from 2.5.0 to 3.0.1 (#1875) Bumps [pyflakes](https://github.com/PyCQA/pyflakes) from 2.5.0 to 3.0.1. - [Release notes](https://github.com/PyCQA/pyflakes/releases) - [Changelog](https://github.com/PyCQA/pyflakes/blob/main/NEWS.rst) - [Commits](https://github.com/PyCQA/pyflakes/compare/2.5.0...3.0.1) --- updated-dependencies: - dependency-name: pyflakes dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 6006eb50b..8e31b3374 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -5,7 +5,7 @@ flake8-import-order==0.18.2 pytest==7.2.2 pytest-cov==4.0.0 pytest-json==0.4.0 -pyflakes==2.5.0 +pyflakes==3.0.1 pylama==8.4.1 mock==5.0.1 mypy==0.982 From 126486122169c0151bfd44f9a4273caa15675ae1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:17:20 -0700 Subject: [PATCH 25/76] Bump ttp-templates from 0.3.2 to 0.3.4 (#1880) Bumps [ttp-templates](https://github.com/dmulyalin/ttp_templates) from 0.3.2 to 0.3.4. - [Release notes](https://github.com/dmulyalin/ttp_templates/releases) - [Commits](https://github.com/dmulyalin/ttp_templates/compare/0.3.2...0.3.4) --- updated-dependencies: - dependency-name: ttp-templates dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 8e31b3374..5a71c949b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -14,4 +14,4 @@ types-requests==2.28.11.15 types-six==1.16.21.7 types-setuptools==67.6.0.5 ttp==0.9.0 -ttp_templates==0.3.2 +ttp_templates==0.3.4 From 8b46f0878231171bc5ee4e01135b3c304149e28b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:33:24 -0700 Subject: [PATCH 26/76] Bump types-requests from 2.28.11.15 to 2.28.11.16 (#1877) Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11.15 to 2.28.11.16. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 5a71c949b..4139a9281 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,7 +10,7 @@ pylama==8.4.1 mock==5.0.1 mypy==0.982 types-PyYAML==6.0.12.8 -types-requests==2.28.11.15 +types-requests==2.28.11.16 types-six==1.16.21.7 types-setuptools==67.6.0.5 ttp==0.9.0 From 8ecc4de6ee27a20f77558bbeff85a2a10416becd Mon Sep 17 00:00:00 2001 From: bewing Date: Tue, 28 Mar 2023 14:07:45 -0500 Subject: [PATCH 27/76] Update get_bgp_config to clarify return values (#1879) --- napalm/base/base.py | 3 +- napalm/eos/eos.py | 2 + napalm/ios/ios.py | 37 +++---- napalm/iosxr/iosxr.py | 47 +++++---- napalm/iosxr_netconf/iosxr_netconf.py | 46 +++++---- napalm/junos/junos.py | 24 +++++ napalm/junos/utils/junos_views.yml | 9 ++ .../expected_result.json | 15 +++ .../issue_1113_dot_asn/expected_result.json | 15 +++ .../normal/expected_result.json | 98 ++++++++++++++++++- .../expected_result.json | 8 +- .../no_afi/expected_result.json | 4 +- .../normal/expected_result.json | 21 +++- .../peers_without_groups/expected_result.json | 6 +- .../expected_result.json | 12 +-- .../normal/expected_result.json | 23 ++++- .../peers_without_groups/expected_result.json | 6 +- .../normal/expected_result.json | 39 +++++--- ...em____routing_options___configuration_.xml | 7 ++ .../nhs/expected_result.json | 74 +++++++++++++- ...em____routing_options___configuration_.xml | 7 ++ .../normal/expected_result.json | 87 +++++++++++++++- 22 files changed, 495 insertions(+), 95 deletions(-) create mode 100644 test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml diff --git a/napalm/base/base.py b/napalm/base/base.py index 1259f6966..d1dbe0eea 100644 --- a/napalm/base/base.py +++ b/napalm/base/base.py @@ -647,7 +647,8 @@ def get_bgp_config( :param neighbor: Returns the configuration of a specific BGP neighbor. Main dictionary keys represent the group name and the values represent a dictionary having - the keys below. Neighbors which aren't members of a group will be stored in a key named "_": + the keys below. A default group named "_" will contain information regarding global + settings and any neighbors that are not members of a group. * type (string) * description (string) diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 7187fe368..cb182ea8d 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -1187,6 +1187,8 @@ def parse_options(options, default_value=False): bgp_config[group_name] = default_group_dict(local_as) bgp_config[group_name].update(parse_options(options, default_value)) + bgp_config["_"] = default_group_dict(local_as) + for peer, peer_details in bgp_neighbors.items(): peer_group = peer_details.pop("__group", None) if not peer_group: diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 6d6f8e540..682a9a990 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -1531,7 +1531,9 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): r" update-source (\w+)", neighbor_config ) local_as = napalm.base.helpers.regex_find_txt( - r"local-as (\d+)", neighbor_config, default=0 + r"local-as (\d+)", + neighbor_config, + default=bgp_asn, ) password = napalm.base.helpers.regex_find_txt( r"password (?:[0-9] )?([^\']+\')", neighbor_config @@ -1565,29 +1567,28 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): "route_reflector_client": route_reflector_client, } + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("_", {}), + } # Get the peer-group level config for each group for group_name in bgp_group_neighbors.keys(): # If a group is passed in params, only continue on that group if group: if group_name != group: continue - # Default no group if group_name == "_": - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": 0, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("_", {}), - } continue neighbor_config = napalm.base.helpers.netutils_parse_objects( group_name, bgp_config_list @@ -1609,7 +1610,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): r" description ([^\']+)\'", neighbor_config ) local_as = napalm.base.helpers.regex_find_txt( - r"local-as (\d+)", neighbor_config, default=0 + r"local-as (\d+)", neighbor_config, default=bgp_asn ) import_policy = napalm.base.helpers.regex_find_txt( r"route-map ([^\s]+) in", neighbor_config diff --git a/napalm/iosxr/iosxr.py b/napalm/iosxr/iosxr.py index f491addfe..2ef1f6cb4 100644 --- a/napalm/iosxr/iosxr.py +++ b/napalm/iosxr/iosxr.py @@ -987,6 +987,15 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): default" result_tree = ETREE.fromstring(self.device.make_rpc_call(rpc_command)) + bgp_asn = napalm.base.helpers.convert( + int, + napalm.base.helpers.find_txt( + result_tree, + "Get/Configuration/BGP/Instance[1]/InstanceAS/FourByteAS/Naming/AS", + ), + 0, + ) + if not group: neighbor = "" @@ -1010,7 +1019,9 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): int, napalm.base.helpers.find_txt(bgp_neighbor, "RemoteAS/AS_YY"), 0 ) local_as = napalm.base.helpers.convert( - int, napalm.base.helpers.find_txt(bgp_neighbor, "LocalAS/AS_YY"), 0 + int, + napalm.base.helpers.find_txt(bgp_neighbor, "LocalAS/AS_YY"), + bgp_asn, ) af_table = napalm.base.helpers.find_txt( bgp_neighbor, "NeighborAFTable/NeighborAF/Naming/AFName" @@ -1102,7 +1113,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): int, napalm.base.helpers.find_txt(bgp_group, "RemoteAS/AS_YY"), 0 ) local_as = napalm.base.helpers.convert( - int, napalm.base.helpers.find_txt(bgp_group, "LocalAS/AS_YY"), 0 + int, napalm.base.helpers.find_txt(bgp_group, "LocalAS/AS_YY"), bgp_asn ) multihop_ttl = napalm.base.helpers.convert( int, @@ -1164,22 +1175,22 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): } if group and group == group_name: break - if "" in bgp_group_neighbors.keys(): - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": 0, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("", {}), - } + + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("", {}), + } return bgp_config diff --git a/napalm/iosxr_netconf/iosxr_netconf.py b/napalm/iosxr_netconf/iosxr_netconf.py index 3f238a1b0..0640f4c82 100644 --- a/napalm/iosxr_netconf/iosxr_netconf.py +++ b/napalm/iosxr_netconf/iosxr_netconf.py @@ -1369,6 +1369,16 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): if not group: neighbor = "" + bgp_asn = napalm.base.helpers.convert( + int, + self._find_txt( + result_tree, + ".//bgpc:bgp/bgpc:instance/bgpc:instance-as/bgpc:four-byte-as/bgpc:as", + default=0, + namespaces=C.NS, + ), + ) + bgp_group_neighbors = {} bgp_neighbor_xpath = ".//bgpc:bgp/bgpc:instance/bgpc:instance-as/\ bgpc:four-byte-as/bgpc:default-vrf/bgpc:bgp-entity/bgpc:neighbors/bgpc:neighbor" @@ -1430,7 +1440,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): ), 0, ) - local_as = local_as_x * 65536 + local_as_y + local_as = (local_as_x * 65536 + local_as_y) or bgp_asn af_table = self._find_txt( bgp_neighbor, "./bgpc:neighbor-afs/bgpc:neighbor-af/bgpc:af-name", @@ -1597,7 +1607,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): ), 0, ) - local_as = local_as_x * 65536 + local_as_y + local_as = (local_as_x * 65536 + local_as_y) or bgp_asn multihop_ttl = napalm.base.helpers.convert( int, self._find_txt( @@ -1679,22 +1689,22 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): } if group and group == group_name: break - if "" in bgp_group_neighbors.keys(): - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": 0, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("", {}), - } + + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("", {}), + } return bgp_config diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index 8d56b0fbc..fdb96e82d 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -1250,6 +1250,30 @@ def build_prefix_limit(**args): bgp_config = {} + routing_options = junos_views.junos_routing_config_table(self.device) + routing_options.get(options=self.junos_config_options) + + bgp_asn = int( + routing_options.xml.find( + "./routing-options/autonomous-system/as-number" + ).text + ) + + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": {}, + } if group: bgp = junos_views.junos_bgp_config_group_table(self.device) bgp.get(group=group, options=self.junos_config_options) diff --git a/napalm/junos/utils/junos_views.yml b/napalm/junos/utils/junos_views.yml index 5d81ae2fc..3fd60b1f4 100644 --- a/napalm/junos/utils/junos_views.yml +++ b/napalm/junos/utils/junos_views.yml @@ -402,6 +402,15 @@ junos_bgp_config_peers_view: inet6_flow_teardown_timeout_prefix_limit: {family/inet6/flow/prefix-limit/teardown/idle-timeout/timeout: int} inet6_flow_novalidate_prefix_limit: {family/inet6/flow/prefix-limit/no-validate: unicode} +junos_routing_config_table: + get: "routing-options/autonomous-system" + view: junos_routing_config_view + +junos_routing_config_view: + fields: + local_system_as: autonomous-system + + #### #### BGP Neighbors and Routing Tables Stats #### diff --git a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json index 8354f24ba..9a66039c0 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json @@ -1,4 +1,19 @@ { + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 64496, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, "IPv6-PEERS-GROUP-NAME": { "type": "", "multipath": false, diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json index 84f8c3bd8..c6c5353d9 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json @@ -1,4 +1,19 @@ { + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 4266524237, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, "IPv4-PEERS-GROUP-NAME": { "type": "", "multipath": false, diff --git a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json index de52578fe..0d22dfaf6 100644 --- a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1 +1,97 @@ -{"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}} +{ + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 13335, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, + "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/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json index f74d5a593..d6a2343ac 100644 --- a/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json @@ -5,7 +5,7 @@ "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +15,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -37,7 +37,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -75,7 +75,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { diff --git a/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json index 6c5a9cbaa..b75943177 100644 --- a/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json @@ -2,7 +2,7 @@ "_": { "apply_groups": [], "description": "", - "local_as": 0, + "local_as": 42, "type": "", "import_policy": "", "export_policy": "", @@ -20,7 +20,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 42, "authentication_key": "", "nhs": false, "route_reflector_client": false diff --git a/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json index 3f4742397..f58f5e0c5 100644 --- a/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,11 +1,26 @@ { + "_": { + "apply_groups": [], + "description": "", + "local_as": 65001, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": false, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": false, + "prefix_limit": {}, + "neighbors": {} + }, "RR-CLIENTS": { "apply_groups": [], "description": "[ibgp - rr clients]", "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +30,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -37,7 +52,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { diff --git a/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json index d2dfbaf32..1f53b03ff 100644 --- a/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json @@ -5,7 +5,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +15,7 @@ "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -37,4 +37,4 @@ "remove_private_as": false, "type": "" } -} \ No newline at end of file +} diff --git a/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json index e39f06c91..60e669b26 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json @@ -8,7 +8,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "pass-all", "local_address": "", "prefix_limit": { @@ -30,7 +30,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "pass-all", "local_address": "", "prefix_limit": { @@ -54,7 +54,7 @@ "remove_private_as": false, "description": "", "export_policy": "", - "local_as": 0, + "local_as": 65900, "apply_groups": [], "multipath": false, "prefix_limit": {} @@ -68,7 +68,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "RP-SPECIAL-SNOWFLAKE-IN", "local_address": "", "prefix_limit": { @@ -90,7 +90,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "", "local_address": "", "prefix_limit": {}, @@ -104,7 +104,7 @@ "remove_private_as": true, "description": "", "export_policy": "", - "local_as": 0, + "local_as": 65900, "apply_groups": [], "multipath": false, "prefix_limit": {} diff --git a/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json index 20971ddf8..c850fe601 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,13 +1,28 @@ { + "_": { + "local_as": 13335, + "remove_private_as": false, + "import_policy": "", + "multihop_ttl": 0, + "neighbors": {}, + "multipath": false, + "export_policy": "", + "type": "", + "apply_groups": [], + "remote_as": 0, + "prefix_limit": {}, + "description": "", + "local_address": "" + }, "4-public-anycast-peers": { - "local_as": 0, + "local_as": 13335, "remove_private_as": true, "import_policy": "4-public-anycast-peers-in", "multihop_ttl": 0, "neighbors": { "192.168.20.3": { "export_policy": "", - "local_as": 0, + "local_as": 13335, "prefix_limit": { "inet": { "unicast": { @@ -29,7 +44,7 @@ }, "172.17.17.50": { "export_policy": "", - "local_as": 0, + "local_as": 13335, "prefix_limit": { "inet": { "unicast": { @@ -51,7 +66,7 @@ }, "192.168.50.5": { "export_policy": "", - "local_as": 0, + "local_as": 13335, "prefix_limit": { "inet": { "unicast": { diff --git a/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json index bc0239416..30a30dd4c 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json @@ -10,7 +10,7 @@ "remove_private_as": false, "remote_as": 0, "multihop_ttl": 0, - "local_as": 0, + "local_as": 65900, "apply_groups": [], "neighbors": { "10.255.255.2": { @@ -26,7 +26,7 @@ } } }, - "local_as": 0, + "local_as": 65900, "description": "", "local_address": "", "import_policy": "pass-all", @@ -48,7 +48,7 @@ } } }, - "local_as": 0, + "local_as": 65900, "description": "", "local_address": "", "import_policy": "pass-all", diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json index 1d60e8893..4ed653140 100644 --- a/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,11 +1,26 @@ { + "_": { + "apply_groups": [], + "description": "", + "export_policy": "", + "import_policy": "", + "local_address": "", + "local_as": 65172, + "multihop_ttl": 0, + "multipath": false, + "neighbors": {}, + "prefix_limit": {}, + "remote_as": 0, + "remove_private_as": false, + "type": "" + }, "EBGP": { "apply_groups": [], "description": "", "export_policy": "EBGP-OUT-POLICY", "import_policy": "EBGP-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +30,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet": { @@ -37,7 +52,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet": { @@ -65,7 +80,7 @@ "export_policy": "EBGP-VRF-OUT-POLICY", "import_policy": "EBGP-VRF-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": {}, @@ -80,7 +95,7 @@ "export_policy": "IBGPv6-OUT-POLICY", "import_policy": "IBGPv6-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -90,7 +105,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet6": { @@ -112,7 +127,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet6": { @@ -140,7 +155,7 @@ "export_policy": "EBGPv6-VRF-OUT-POLICY", "import_policy": "EBGPv6-VRF-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": {}, @@ -155,7 +170,7 @@ "export_policy": "IBGP-OUT-POLICY", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -165,7 +180,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet": { @@ -193,7 +208,7 @@ "export_policy": "IBGP-OUT-POLICY", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -203,7 +218,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet6": { diff --git a/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml new file mode 100644 index 000000000..bd581bc2c --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml @@ -0,0 +1,7 @@ + + + + 65001 + + + diff --git a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json index 93c77a2ec..507acf743 100644 --- a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json @@ -1 +1,73 @@ -{"internal":{"apply_groups":[],"description":"","export_policy":"","import_policy":"","local_address":"","local_as":0,"multihop_ttl":0,"multipath":false,"neighbors":{"10.10.10.1":{"authentication_key":"","description":"","export_policy":"nhs","import_policy":"","local_address":"","local_as":0,"nhs":true,"prefix_limit":{},"remote_as":0,"route_reflector_client":false}},"prefix_limit":{},"remote_as":0,"remove_private_as":false,"type":"internal"},"internal-2":{"apply_groups":[],"description":"","export_policy":"","import_policy":"","local_address":"","local_as":0,"multihop_ttl":0,"multipath":false,"neighbors":{"10.10.10.2":{"authentication_key":"","description":"","export_policy":"static","import_policy":"","local_address":"","local_as":0,"nhs":false,"prefix_limit":{},"remote_as":0,"route_reflector_client":false}},"prefix_limit":{},"remote_as":0,"remove_private_as":false,"type":"internal"}} +{ + "_": { + "export_policy": "", + "multipath": false, + "prefix_limit": {}, + "description": "", + "local_as": 65001, + "multihop_ttl": 0, + "apply_groups": [], + "remote_as": 0, + "remove_private_as": false, + "local_address": "", + "type": "", + "import_policy": "", + "neighbors": {} + }, + "internal": { + "apply_groups": [], + "description": "", + "export_policy": "", + "import_policy": "", + "local_address": "", + "local_as": 0, + "multihop_ttl": 0, + "multipath": false, + "neighbors": { + "10.10.10.1": { + "authentication_key": "", + "description": "", + "export_policy": "nhs", + "import_policy": "", + "local_address": "", + "local_as": 0, + "nhs": true, + "prefix_limit": {}, + "remote_as": 0, + "route_reflector_client": false + } + }, + "prefix_limit": {}, + "remote_as": 0, + "remove_private_as": false, + "type": "internal" + }, + "internal-2": { + "apply_groups": [], + "description": "", + "export_policy": "", + "import_policy": "", + "local_address": "", + "local_as": 0, + "multihop_ttl": 0, + "multipath": false, + "neighbors": { + "10.10.10.2": { + "authentication_key": "", + "description": "", + "export_policy": "static", + "import_policy": "", + "local_address": "", + "local_as": 0, + "nhs": false, + "prefix_limit": {}, + "remote_as": 0, + "route_reflector_client": false + } + }, + "prefix_limit": {}, + "remote_as": 0, + "remove_private_as": false, + "type": "internal" + } +} diff --git a/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml new file mode 100644 index 000000000..6ad44d234 --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml @@ -0,0 +1,7 @@ + + + + 13335 + + + diff --git a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json index 868ef99cc..9d41495fd 100644 --- a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1 +1,86 @@ -{"PEERS-GROUP-NAME": {"neighbors": {"192.168.0.1": {"export_policy": "", "prefix_limit": {"inet": {"unicast": {"limit": 100}}}, "route_reflector_client": false, "description": "Facebook [CDN]", "local_as": 0, "nhs": false, "local_address": "", "remote_as": 32934, "authentication_key": "", "import_policy": ""}, "172.17.17.1": {"export_policy": "", "prefix_limit": {"inet": {"unicast": {"limit": 500}}}, "route_reflector_client": false, "description": "Twitter [CDN]", "local_as": 0, "nhs": false, "local_address": "", "remote_as": 13414, "authentication_key": "", "import_policy": ""}}, "export_policy": "PUBLIC-PEER-OUT", "multipath": true, "prefix_limit": {}, "description": "", "local_as": 13335, "multihop_ttl": 0, "apply_groups": ["B", "G", "P", "-", "P", "R", "E", "F", "I", "X", "-", "L", "I", "M", "I", "T"], "remote_as": 0, "remove_private_as": true, "local_address": "", "type": "external", "import_policy": "PUBLIC-PEER-IN"}} +{ + "_": { + "export_policy": "", + "multipath": false, + "prefix_limit": {}, + "description": "", + "local_as": 13335, + "multihop_ttl": 0, + "apply_groups": [], + "remote_as": 0, + "remove_private_as": false, + "local_address": "", + "type": "", + "import_policy": "", + "neighbors": {} + }, + "PEERS-GROUP-NAME": { + "neighbors": { + "192.168.0.1": { + "export_policy": "", + "prefix_limit": { + "inet": { + "unicast": { + "limit": 100 + } + } + }, + "route_reflector_client": false, + "description": "Facebook [CDN]", + "local_as": 0, + "nhs": false, + "local_address": "", + "remote_as": 32934, + "authentication_key": "", + "import_policy": "" + }, + "172.17.17.1": { + "export_policy": "", + "prefix_limit": { + "inet": { + "unicast": { + "limit": 500 + } + } + }, + "route_reflector_client": false, + "description": "Twitter [CDN]", + "local_as": 0, + "nhs": false, + "local_address": "", + "remote_as": 13414, + "authentication_key": "", + "import_policy": "" + } + }, + "export_policy": "PUBLIC-PEER-OUT", + "multipath": true, + "prefix_limit": {}, + "description": "", + "local_as": 13335, + "multihop_ttl": 0, + "apply_groups": [ + "B", + "G", + "P", + "-", + "P", + "R", + "E", + "F", + "I", + "X", + "-", + "L", + "I", + "M", + "I", + "T" + ], + "remote_as": 0, + "remove_private_as": true, + "local_address": "", + "type": "external", + "import_policy": "PUBLIC-PEER-IN" + } +} From 322f208ed3b7a26aafdfcca154aaba812f34a9a8 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 28 Mar 2023 13:01:46 -0700 Subject: [PATCH 28/76] Fixing parsing error when there is no BGP configured on Junos (#1887) --- napalm/junos/junos.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index fdb96e82d..3ce185e52 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -1253,11 +1253,10 @@ def build_prefix_limit(**args): routing_options = junos_views.junos_routing_config_table(self.device) routing_options.get(options=self.junos_config_options) - bgp_asn = int( - routing_options.xml.find( - "./routing-options/autonomous-system/as-number" - ).text + bgp_asn_obj = routing_options.xml.find( + "./routing-options/autonomous-system/as-number" ) + bgp_asn = int(bgp_asn_obj.text) if bgp_asn_obj is not None else 0 bgp_config["_"] = { "apply_groups": [], From 483efae794449082e4db6ef1da910ded22ac39cf Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 3 Apr 2023 09:18:34 -0700 Subject: [PATCH 29/76] Implement no BGP config behavior for Junos (get_bgp_config) (#1890) --- napalm/base/test/getters.py | 2 +- napalm/junos/junos.py | 96 +++++++++++-------- .../nhs/expected_result.json | 8 +- ...ent____policy_options___configuration_.xml | 2 + ...up____bgp___protocols___configuration_.xml | 2 + ...em____routing_options___configuration_.xml | 2 + .../no_bgp/expected_result.json | 1 + .../normal/expected_result.json | 23 +---- 8 files changed, 72 insertions(+), 64 deletions(-) create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json diff --git a/napalm/base/test/getters.py b/napalm/base/test/getters.py index cc64f551e..0a2e47a66 100644 --- a/napalm/base/test/getters.py +++ b/napalm/base/test/getters.py @@ -244,7 +244,7 @@ def test_get_lldp_neighbors_detail(self, test_case): def test_get_bgp_config(self, test_case): """Test get_bgp_config.""" get_bgp_config = self.device.get_bgp_config() - assert len(get_bgp_config) > 0 + assert get_bgp_config == {} or len(get_bgp_config) > 0 for bgp_group in get_bgp_config.values(): assert helpers.test_model(models.BPGConfigGroupDict, bgp_group) diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index 3ce185e52..74b6e5efe 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -1256,30 +1256,34 @@ def build_prefix_limit(**args): bgp_asn_obj = routing_options.xml.find( "./routing-options/autonomous-system/as-number" ) - bgp_asn = int(bgp_asn_obj.text) if bgp_asn_obj is not None else 0 + system_bgp_asn = int(bgp_asn_obj.text) if bgp_asn_obj is not None else 0 - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": bgp_asn, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": {}, - } - if group: + # No BGP peer-group i.e. "_" key is a special case. + if group and group != "_": bgp = junos_views.junos_bgp_config_group_table(self.device) bgp.get(group=group, options=self.junos_config_options) else: bgp = junos_views.junos_bgp_config_table(self.device) bgp.get(options=self.junos_config_options) neighbor = "" # if no group is set, no neighbor should be set either + + # Only set no peer-group if BGP is actually configured. + if bgp.items() or system_bgp_asn: + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": system_bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": {}, + } bgp_items = bgp.items() if neighbor: @@ -1306,13 +1310,17 @@ def build_prefix_limit(**args): for field, datatype in _GROUP_FIELDS_DATATYPE_MAP_.items() if "_prefix_limit" not in field } - for elem in bgp_group_details: - if not ("_prefix_limit" not in elem[0] and elem[1] is not None): + + # Always overwrite with the system local_as (this will either be + # valid or will be zero i.e. the same as the default value). + bgp_config[bgp_group_name]["local_as"] = system_bgp_asn + + for key, value in bgp_group_details: + if "_prefix_limit" in key or value is None: continue - datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0]) + datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) - key = elem[0] - value = elem[1] + if key in ["export_policy", "import_policy"]: if isinstance(value, list): value = " ".join(value) @@ -1320,6 +1328,10 @@ def build_prefix_limit(**args): value = napalm.base.helpers.convert( napalm.base.helpers.ip, value, value ) + if key == "apply_groups": + # Ensure apply_groups value is wrapped in a list + if isinstance(value, str): + value = [value] if key == "neighbors": bgp_group_peers = value continue @@ -1327,15 +1339,15 @@ def build_prefix_limit(**args): {key: napalm.base.helpers.convert(datatype, value, default)} ) prefix_limit_fields = {} - for elem in bgp_group_details: - if "_prefix_limit" in elem[0] and elem[1] is not None: - datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0]) + for key, value in bgp_group_details: + if "_prefix_limit" in key and value is not None: + datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) prefix_limit_fields.update( { - elem[0].replace( + key.replace( "_prefix_limit", "" - ): napalm.base.helpers.convert(datatype, elem[1], default) + ): napalm.base.helpers.convert(datatype, value, default) } ) bgp_config[bgp_group_name]["prefix_limit"] = build_prefix_limit( @@ -1349,23 +1361,31 @@ def build_prefix_limit(**args): bgp_config[bgp_group_name]["multihop_ttl"] = 64 bgp_config[bgp_group_name]["neighbors"] = {} + bgp_group_remote_as = bgp_config[bgp_group_name]["remote_as"] for bgp_group_neighbor in bgp_group_peers.items(): bgp_peer_address = napalm.base.helpers.ip(bgp_group_neighbor[0]) if neighbor and bgp_peer_address != neighbor: continue # if filters applied, jump over all other neighbors bgp_group_details = bgp_group_neighbor[1] + + # Set defaults for this BGP peer bgp_peer_details = { field: _DATATYPE_DEFAULT_.get(datatype) for field, datatype in _PEER_FIELDS_DATATYPE_MAP_.items() if "_prefix_limit" not in field } - for elem in bgp_group_details: - if not ("_prefix_limit" not in elem[0] and elem[1] is not None): + + # Always overwrite with the system local_as (this will either be + # valid or will be zero i.e. the same as the default value). + bgp_peer_details["local_as"] = system_bgp_asn + # Always set the default remote-as as the Peer-Group remote-as + bgp_peer_details["remote_as"] = bgp_group_remote_as + + for key, value in bgp_group_details: + if "_prefix_limit" in key or value is None: continue - datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0]) + datatype = _PEER_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) - key = elem[0] - value = elem[1] if key in ["export_policy"]: # next-hop self is applied on export IBGP sessions bgp_peer_details["nhs"] = _check_nhs(value, nhs_policies) @@ -1393,17 +1413,15 @@ def build_prefix_limit(**args): if "cluster" in bgp_config[bgp_group_name].keys(): bgp_peer_details["route_reflector_client"] = True prefix_limit_fields = {} - for elem in bgp_group_details: - if "_prefix_limit" in elem[0] and elem[1] is not None: - datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0]) + for key, value in bgp_group_details: + if "_prefix_limit" in key and value is not None: + datatype = _PEER_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) prefix_limit_fields.update( { - elem[0].replace( + key.replace( "_prefix_limit", "" - ): napalm.base.helpers.convert( - datatype, elem[1], default - ) + ): napalm.base.helpers.convert(datatype, value, default) } ) bgp_peer_details["prefix_limit"] = build_prefix_limit( diff --git a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json index 507acf743..a375a75a0 100644 --- a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json @@ -20,7 +20,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -30,7 +30,7 @@ "export_policy": "nhs", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": true, "prefix_limit": {}, "remote_as": 0, @@ -48,7 +48,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -58,7 +58,7 @@ "export_policy": "static", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": {}, "remote_as": 0, diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml new file mode 100644 index 000000000..83138436e --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml @@ -0,0 +1,2 @@ + + diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml new file mode 100644 index 000000000..83138436e --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml @@ -0,0 +1,2 @@ + + diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml new file mode 100644 index 000000000..83138436e --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml @@ -0,0 +1,2 @@ + + diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json index 9d41495fd..6c44290dd 100644 --- a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -27,7 +27,7 @@ }, "route_reflector_client": false, "description": "Facebook [CDN]", - "local_as": 0, + "local_as": 13335, "nhs": false, "local_address": "", "remote_as": 32934, @@ -45,7 +45,7 @@ }, "route_reflector_client": false, "description": "Twitter [CDN]", - "local_as": 0, + "local_as": 13335, "nhs": false, "local_address": "", "remote_as": 13414, @@ -59,24 +59,7 @@ "description": "", "local_as": 13335, "multihop_ttl": 0, - "apply_groups": [ - "B", - "G", - "P", - "-", - "P", - "R", - "E", - "F", - "I", - "X", - "-", - "L", - "I", - "M", - "I", - "T" - ], + "apply_groups": ["BGP-PREFIX-LIMIT"], "remote_as": 0, "remove_private_as": true, "local_address": "", From ba460d9b73c241a539ab33deedbccd6cf905053a Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 3 Apr 2023 16:17:44 -0500 Subject: [PATCH 30/76] eos: add test case for issue 905 --- .../expected_result.json | 57 +++++++++++++++++++ ...w_running_config___section_router_bgp.text | 11 ++++ 2 files changed, 68 insertions(+) create mode 100644 test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json create mode 100644 test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json new file mode 100644 index 000000000..4f2f36e4e --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json @@ -0,0 +1,57 @@ +{ + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 65534, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, + "FOO-GROUP": { + "local_address": "", + "description": "FOO", + "type": "", + "local_as": 65534, + "apply_groups": [], + "multihop_ttl": 0, + "remove_private_as": false, + "remote_as": 65534, + "import_policy": "", + "export_policy": "", + "neighbors": { + "192.0.2.2": { + "local_address": "", + "authentication_key": "", + "description": "FOO", + "nhs": false, + "local_as": 65534, + "route_reflector_client": false, + "remote_as": 65534, + "import_policy": "", + "export_policy": "", + "prefix_limit": {} + }, + "192.0.2.3": { + "local_address": "", + "authentication_key": "", + "description": "SECOND-PEER", + "nhs": true, + "local_as": 65534, + "route_reflector_client": false, + "remote_as": 65534, + "import_policy": "", + "export_policy": "", + "prefix_limit": {} + } + }, + "prefix_limit": {}, + "multipath": false + } +} diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text new file mode 100644 index 000000000..0db6d0c27 --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text @@ -0,0 +1,11 @@ +router bgp 65534 + router-id 192.0.2.1 + neighbor FOO-GROUP peer group + neighbor FOO-GROUP next-hop-self + neighbor FOO-GROUP description FOO + neighbor FOO-GROUP remote-as 65534 + neighbor 192.0.2.2 peer group FOO-GROUP + no neighbor 192.0.2.2 next-hop-self + neighbor 192.0.2.3 peer group FOO-GROUP + neighbor 192.0.2.3 description SECOND-PEER +! From f7e83d352fbc2750183fcb8d676f98bce32fbee0 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 3 Apr 2023 16:20:25 -0500 Subject: [PATCH 31/76] eos: use peer group dict to populate neighbors Since EOS outputs all peer group configuration prior to individual neighbor configurations, we can use the settings for NHS, remote-as, etc present in the group level dictionary when creating the neighbor dictionary, resulting in a consistent view of the configuration applied to the neighbor. Closes #905 --- napalm/eos/eos.py | 28 +++++++++++++++---- .../expected_result.json | 8 +++--- .../issue_1113_dot_asn/expected_result.json | 16 +++++------ .../normal/expected_result.json | 16 +++++------ 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index cb182ea8d..01793e1a7 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -994,6 +994,7 @@ def get_bgp_config(self, group="", neighbor=""): "local-v4-addr": "local_address", "local-v6-addr": "local_address", "local-as": "local_as", + "next-hop-self": "nhs", "description": "description", "import-policy": "import_policy", "export-policy": "export_policy", @@ -1051,7 +1052,7 @@ def default_group_dict(local_as): ) # few more default values return group_dict - def default_neighbor_dict(local_as): + def default_neighbor_dict(local_as, group_dict): neighbor_dict = {} neighbor_dict.update( { @@ -1062,6 +1063,13 @@ def default_neighbor_dict(local_as): neighbor_dict.update( {"prefix_limit": {}, "local_as": local_as, "authentication_key": ""} ) # few more default values + neighbor_dict.update( + { + key: group_dict.get(key) + for key in _GROUP_FIELD_MAP_.values() + if key in group_dict and key in _PEER_FIELD_MAP_.values() + } + ) # copy in values from group dict if present return neighbor_dict def parse_options(options, default_value=False): @@ -1152,14 +1160,20 @@ def parse_options(options, default_value=False): ipaddress.ip_address(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) + group_name = None if options[0] == "peer-group": - bgp_neighbors[peer_address]["__group"] = options[1] + group_name = options[1] # EOS > 4.23.0 only supports the new syntax # https://www.arista.com/en/support/advisories-notices/fieldnotices/7097-field-notice-39 elif options[0] == "peer" and options[1] == "group": - bgp_neighbors[peer_address]["__group"] = options[2] + group_name = options[2] + if peer_address not in bgp_neighbors: + bgp_neighbors[peer_address] = default_neighbor_dict( + local_as, bgp_config.get(group_name, {}) + ) + + if group_name: + bgp_neighbors[peer_address]["__group"] = group_name # in the config, neighbor details are lister after # the group is specified for the neighbor: @@ -1197,6 +1211,10 @@ def parse_options(options, default_value=False): bgp_config[peer_group] = default_group_dict(local_as) bgp_config[peer_group]["neighbors"][peer] = peer_details + [ + v.pop("nhs", None) for v in bgp_config.values() + ] # remove NHS from group-level dictionary + return bgp_config def get_arp_table(self, vrf=""): diff --git a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json index 9a66039c0..1dbf0d43b 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json @@ -35,8 +35,8 @@ "local_as": 64496, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} }, @@ -47,8 +47,8 @@ "local_as": 64496, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} } diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json index c6c5353d9..1f885538c 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json @@ -35,8 +35,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "4-public-peer-anycast-out", "authentication_key": "", "prefix_limit": {} }, @@ -47,8 +47,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "4-public-peer-anycast-out", "authentication_key": "", "prefix_limit": {} } @@ -75,8 +75,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} }, @@ -87,8 +87,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} } diff --git a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json index 0d22dfaf6..bdf8f2657 100644 --- a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -34,8 +34,8 @@ "local_as": 13335, "route_reflector_client": false, "remote_as": 13414, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "4-public-peer-anycast-out", "prefix_limit": {} }, "192.168.0.1": { @@ -46,8 +46,8 @@ "local_as": 13335, "route_reflector_client": false, "remote_as": 32934, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "4-public-peer-anycast-out", "prefix_limit": {} } }, @@ -74,8 +74,8 @@ "local_as": 13335, "route_reflector_client": false, "remote_as": 54113, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "prefix_limit": {} }, "2001:db8::0:1": { @@ -86,8 +86,8 @@ "local_as": 13335, "route_reflector_client": false, "remote_as": 8403, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "prefix_limit": {} } }, From 02837c0827a9e00859cfc4af45df661cdedaa39c Mon Sep 17 00:00:00 2001 From: bewing Date: Tue, 4 Apr 2023 17:52:25 -0500 Subject: [PATCH 32/76] eos: get_bgp_config when BGP not running (#1891) Return an empty dictionary if we are unable to detect a local ASN, as this indicates that no BGP configuration is present on the device. --- napalm/eos/eos.py | 4 ++++ .../test_get_bgp_config/no_bgp_config/expected_result.json | 1 + .../show_running_config___section_router_bgp.text | 0 3 files changed, 5 insertions(+) create mode 100644 test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json create mode 100644 test/eos/mocked_data/test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index cb182ea8d..3de3ed8a2 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -1197,6 +1197,10 @@ def parse_options(options, default_value=False): bgp_config[peer_group] = default_group_dict(local_as) bgp_config[peer_group]["neighbors"][peer] = peer_details + if local_as == 0: + # BGP not running + return {} + return bgp_config def get_arp_table(self, vrf=""): diff --git a/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text b/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text new file mode 100644 index 000000000..e69de29bb From 7544274760451a002cb5bb068cd6b14accba34dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 10:52:40 -0700 Subject: [PATCH 33/76] Bump types-requests from 2.28.11.16 to 2.28.11.17 (#1882) Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11.16 to 2.28.11.17. - [Release notes](https://github.com/python/typeshed/releases) - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: types-requests dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kirk Byers --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 4139a9281..05a9f7a53 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -10,7 +10,7 @@ pylama==8.4.1 mock==5.0.1 mypy==0.982 types-PyYAML==6.0.12.8 -types-requests==2.28.11.16 +types-requests==2.28.11.17 types-six==1.16.21.7 types-setuptools==67.6.0.5 ttp==0.9.0 From 8e7d663e0f4432e7a896becc34c16b103d9a26d0 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Thu, 20 Apr 2023 09:31:43 -0700 Subject: [PATCH 34/76] Move canonical_interface_name, base_interfaces to netutils (#1904) Co-authored-by: itdependsnetworks --- napalm/base/base.py | 5 +- napalm/base/canonical_map.py | 157 +---------------------------------- napalm/base/helpers.py | 96 ++------------------- napalm/ios/ios.py | 8 +- napalm/nxos/nxos.py | 11 +-- napalm/nxos_ssh/nxos_ssh.py | 14 ++-- test/base/test_helpers.py | 81 ------------------ 7 files changed, 31 insertions(+), 341 deletions(-) diff --git a/napalm/base/base.py b/napalm/base/base.py index d1dbe0eea..7410bf6a8 100644 --- a/napalm/base/base.py +++ b/napalm/base/base.py @@ -19,6 +19,7 @@ from typing_extensions import Literal from netmiko import ConnectHandler, NetMikoTimeoutException +from netutils.interface import canonical_interface_name # local modules import napalm.base.exceptions @@ -1805,8 +1806,6 @@ def compliance_report( def _canonical_int(self, interface: str) -> str: """Expose the helper function within this class.""" if self.use_canonical_interface is True: - return napalm.base.helpers.canonical_interface_name( - interface, addl_name_map=None - ) + return canonical_interface_name(interface, addl_name_map=None) else: return interface diff --git a/napalm/base/canonical_map.py b/napalm/base/canonical_map.py index 29b50e714..fb9658213 100644 --- a/napalm/base/canonical_map.py +++ b/napalm/base/canonical_map.py @@ -1,153 +1,4 @@ -base_interfaces = { - "ATM": "ATM", - "AT": "ATM", - "B": "Bdi", - "Bd": "Bdi", - "Bdi": "Bdi", - "EOBC": "EOBC", - "EO": "EOBC", - "Ethernet": "Ethernet", - "Eth": "Ethernet", - "eth": "Ethernet", - "Et": "Ethernet", - "et": "Ethernet", - "FastEthernet": "FastEthernet", - "FastEth": "FastEthernet", - "FastE": "FastEthernet", - "Fast": "FastEthernet", - "Fas": "FastEthernet", - "FE": "FastEthernet", - "Fa": "FastEthernet", - "fa": "FastEthernet", - "Fddi": "Fddi", - "FD": "Fddi", - "FortyGigabitEthernet": "FortyGigabitEthernet", - "FortyGigEthernet": "FortyGigabitEthernet", - "FortyGigEth": "FortyGigabitEthernet", - "FortyGigE": "FortyGigabitEthernet", - "FortyGig": "FortyGigabitEthernet", - "FGE": "FortyGigabitEthernet", - "FO": "FortyGigabitEthernet", - "Fo": "FortyGigabitEthernet", - "FiftyGigabitEthernet": "FiftyGigabitEthernet", - "FiftyGigEthernet": "FiftyGigabitEthernet", - "FiftyGigEth": "FiftyGigabitEthernet", - "FiftyGigE": "FiftyGigabitEthernet", - "FI": "FiftyGigabitEthernet", - "Fi": "FiftyGigabitEthernet", - "fi": "FiftyGigabitEthernet", - "GigabitEthernet": "GigabitEthernet", - "GigEthernet": "GigabitEthernet", - "GigEth": "GigabitEthernet", - "GigE": "GigabitEthernet", - "Gig": "GigabitEthernet", - "GE": "GigabitEthernet", - "Ge": "GigabitEthernet", - "ge": "GigabitEthernet", - "Gi": "GigabitEthernet", - "gi": "GigabitEthernet", - "HundredGigabitEthernet": "HundredGigabitEthernet", - "HundredGigEthernet": "HundredGigabitEthernet", - "HundredGigEth": "HundredGigabitEthernet", - "HundredGigE": "HundredGigabitEthernet", - "HundredGig": "HundredGigabitEthernet", - "Hu": "HundredGigabitEthernet", - "TwentyFiveGigabitEthernet": "TwentyFiveGigabitEthernet", - "TwentyFiveGigEthernet": "TwentyFiveGigabitEthernet", - "TwentyFiveGigEth": "TwentyFiveGigabitEthernet", - "TwentyFiveGigE": "TwentyFiveGigabitEthernet", - "TwentyFiveGig": "TwentyFiveGigabitEthernet", - "TF": "TwentyFiveGigabitEthernet", - "Tf": "TwentyFiveGigabitEthernet", - "tf": "TwentyFiveGigabitEthernet", - "TwoHundredGigabitEthernet": "TwoHundredGigabitEthernet", - "TwoHundredGigEthernet": "TwoHundredGigabitEthernet", - "TwoHundredGigEth": "TwoHundredGigabitEthernet", - "TwoHundredGigE": "TwoHundredGigabitEthernet", - "TwoHundredGig": "TwoHundredGigabitEthernet", - "TH": "TwoHundredGigabitEthernet", - "Th": "TwoHundredGigabitEthernet", - "th": "TwoHundredGigabitEthernet", - "FourHundredGigabitEthernet": "FourHundredGigabitEthernet", - "FourHundredGigEthernet": "FourHundredGigabitEthernet", - "FourHundredGigEth": "FourHundredGigabitEthernet", - "FourHundredGigE": "FourHundredGigabitEthernet", - "FourHundredGig": "FourHundredGigabitEthernet", - "F": "FourHundredGigabitEthernet", - "f": "FourHundredGigabitEthernet", - "Loopback": "Loopback", - "loopback": "Loopback", - "Lo": "Loopback", - "lo": "Loopback", - "Management": "Management", - "Mgmt": "Management", - "mgmt": "Management", - "Ma": "Management", - "Management_short": "Ma", - "MFR": "MFR", - "Multilink": "Multilink", - "Mu": "Multilink", - "n": "nve", - "nv": "nve", - "nve": "nve", - "PortChannel": "Port-channel", - "Port-channel": "Port-channel", - "Port-Channel": "Port-channel", - "port-channel": "Port-channel", - "po": "Port-channel", - "Po": "Port-channel", - "POS": "POS", - "PO": "POS", - "Serial": "Serial", - "Se": "Serial", - "S": "Serial", - "TenGigabitEthernet": "TenGigabitEthernet", - "TenGigEthernet": "TenGigabitEthernet", - "TenGigEth": "TenGigabitEthernet", - "TenGig": "TenGigabitEthernet", - "TeGig": "TenGigabitEthernet", - "Ten": "TenGigabitEthernet", - "T": "TenGigabitEthernet", - "Te": "TenGigabitEthernet", - "te": "TenGigabitEthernet", - "Tunnel": "Tunnel", - "Tun": "Tunnel", - "Tu": "Tunnel", - "Twe": "TwentyFiveGigE", - "Tw": "TwoGigabitEthernet", - "Two": "TwoGigabitEthernet", - "Virtual-Access": "Virtual-Access", - "Vi": "Virtual-Access", - "Virtual-Template": "Virtual-Template", - "Vt": "Virtual-Template", - "VLAN": "VLAN", - "V": "VLAN", - "Vl": "VLAN", - "Wlan-GigabitEthernet": "Wlan-GigabitEthernet", -} - -reverse_mapping = { - "ATM": "At", - "EOBC": "EO", - "Ethernet": "Et", - "FastEthernet": "Fa", - "Fddi": "FD", - "FortyGigabitEthernet": "Fo", - "GigabitEthernet": "Gi", - "HundredGigabitEthernet": "Hu", - "Loopback": "Lo", - "Management": "Ma", - "MFR": "MFR", - "Multilink": "Mu", - "Port-channel": "Po", - "POS": "PO", - "Serial": "Se", - "TenGigabitEthernet": "Te", - "Tunnel": "Tu", - "TwoGigabitEthernet": "Two", - "TwentyFiveGigE": "Twe", - "Virtual-Access": "Vi", - "Virtual-Template": "Vt", - "VLAN": "Vl", - "Wlan-GigabitEthernet": "Wl-Gi", -} +# Do not remove the below imports, functions were moved to netutils, but to not +# break backwards compatibility, these should remain +from netutils.constants import BASE_INTERFACES as base_interfaces # noqa +from netutils.constants import REVERSE_MAPPING as reverse_mapping # noqa diff --git a/napalm/base/helpers.py b/napalm/base/helpers.py index e40b88a77..dd58ddc7a 100644 --- a/napalm/base/helpers.py +++ b/napalm/base/helpers.py @@ -18,6 +18,14 @@ from netaddr import mac_unix from netutils.config.parser import IOSConfigParser +# Do not remove the below imports, functions were moved to netutils, but to not +# break backwards compatibility, these should remain +from netutils.interface import abbreviated_interface_name # noqa +from netutils.interface import canonical_interface_name # noqa +from netutils.constants import BASE_INTERFACES as base_interfaces # noqa +from netutils.constants import REVERSE_MAPPING as reverse_mapping # noqa +from netutils.interface import split_interface as _split_interface + try: from ttp import quick_parse as ttp_quick_parse @@ -30,7 +38,6 @@ from napalm.base import constants from napalm.base.models import ConfigDict from napalm.base.utils.jinja_filters import CustomJinjaFilters -from napalm.base.canonical_map import base_interfaces, reverse_mapping T = TypeVar("T") R = TypeVar("R") @@ -564,92 +571,7 @@ def as_number(as_number_val: str) -> int: def split_interface(intf_name: str) -> Tuple[str, str]: """Split an interface name based on first digit, slash, or space match.""" - head = intf_name.rstrip(r"/\0123456789. ") - tail = intf_name[len(head) :].lstrip() - return (head, tail) - - -def canonical_interface_name( - interface: str, addl_name_map: Optional[Dict[str, str]] = None -) -> str: - """Function to return an interface's canonical name (fully expanded name). - - Use of explicit matches used to indicate a clear understanding on any potential - match. Regex and other looser matching methods were not implmented to avoid false - positive matches. As an example, it would make sense to do "[P|p][O|o]" which would - incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not - easily troubleshot, found, or known. - - :param interface: The interface you are attempting to expand. - :param addl_name_map: A dict containing key/value pairs that updates - the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs - {"Po": "Port-Channel"} - :type addl_name_map: optional - """ - - name_map = {} - name_map.update(base_interfaces) - interface_type, interface_number = split_interface(interface) - - if isinstance(addl_name_map, dict): - name_map.update(addl_name_map) - # check in dict for mapping - if name_map.get(interface_type): - long_int = name_map.get(interface_type) - assert isinstance(long_int, str) - return long_int + str(interface_number) - # if nothing matched, return the original name - else: - return interface - - -def abbreviated_interface_name( - interface: str, - addl_name_map: Optional[Dict[str, str]] = None, - addl_reverse_map: Optional[Dict[str, str]] = None, -) -> str: - """Function to return an abbreviated representation of the interface name. - - :param interface: The interface you are attempting to abbreviate. - :param addl_name_map: A dict containing key/value pairs that updates - the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs - {"Po": "Port-Channel"} - :type addl_name_map: optional - :param addl_reverse_map: A dict containing key/value pairs that updates - the reverse mapping. Used if an OS has specific differences. e.g. {"PortChannel": "Po"} vs - {"PortChannel": "po"} - :type addl_reverse_map: optional - """ - - name_map = {} - name_map.update(base_interfaces) - interface_type, interface_number = split_interface(interface) - - if isinstance(addl_name_map, dict): - name_map.update(addl_name_map) - - rev_name_map = {} - rev_name_map.update(reverse_mapping) - - if isinstance(addl_reverse_map, dict): - rev_name_map.update(addl_reverse_map) - - # Try to ensure canonical type. - if name_map.get(interface_type): - canonical_type = name_map.get(interface_type) - else: - canonical_type = interface_type - - assert isinstance(canonical_type, str) - - try: - abbreviated_name = rev_name_map[canonical_type] + str(interface_number) - return abbreviated_name - except KeyError: - pass - - # If abbreviated name lookup fails, return original name - return interface + return _split_interface(interface=intf_name) def transform_lldp_capab(capabilities: Union[str, Any]) -> List[str]: diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 682a9a990..7c01fc655 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -36,15 +36,17 @@ CommitConfirmException, ) from napalm.base.helpers import ( - canonical_interface_name, transform_lldp_capab, textfsm_extractor, - split_interface, - abbreviated_interface_name, generate_regex_or, sanitize_configs, ) from netaddr.core import AddrFormatError +from netutils.interface import ( + abbreviated_interface_name, + canonical_interface_name, + split_interface, +) from napalm.base.netmiko_helpers import netmiko_args # Easier to store these as constants diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index 7eac8077e..9668569ff 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -46,6 +46,7 @@ from netmiko import file_transfer from requests.exceptions import ConnectionError from netutils.config.compliance import diff_network_config +from netutils.interface import canonical_interface_name import napalm.base.constants as c @@ -682,7 +683,7 @@ def get_lldp_neighbors_detail( lldp_entry["remote_system_enable_capab"] ) # Turn the interfaces into their long version - local_intf = napalm.base.helpers.canonical_interface_name(local_intf) + local_intf = canonical_interface_name(local_intf) lldp.setdefault(local_intf, []) lldp[local_intf].append(lldp_entry) # type: ignore @@ -738,13 +739,9 @@ def _parse_vlan_ports(self, vlan_s: Union[str, List]) -> List: find = re.findall(find_regexp, vls.strip()) if find: for i in range(int(find[0][1]), int(find[0][2]) + 1): - vlans.append( - napalm.base.helpers.canonical_interface_name( - find[0][0] + str(i) - ) - ) + vlans.append(canonical_interface_name(find[0][0] + str(i))) else: - vlans.append(napalm.base.helpers.canonical_interface_name(vls.strip())) + vlans.append(canonical_interface_name(vls.strip())) return vlans @abstractmethod diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index 51aa2c690..bdb01f5a9 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -20,6 +20,9 @@ import socket from collections import defaultdict +# import external lib +from netutils.interface import canonical_interface_name + # import NAPALM Base from napalm.base import helpers from napalm.base.exceptions import CommandErrorException, ReplaceConfigException @@ -116,7 +119,7 @@ def parse_intf_section(interface): else: # More standard is up, next line admin state is lines match = re.search(re_intf_name_state, interface) - intf_name = helpers.canonical_interface_name(match.group("intf_name")) + intf_name = canonical_interface_name(match.group("intf_name")) intf_state = match.group("intf_state").strip() is_up = True if intf_state == "up" else False @@ -516,7 +519,6 @@ def is_alive(self): return {"is_alive": self.device.remote_conn.transport.is_active()} def _copy_run_start(self): - output = self.device.save_config() if "complete" in output.lower(): return True @@ -525,7 +527,6 @@ def _copy_run_start(self): raise CommandErrorException(msg) def _load_cfg_from_checkpoint(self): - commands = [ "terminal dont-ask", "rollback running-config file {}".format(self.candidate_cfg), @@ -655,7 +656,7 @@ def get_facts(self): continue interface = line.split()[0] # Return canonical interface name - interface_list.append(helpers.canonical_interface_name(interface)) + interface_list.append(canonical_interface_name(interface)) return { "uptime": float(uptime), @@ -1190,7 +1191,7 @@ def process_mac_fields(vlan, mac, mac_type, interface): active = False return { "mac": helpers.mac(mac), - "interface": helpers.canonical_interface_name(interface), + "interface": canonical_interface_name(interface), "vlan": int(vlan), "static": static, "active": active, @@ -1209,7 +1210,6 @@ def process_mac_fields(vlan, mac, mac_type, interface): output = re.sub(r"vPC Peer-Link", "vPC-Peer-Link", output, flags=re.M) for line in output.splitlines(): - # Every 500 Mac's Legend is reprinted, regardless of terminal length if re.search(r"^Legend", line): continue @@ -1460,7 +1460,7 @@ def get_route_to(self, destination="", protocol="", longer=False): # routing protocol process number, for future use # nh_source_proc_nr = viastr.group('procnr) if nh_int: - nh_int_canon = helpers.canonical_interface_name(nh_int) + nh_int_canon = canonical_interface_name(nh_int) else: nh_int_canon = "" route_entry = { diff --git a/test/base/test_helpers.py b/test/base/test_helpers.py index 24bdb0f5f..96dbb86f5 100644 --- a/test/base/test_helpers.py +++ b/test/base/test_helpers.py @@ -493,87 +493,6 @@ def test_convert_uptime_string_seconds(self): self.assertEqual(convert_uptime_string_seconds("95w2d10h58m"), 57668280) self.assertEqual(convert_uptime_string_seconds("1h5m"), 3900) - def test_canonical_interface_name(self): - """Test the canonical_interface_name helper function.""" - self.assertEqual( - napalm.base.helpers.canonical_interface_name("Fa0/1"), "FastEthernet0/1" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("FastEthernet0/1"), - "FastEthernet0/1", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("TenGig1/1/1.5"), - "TenGigabitEthernet1/1/1.5", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("Gi1/2"), "GigabitEthernet1/2" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("HundredGigE105/1/1"), - "HundredGigabitEthernet105/1/1", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("Lo0"), "Loopback0" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("lo0"), "Loopback0" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("no_match0/1"), "no_match0/1" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name( - "lo10", addl_name_map={"lo": "something_custom"} - ), - "something_custom10", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name( - "uniq0/1/1", addl_name_map={"uniq": "something_custom"} - ), - "something_custom0/1/1", - ) - - def test_abbreviated_interface_name(self): - """Test the abbreviated_interface_name helper function.""" - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("Fa0/1"), "Fa0/1" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("FastEthernet0/1"), "Fa0/1" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("TenGig1/1/1.5"), "Te1/1/1.5" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("Gi1/2"), "Gi1/2" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("HundredGigE105/1/1"), - "Hu105/1/1", - ) - self.assertEqual(napalm.base.helpers.abbreviated_interface_name("Lo0"), "Lo0") - self.assertEqual(napalm.base.helpers.abbreviated_interface_name("lo0"), "Lo0") - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("something_custom0/1"), - "something_custom0/1", - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name( - "loop10", addl_name_map={"loop": "Loopback"} - ), - "Lo10", - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name( - "loop10", - addl_name_map={"loop": "Loopback"}, - addl_reverse_map={"Loopback": "lo"}, - ), - "lo10", - ) - def test_netmiko_arguments(self): """Test the netmiko argument processing.""" self.assertEqual(netmiko_args(optional_args={}), {}) From 4af4391bdb85bc11f261afab2b1026e46350fac4 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 1 May 2023 10:01:59 -0700 Subject: [PATCH 35/76] get_bgp_config for Cisco when no BGP is configured (#1910) --- napalm/ios/ios.py | 39 +++-- .../no_bgp/expected_result.json | 1 + .../no_bgp/show_running_config.txt | 150 ++++++++++++++++++ 3 files changed, 175 insertions(+), 15 deletions(-) create mode 100644 test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json create mode 100644 test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 7c01fc655..5e31c49f8 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -1463,6 +1463,11 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): bgp_config_list = napalm.base.helpers.netutils_parse_objects( "router bgp", cfg["running"] ) + + # No BGP configuration + if not bgp_config_list: + return {} + bgp_asn = napalm.base.helpers.regex_find_txt( r"router bgp (\d+)", bgp_config_list, default=0 ) @@ -1569,21 +1574,25 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): "route_reflector_client": route_reflector_client, } - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": bgp_asn, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("_", {}), - } + # Do not include the no-group ("_") if a group argument is passed in + # unless group argument is "_" + if not group or group == "_": + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("_", {}), + } + # Get the peer-group level config for each group for group_name in bgp_group_neighbors.keys(): # If a group is passed in params, only continue on that group diff --git a/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt b/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt new file mode 100644 index 000000000..50e08a544 --- /dev/null +++ b/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt @@ -0,0 +1,150 @@ +! +! Last configuration change at 18:41:02 UTC Thu Nov 24 2016 +! +version 15.5 +service timestamps debug datetime msec +service timestamps log datetime msec +no platform punt-keepalive disable-kernel-core +platform console auto +! +hostname CSR1 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +aaa new-model +! +! +aaa authentication login default local +aaa authorization exec default local +! +! +! +! +! +aaa session-id common +! +ip vrf MGMT +! +! +! +! +! +! +! +! +! + + +ip domain name example.local + +! +! +! +! +! +! +! +! +! +! +subscriber templating +! +multilink bundle-name authenticated +! +! +! +! +! +! +! +! +! +! +! +! +! +license udi pid CSR1000V sn 9OSEGKJXRHE +spanning-tree extend system-id +! +username cisco privilege 15 password 0 cisco +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + ip address 1.1.1.1 255.255.255.255 +! +interface GigabitEthernet1 + ip vrf forwarding MGMT + ip address 192.168.35.121 255.255.255.0 + negotiation auto +! +interface GigabitEthernet2 + ip address 10.1.1.1 255.255.255.0 + negotiation auto +! +interface GigabitEthernet3 + no ip address + shutdown + negotiation auto +! +router ospf 1 + redistribute connected subnets + network 10.1.1.0 0.0.0.255 area 0 +! +! +! +! +virtual-service csr_mgmt +! +ip forward-protocol nd +! +no ip http server +no ip http secure-server +! +! +! +! +! +! +control-plane +! + ! + ! + ! + ! +! +! +! +! +! +line con 0 +line vty 0 4 +! +! +end From 27ccd5608b2425a9aaa3e04b85b88d93aa6c70d2 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Mon, 8 May 2023 17:38:46 +0200 Subject: [PATCH 36/76] Fix documentation of getter support matrix (#1913) Replace pytest-json with pytest-json-report and make modifications to support new format. --- .gitignore | 1 + docs/conf.py | 6 +++--- docs/test.sh | 6 +++--- requirements-dev.txt | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index a00f7f807..87330b57c 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ env test/unit/test_devices.py +.report.json report.json tags .pytest_cache/ diff --git a/docs/conf.py b/docs/conf.py index cf56e0537..d9b5774cd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -371,13 +371,13 @@ def build_getters_support_matrix(app): if not (m.startswith("_") or m in EXCLUDE_METHODS) } - regex_name = re.compile(r"(?P\w+)\/.*::test_(?P\w+)") + regex_name = re.compile(r"test.*/(?P\w+)\/.*::test_(?P\w+)") filename = "./support/tests/report.json" with open(filename, "r") as f: data = json.loads(f.read()) - for test in data["report"]["tests"]: - match = regex_name.search(test["name"]) + for test in data["tests"]: + match = regex_name.search(test["nodeid"]) if match: driver = match.group("driver") drivers.add(driver) diff --git a/docs/test.sh b/docs/test.sh index b911f782d..3d102c74a 100755 --- a/docs/test.sh +++ b/docs/test.sh @@ -3,10 +3,10 @@ CWD=`pwd` TEST_RESULTS_PATH="$CWD/support/tests" REPOBASE=$CWD/.. -if [ ! -f "report.json" ]; then +if [ ! -f ".report.json" ]; then set -e - py.test --rootdir $REPOBASE -c /dev/null --cov=./ -vs --json=report.json $REPOBASE/test*/*/test_getters.py + pytest --rootdir $REPOBASE -c /dev/null --json-report --cov=./ -vs $REPOBASE/test*/*/test_getters.py set -e - cp report.json $TEST_RESULTS_PATH/report.json + cp .report.json $TEST_RESULTS_PATH/report.json fi diff --git a/requirements-dev.txt b/requirements-dev.txt index 05a9f7a53..3d6b0cf20 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ ddt==1.6.0 flake8-import-order==0.18.2 pytest==7.2.2 pytest-cov==4.0.0 -pytest-json==0.4.0 +pytest-json-report==1.5.0 pyflakes==3.0.1 pylama==8.4.1 mock==5.0.1 From fa918367a0c6e533dbf50bd67d5ae67b8fef6ea4 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Mon, 8 May 2023 11:54:51 -0700 Subject: [PATCH 37/76] Pin docs dependencies to specific urllib3 version (#1915) --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 482643959..24e3fa96b 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,4 @@ +urllib3==1.26.15 # https://github.com/readthedocs/readthedocs.org/issues/10290 sphinx==1.8.6 sphinx-rtd-theme==1.2.0 sphinxcontrib-napoleon==0.7 From cb4845c40017a3e8e3c2b4e57838de2fd31a1348 Mon Sep 17 00:00:00 2001 From: Patrick Ogenstad Date: Fri, 12 May 2023 18:05:54 +0200 Subject: [PATCH 38/76] Update actions/checkout@v3 actions/setup-python@v4 (#1916) --- .github/workflows/commit.yaml | 8 ++++---- .github/workflows/pythonpublish.yml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index 94de245e9..0329a5554 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -14,10 +14,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -54,10 +54,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index 12d829c1e..ed1ba114e 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -12,9 +12,9 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: '3.x' - name: Install dependencies From f1ce50eedbb2cf8b96d55002769ded54d68e1dd0 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Fri, 19 May 2023 13:04:50 -0700 Subject: [PATCH 39/76] EOS add force_cfg_session_invalid argument (#1927) Co-authored-by: Kevin Petremann --- docs/support/index.rst | 1 + napalm/eos/eos.py | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/support/index.rst b/docs/support/index.rst index 9fa7bd650..78ad1191a 100644 --- a/docs/support/index.rst +++ b/docs/support/index.rst @@ -141,6 +141,7 @@ ____________________________________ * :code:`eos_fn0039_config` (eos) - Transform old style configuration to the new style, available beginning with EOS release 4.23.0, as per FN 0039. Beware that enabling this option will change the configuration you're loading through NAPALM. Default: ``False`` (won't change your configuration commands). .. versionadded:: 3.0.1 +* :code:`force_cfg_session_invalid` (eos) - Force the config_session to be cleared in case of issues, like `discard_config` failure. (default: ``False``) The transport argument ______________________ diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index aaadec1c6..9f653850a 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -96,6 +96,8 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) Optional args: * lock_disable (True/False): force configuration lock to be disabled (for external lock management). + * force_cfg_session_invalid (True/False): force invalidation of the config session + in case of failure. * enable_password (True/False): Enable password for privilege elevation * eos_autoComplete (True/False): Allow for shortening of cli commands * transport (string): transport, eos_transport is a fallback for compatibility. @@ -134,6 +136,10 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) # Define locking method self.lock_disable = self.optional_args.pop("lock_disable", False) + self.force_cfg_session_invalid = self.optional_args.pop( + "force_cfg_session_invalid", False + ) + # eos_transport is there for backwards compatibility, transport is the preferred method transport = self.optional_args.get( "transport", self.optional_args.get("eos_transport", "https") @@ -150,7 +156,6 @@ def _process_optional_args_ssh(self, optional_args): self.netmiko_optional_args = netmiko_args(optional_args) def _process_optional_args_eapi(self, optional_args): - # Parse pyeapi transport class self.transport_class = self._parse_transport(self.transport) @@ -543,8 +548,15 @@ def confirm_commit(self): def discard_config(self): """Implementation of NAPALM method discard_config.""" if self.config_session is not None: - commands = [f"configure session {self.config_session} abort"] - self._run_commands(commands, encoding="text") + try: + commands = [f"configure session {self.config_session} abort"] + self._run_commands(commands, encoding="text") + except Exception: + # If discard fails, you might want to invalidate the config_session (esp. Salt) + # The config_session in EOS is used as the config lock. + if self.force_cfg_session_invalid: + self.config_session = None + raise self.config_session = None def rollback(self): From 40b1364e7c12e6bd3d6f7a0bedc6e3edb725f8a8 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 15 May 2023 15:32:18 -0500 Subject: [PATCH 40/76] eos: refactor vrf parsing Add a fixed width table parser to base string utilities. Use the known dashed line to discern field widths of VRF text output. Use those values instead of TextFSM/regex parsing of the output to determine VRF RD and interface assignments. --- napalm/base/utils/string_parsers.py | 14 ++++++- napalm/eos/eos.py | 62 +++++++++++++++++++++-------- test/base/test_helpers.py | 36 ++++++++++++++++- 3 files changed, 93 insertions(+), 19 deletions(-) diff --git a/napalm/base/utils/string_parsers.py b/napalm/base/utils/string_parsers.py index 5e5df5f57..f14f10e8b 100644 --- a/napalm/base/utils/string_parsers.py +++ b/napalm/base/utils/string_parsers.py @@ -1,6 +1,7 @@ """ Common methods to normalize a string """ import re -from typing import Union, List, Iterable, Dict, Optional +import struct +from typing import Union, List, Iterable, Dict, Optional, Tuple def convert(text: str) -> Union[str, int]: @@ -133,3 +134,14 @@ def convert_uptime_string_seconds(uptime: str) -> int: raise Exception("Unrecognized uptime string:{}".format(uptime)) return uptime_seconds + + +def parse_fixed_width(text: str, *fields: int) -> List[Tuple[str, ...]]: + len = sum(fields) + fmtstring = " ".join(f"{fw}s" for fw in fields) + unpack = struct.Struct(fmtstring).unpack_from + + def parse(line: str) -> Tuple[str, ...]: + return tuple([str(s.decode()) for s in unpack(line.ljust(len).encode())]) + + return [parse(s) for s in text.splitlines()] diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 9f653850a..3eb9935d8 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -2133,12 +2133,37 @@ def get_config(self, retrieve="all", full=False, sanitized=False): def _show_vrf(self): commands = ["show vrf"] - # This command has no JSON yet + # This command has no JSON in EOS < 4.23 raw_output = self._run_commands(commands, encoding="text")[0].get("output", "") - output = napalm.base.helpers.textfsm_extractor(self, "vrf", raw_output) + width_line = raw_output.splitlines()[2] # Line with dashes + fields = width_line.split(" ") + widths = [len(f) + 1 for f in fields] + widths[-1] -= 1 + + parsed_lines = string_parsers.parse_fixed_width(raw_output, *widths) + + vrfs = [] + vrf = {} + current_vrf = None + for line in parsed_lines[3:]: + line = [t.strip() for t in line] + if line[0]: + if current_vrf: + vrfs.append(vrf) + current_vrf = line[0] + vrf = { + "name": current_vrf, + "interfaces": list(), + } + if line[1]: + vrf["route_distinguisher"] = line[1] + if line[4]: + vrf["interfaces"].extend([t.strip() for t in line[4].split(",") if t]) + if current_vrf: + vrfs.append(vrf) - return output + return vrfs def _get_vrfs(self): output = self._show_vrf() @@ -2171,23 +2196,26 @@ def get_network_instances(self, name=""): interfaces[str(line.strip())] = {} all_vrf_interfaces[str(line.strip())] = {} - vrfs[str(vrf["name"])] = { - "name": str(vrf["name"]), - "type": "L3VRF", + vrfs[vrf["name"]] = { + "name": vrf["name"], + "type": "DEFAULT_INSTANCE" if vrf["name"] == "default" else "L3VRF", "state": {"route_distinguisher": vrf["route_distinguisher"]}, "interfaces": {"interface": interfaces}, } - all_interfaces = self.get_interfaces_ip().keys() - vrfs["default"] = { - "name": "default", - "type": "DEFAULT_INSTANCE", - "state": {"route_distinguisher": ""}, - "interfaces": { - "interface": { - k: {} for k in all_interfaces if k not in all_vrf_interfaces.keys() - } - }, - } + if "default" not in vrfs: + all_interfaces = self.get_interfaces_ip().keys() + vrfs["default"] = { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": {"route_distinguisher": ""}, + "interfaces": { + "interface": { + k: {} + for k in all_interfaces + if k not in all_vrf_interfaces.keys() + } + }, + } if name: if name in vrfs: diff --git a/test/base/test_helpers.py b/test/base/test_helpers.py index 96dbb86f5..cd2226877 100644 --- a/test/base/test_helpers.py +++ b/test/base/test_helpers.py @@ -57,7 +57,10 @@ from napalm.base.netmiko_helpers import netmiko_args import napalm.base.exceptions from napalm.base.base import NetworkDriver -from napalm.base.utils.string_parsers import convert_uptime_string_seconds +from napalm.base.utils.string_parsers import ( + convert_uptime_string_seconds, + parse_fixed_width, +) class TestBaseHelpers(unittest.TestCase): @@ -672,6 +675,37 @@ def test_ttp_parse(self): ) self.assertEqual(result, _EXPECTED_RESULT) + def test_parse_fixed_width(self): + _TEST_STRING = """ VRF RD Protocols State Interfaces +---------------- --------------- --------------- ------------------- --------------------------- +123456789012345671234567890123456123456789012345612345678901234567890123456789012345678901234567 +""" # noqa: E501 + _EXPECTED_RESULT = [ + ( + " VRF ", + " RD ", + " Protocols ", + " State ", + "Interfaces ", + ), + ( + "---------------- ", + "--------------- ", + "--------------- ", + "------------------- ", + "---------------------------", + ), + ( + "12345678901234567", + "1234567890123456", + "1234567890123456", + "12345678901234567890", + "123456789012345678901234567", + ), + ] + result = parse_fixed_width(_TEST_STRING, 17, 16, 16, 20, 27) + self.assertEqual(result, _EXPECTED_RESULT) + class FakeNetworkDriver(NetworkDriver): def __init__(self): From 8a9d43e36691a4d17f5c20d8ca4378e960bef714 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 15 May 2023 16:41:32 -0500 Subject: [PATCH 41/76] eos: fix whitespace in test output for vrf I believe when I first collected the output for this test case 6 years ago, I didn't actually collect it from a router, and may have just copied an existing text file and edited it manually. This is an issue since we are trying to switch to fixed-width column parsing for the output. I have hand-edited it this time to match the format and spacing of the other test cases, as I do not have access to the router or config that was used as the source for this test case. --- .../issue-509/show_vrf.text | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text index e81cd6e11..65fdb6529 100644 --- a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text +++ b/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text @@ -1,11 +1,11 @@ Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- ------------ ------------ ------------------- ------------------- -VRFA0 201:201 ipv4 v4:routing; multicast, Vlan2, Vlan102 - v6:no routing + Vrf RD Protocols State Interfaces +------- --------- ------------ ------------------------ ------------------- + VRFA0 201:201 ipv4 v4:routing; multicast, Vlan2, Vlan102 + v6:no routing -VRFA1 203:203 ipv4 v4:routing; multicast, Vlan3, Vlan103 - v6:no routing + VRFA1 203:203 ipv4 v4:routing; multicast, Vlan3, Vlan103 + v6:no routing -VRFA2 205:205 ipv4 v4:routing; multicast, Ethernet1, Vlan100 - v6:no routing + VRFA2 205:205 ipv4 v4:routing; multicast, Ethernet1, Vlan100 + v6:no routing From 333910e7ad9a3221876cf9ac28ae628d64abb4fd Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 15 May 2023 17:01:45 -0500 Subject: [PATCH 42/76] eos: add test case for issue 1922 --- .../issue-1922/expected_result.json | 30 +++++++++++++++++++ .../issue-1922/show_vrf.text | 12 ++++++++ 2 files changed, 42 insertions(+) create mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json create mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json b/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json new file mode 100644 index 000000000..413d219c4 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json @@ -0,0 +1,30 @@ +{ + "management": { + "name": "management", + "type": "L3VRF", + "state": { "route_distinguisher": "" }, + "interfaces": { "interface": { "Management1": {} } } + }, + "default": { + "interfaces": { + "interface": { + "Ethernet1": {}, + "Ethernet2": {}, + "Ethernet3": {}, + "Ethernet4": {}, + "Ethernet49/1": {}, + "Ethernet5": {}, + "Ethernet50/1": {}, + "Ethernet52/1": {}, + "Ethernet53/1": {}, + "Ethernet54/1": {}, + "Ethernet55/1": {}, + "Ethernet56/1": {}, + "Loopback0": {} + } + }, + "state": { "route_distinguisher": "" }, + "type": "DEFAULT_INSTANCE", + "name": "default" + } +} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text new file mode 100644 index 000000000..cd1dbbba4 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text @@ -0,0 +1,12 @@ +Maximum number of vrfs allowed: 1023 + VRF RD Protocols State Interfaces +---------------- --------------- --------------- ------------------- --------------------------- + default ipv4,ipv6 v4:routing, Ethernet1, Ethernet2, + v6:no routing Ethernet3, Ethernet4, + Ethernet49/1, Ethernet5, + Ethernet50/1, Ethernet52/1, + Ethernet53/1, Ethernet54/1, + Ethernet55/1, Ethernet56/1, + Loopback0 + management ipv4,ipv6 v4:routing, Management1 + v6:no routing From 19622758791726773c0f26ca9adaf5bc4fb148bf Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Tue, 16 May 2023 16:45:47 -0500 Subject: [PATCH 43/76] eos: support setting cli_version in unit tests --- test/eos/conftest.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/eos/conftest.py b/test/eos/conftest.py index 7cf515f31..aff8e78a1 100644 --- a/test/eos/conftest.py +++ b/test/eos/conftest.py @@ -37,6 +37,19 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.patched_attrs = ["device"] self.device = FakeEOSDevice() + self._cli_version = 1 + + @property + def cli_version(self): + try: + full_path = self.device.find_file("cli_version.txt") + except IOError: + return self._cli_version + return int(self.device.read_txt_file(full_path)) + + @cli_version.setter + def cli_version(self, value): + self._cli_version = value class FakeEOSDevice(BaseTestDouble): From f9103a12ca344a3b85aa28ad71f11c8d8370113a Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Tue, 16 May 2023 16:49:38 -0500 Subject: [PATCH 44/76] eos: support using json version of show vrf If version of EOS is new enough (>= 4.23.0), use the JSON output of "show vrf" to avoid issues with text parsing in 4.28+ Anecdotal evidence suggests that "default" was added to the text output of "show vrf" in 4.23, so this also resolves the double route issue in 1919. closes #1919 --- napalm/eos/eos.py | 21 ++++++- .../vrf/cli_version.txt | 1 + .../vrf/expected_result.json | 31 ++++++++++ .../vrf/show_vrf.json | 61 +++++++++++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt create mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json create mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 3eb9935d8..d5554f434 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -2130,7 +2130,20 @@ def get_config(self, retrieve="all", full=False, sanitized=False): else: raise Exception("Wrong retrieve filter: {}".format(retrieve)) - def _show_vrf(self): + def _show_vrf_json(self): + commands = ["show vrf"] + + vrfs = self._run_commands(commands)[0]["vrfs"] + return [ + { + "name": k, + "interfaces": [i for i in v["interfaces"]], + "route_distinguisher": v["routeDistinguisher"], + } + for k, v in vrfs.items() + ] + + def _show_vrf_text(self): commands = ["show vrf"] # This command has no JSON in EOS < 4.23 @@ -2165,6 +2178,12 @@ def _show_vrf(self): return vrfs + def _show_vrf(self): + if self.cli_version == 2: + return self._show_vrf_json() + else: + return self._show_vrf_text() + def _get_vrfs(self): output = self._show_vrf() diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt b/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt @@ -0,0 +1 @@ +2 diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json b/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json new file mode 100644 index 000000000..dc3f3d294 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json @@ -0,0 +1,31 @@ +{ + "default": { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": { "route_distinguisher": "" }, + "interfaces": { + "interface": { + "Ethernet1": {}, + "Ethernet2": {}, + "Loopback0": {}, + "Management0": {} + } + } + }, + "foo": { + "name": "foo", + "type": "L3VRF", + "state": { "route_distinguisher": "0:1" }, + "interfaces": { + "interface": {} + } + }, + "bar": { + "name": "bar", + "type": "L3VRF", + "state": { "route_distinguisher": "" }, + "interfaces": { + "interface": {} + } + } +} diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json b/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json new file mode 100644 index 000000000..bbc04245a --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json @@ -0,0 +1,61 @@ +{ + "vrfs": { + "foo": { + "routeDistinguisher": "0:1", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfacesV4": [], + "interfacesV6": [], + "interfaces": [] + }, + "bar": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "down" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfacesV4": [], + "interfacesV6": [], + "interfaces": [] + }, + "default": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfacesV4": ["Ethernet1", "Ethernet2", "Loopback0", "Management0"], + "interfacesV6": ["Management0"], + "interfaces": ["Ethernet1", "Ethernet2", "Loopback0", "Management0"] + } + } +} From 397d7f3605f15e31fb83eab1788a520cc6c511cc Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 23 May 2023 09:39:16 -0700 Subject: [PATCH 45/76] Fixing IOS-XR with no BGP configured (xml agent) (#1925) --- napalm/iosxr/iosxr.py | 7 +++++++ ...me___Naming___Instance___BGP___Configuration___Get_.txt | 2 ++ .../test_get_bgp_config/no_bgp/expected_result.json | 1 + 3 files changed, 10 insertions(+) create mode 100644 test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt create mode 100644 test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json diff --git a/napalm/iosxr/iosxr.py b/napalm/iosxr/iosxr.py index 2ef1f6cb4..383e8ae00 100644 --- a/napalm/iosxr/iosxr.py +++ b/napalm/iosxr/iosxr.py @@ -987,6 +987,13 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): default" result_tree = ETREE.fromstring(self.device.make_rpc_call(rpc_command)) + # Check if BGP is not configured. + get_tag = result_tree.find("./Get") + if get_tag is not None: + bgp_not_found = get_tag.attrib.get("ItemNotFound") + if bgp_not_found: + return {} + bgp_asn = napalm.base.helpers.convert( int, napalm.base.helpers.find_txt( diff --git a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt new file mode 100644 index 000000000..1bcd305b2 --- /dev/null +++ b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt @@ -0,0 +1,2 @@ + +default diff --git a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} From b6de74e81db806670a165d7f0498c356f56840c7 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 23 May 2023 09:50:25 -0700 Subject: [PATCH 46/76] Implement no BGP for IOSXR-netconf (#1926) --- napalm/iosxr_netconf/iosxr_netconf.py | 8 +++++++- .../test_get_bgp_config/no_bgp/expected_result.json | 1 + .../no_bgp/ipv4-bgp-cfg_bgp__running.xml | 6 ++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json create mode 100644 test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml diff --git a/napalm/iosxr_netconf/iosxr_netconf.py b/napalm/iosxr_netconf/iosxr_netconf.py index 0640f4c82..ff7a06ef8 100644 --- a/napalm/iosxr_netconf/iosxr_netconf.py +++ b/napalm/iosxr_netconf/iosxr_netconf.py @@ -1366,6 +1366,12 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): # Converts string to etree result_tree = ETREE.fromstring(rpc_reply) + data_ele = result_tree.find("./{*}data") + # If there are no children in "", then there is no BGP configured + bgp_configured = bool(len(data_ele.getchildren())) + if not bgp_configured: + return {} + if not group: neighbor = "" @@ -3148,7 +3154,7 @@ def get_config(self, retrieve="all", full=False, sanitized=False): if config[datastore] != "": if encoding == "cli": cli_tree = ETREE.XML(config[datastore], parser=parser)[0] - if cli_tree: + if len(cli_tree): config[datastore] = cli_tree[0].text.strip() else: config[datastore] = "" diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml new file mode 100644 index 000000000..7a3a0b218 --- /dev/null +++ b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml @@ -0,0 +1,6 @@ + + + + From c2d2e2063bb8bec8e9a06938306a98a35dbbe6e4 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 23 May 2023 10:11:34 -0700 Subject: [PATCH 47/76] Fix dependabot issues (#1934) --- requirements-dev.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 3d6b0cf20..62923790b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,16 +2,16 @@ black==22.6.0 coveralls==3.3.1 ddt==1.6.0 flake8-import-order==0.18.2 -pytest==7.2.2 +pytest==7.3.1 pytest-cov==4.0.0 pytest-json-report==1.5.0 pyflakes==3.0.1 pylama==8.4.1 -mock==5.0.1 +mock==5.0.2 mypy==0.982 -types-PyYAML==6.0.12.8 +types-PyYAML==6.0.12.10 types-requests==2.28.11.17 -types-six==1.16.21.7 -types-setuptools==67.6.0.5 -ttp==0.9.0 -ttp_templates==0.3.4 +types-six==1.16.21.8 +types-setuptools==67.8.0.0 +ttp==0.9.4 +ttp_templates==0.3.5 From 26b7bfb9c4affe8f2f9408f933d28b24520a655a Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 23 May 2023 10:23:36 -0700 Subject: [PATCH 48/76] NAPALM 4.1.0 (#1935) --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 9eb0865d0..0a3bbe374 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="napalm", - version="4.0.0", + version="4.1.0", packages=find_packages(exclude=("test*",)), test_suite="test_base", author="David Barroso, Kirk Byers, Mircea Ulinic", From 02a7657b2c80c4474c2ac6938fff99f5802f2cae Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 23 May 2023 10:34:43 -0700 Subject: [PATCH 49/76] NAPALM 4.1.0 Release (#1936) --- .github/workflows/commit.yaml | 14 +- .github/workflows/pythonpublish.yml | 17 +- .gitignore | 1 + .readthedocs.yml | 3 +- docs/conf.py | 6 +- docs/development/testing_framework.rst | 55 +++- docs/requirements.txt | 13 +- docs/support/index.rst | 3 +- docs/support/ios.rst | 2 +- docs/support/nxos.rst | 2 +- docs/test.sh | 10 +- napalm/base/base.py | 8 +- napalm/base/canonical_map.py | 157 +---------- napalm/base/helpers.py | 111 ++------ napalm/base/test/getters.py | 2 +- napalm/base/utils/string_parsers.py | 16 +- napalm/eos/eos.py | 252 ++++++++++++------ napalm/ios/ios.py | 94 ++++--- napalm/iosxr/iosxr.py | 66 +++-- napalm/iosxr_netconf/iosxr_netconf.py | 65 +++-- napalm/junos/junos.py | 95 +++++-- napalm/junos/utils/junos_views.yml | 9 + napalm/nxos/nxos.py | 24 +- napalm/nxos_ssh/nxos_ssh.py | 105 ++++++-- napalm/pyIOSXR/iosxr.py | 2 +- requirements-dev.txt | 30 +-- requirements.txt | 4 +- setup.cfg | 4 +- setup.py | 2 +- test/base/test_helpers.py | 125 +++------ test/eos/conftest.py | 13 + .../expected_result.json | 23 +- .../issue_1113_dot_asn/expected_result.json | 31 ++- .../expected_result.json | 57 ++++ ...w_running_config___section_router_bgp.text | 11 + .../no_bgp_config/expected_result.json | 1 + ..._running_config___section_router_bgp.text} | 0 .../normal/expected_result.json | 98 ++++++- ...___Local_AS_Desc_BGP_state__remote_r.text} | 0 ...AS___Local_AS_Desc_BGP_state__remote.text} | 0 ...___Local_AS_Desc_BGP_state__remote_r.text} | 0 ..._AS___Local_AS_Desc_BGP_state__remote.text | 0 .../issue1759/expected_result.json | 112 ++++++++ ...S___Local_AS_Desc_BGP_state__remote_r.text | 0 .../show_ip_bgp_summary_vrf_all.json | 76 ++++++ ..._AS___Local_AS_Desc_BGP_state__remote.text | 30 +++ .../show_ipv6_bgp_summary_vrf_all.json | 76 ++++++ ...___Local_AS_Desc_BGP_state__remote_r.text} | 0 ...AS___Local_AS_Desc_BGP_state__remote.text} | 0 ...___Local_AS_Desc_BGP_state__remote_r.text} | 0 ...AS___Local_AS_Desc_BGP_state__remote.text} | 0 ...___Local_AS_Desc_BGP_state__remote_r.text} | 0 ...AS___Local_AS_Desc_BGP_state__remote.text} | 0 .../issue-1922/expected_result.json | 30 +++ .../issue-1922/show_vrf.text | 12 + .../issue-509/show_vrf.text | 16 +- .../vrf/cli_version.txt | 1 + .../vrf/expected_result.json | 31 +++ .../vrf/show_vrf.json | 61 +++++ .../expected_result.json | 8 +- .../no_afi/expected_result.json | 4 +- .../no_bgp/expected_result.json | 1 + .../no_bgp/show_running_config.txt | 150 +++++++++++ .../normal/expected_result.json | 21 +- .../peers_without_groups/expected_result.json | 6 +- .../no_mac_support/expected_result.json | 15 ++ .../no_mac_support/show_lldp_neighbors.txt | 8 + .../show_lldp_neighbors_detail.txt | 68 +++++ .../expected_result.json | 12 +- ..._Instance___BGP___Configuration___Get_.txt | 2 + .../no_bgp/expected_result.json | 1 + .../normal/expected_result.json | 23 +- .../peers_without_groups/expected_result.json | 6 +- .../no_bgp/expected_result.json | 1 + .../no_bgp/ipv4-bgp-cfg_bgp__running.xml | 6 + .../normal/expected_result.json | 39 ++- ...em____routing_options___configuration_.xml | 7 + .../nhs/expected_result.json | 74 ++++- ...ent____policy_options___configuration_.xml | 2 + ...up____bgp___protocols___configuration_.xml | 2 + ...em____routing_options___configuration_.xml | 2 + .../no_bgp/expected_result.json | 1 + ...em____routing_options___configuration_.xml | 7 + .../normal/expected_result.json | 70 ++++- .../normal/expected_result.json | 36 +++ .../normal/show_vrf_detail___json.txt | 58 ++++ .../normal/show_vrf_interface___json.txt | 78 ++++++ test/pyiosxr/test_iosxr.py | 2 +- tox.ini | 39 --- 89 files changed, 1997 insertions(+), 728 deletions(-) create mode 100644 test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json create mode 100644 test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text create mode 100644 test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json rename test/eos/mocked_data/{test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1168/{show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1168/{show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1356/{show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text} (100%) create mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text create mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json create mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text create mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json create mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text create mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json rename test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/{show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/{show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue944/{show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue944/{show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/normal/{show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/normal/{show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text => show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text} (100%) create mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json create mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text create mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt create mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json create mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json create mode 100644 test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json create mode 100644 test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt create mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt create mode 100644 test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt create mode 100644 test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json create mode 100644 test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json create mode 100644 test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml create mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json create mode 100644 test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml create mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json create mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt create mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt delete mode 100644 tox.ini diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index f7d265f1f..0329a5554 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -10,14 +10,14 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.7, 3.8, 3.9, 3.10.0] + python-version: [3.7, 3.8, 3.9, 3.10.9, 3.11] steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -54,10 +54,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -65,9 +65,9 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -e . - pip install -r requirements.txt - pip install -r requirements-dev.txt python -m pip install -r docs/requirements.txt + pip install -r requirements-dev.txt + pip install -r requirements.txt - name: Doctests run: | diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index 1fba0b41b..ed1ba114e 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -12,19 +12,20 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: '3.x' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel twine - - name: Build and publish - env: - TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} + pip install setuptools wheel + - name: Build run: | python setup.py sdist bdist_wheel - twine upload dist/* + - name: Publish + uses: pypa/gh-action-pypi-publish@master + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} diff --git a/.gitignore b/.gitignore index a00f7f807..87330b57c 100644 --- a/.gitignore +++ b/.gitignore @@ -65,6 +65,7 @@ env test/unit/test_devices.py +.report.json report.json tags .pytest_cache/ diff --git a/.readthedocs.yml b/.readthedocs.yml index 65fd950da..320d0121d 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -14,9 +14,10 @@ formats: all # Optionally set the version of Python and requirements required to build your docs python: - version: 3.7 + version: 3.8 install: - method: pip path: . - requirements: docs/requirements.txt + - requirements: requirements-dev.txt - requirements: requirements.txt diff --git a/docs/conf.py b/docs/conf.py index cf56e0537..d9b5774cd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -371,13 +371,13 @@ def build_getters_support_matrix(app): if not (m.startswith("_") or m in EXCLUDE_METHODS) } - regex_name = re.compile(r"(?P\w+)\/.*::test_(?P\w+)") + regex_name = re.compile(r"test.*/(?P\w+)\/.*::test_(?P\w+)") filename = "./support/tests/report.json" with open(filename, "r") as f: data = json.loads(f.read()) - for test in data["report"]["tests"]: - match = regex_name.search(test["name"]) + for test in data["tests"]: + match = regex_name.search(test["nodeid"]) if match: driver = match.group("driver") drivers.add(driver) diff --git a/docs/development/testing_framework.rst b/docs/development/testing_framework.rst index 2b61cc9da..ef5a7ed7f 100644 --- a/docs/development/testing_framework.rst +++ b/docs/development/testing_framework.rst @@ -1,7 +1,7 @@ Testing Framework ----------------- -As napalm consists of multiple drivers and all of them have to provide similar functionality, we have developed a testing framework to provide a consistent test suite for all the drivers. +As NAPALM consists of multiple drivers and all of them have to provide similar functionality, we have developed a testing framework to provide a consistent test suite for all the drivers. Features ________ @@ -42,7 +42,7 @@ By default, the tests are going to be run against mocked data but you can change * ``NAPALM_USERNAME`` * ``NAPALM_PASSWORD`` * ``NAPALM_OPTIONAL_ARGS`` - + Mocking the ``open`` method ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,29 +56,29 @@ Multiple test cases:: (napalm) ➜ napalm-eos git:(test_framework) ✗ ls test/unit/mocked_data/test_get_bgp_neighbors lots_of_peers no_peers normal (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors - ... + ... test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[lots_of_peers] <- ../napalm/napalm.base/test/getters.py PASSED test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[no_peers] <- ../napalm/napalm.base/test/getters.py PASSED test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[normal] <- ../napalm/napalm.base/test/getters.py PASSED - + Missing test cases:: (napalm) ➜ napalm-eos git:(test_framework) ✗ ls test/unit/mocked_data/test_get_bgp_neighbors ls: test/unit/mocked_data/test_get_bgp_neighbors: No such file or directory (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors - ... + ... test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[no_test_case_found] <- ../napalm/napalm.base/test/getters.py FAILED - + ========================================================= FAILURES ========================================================== ___________________________________ TestGetter.test_get_bgp_neighbors[no_test_case_found] ___________________________________ - + cls = , test_case = 'no_test_case_found' - + @functools.wraps(func) def wrapper(cls, test_case): cls.device.device.current_test = func.__name__ cls.device.device.current_test_case = test_case - + try: # This is an ugly, ugly, ugly hack because some python objects don't load # as expected. For example, dicts where integers are strings @@ -87,7 +87,7 @@ Missing test cases:: if test_case == "no_test_case_found": > pytest.fail("No test case for '{}' found".format(func.__name__)) E Failed: No test case for 'test_get_bgp_neighbors' found - + ../napalm/napalm.base/test/getters.py:64: Failed ================================================= 1 failed in 0.12 seconds ================================================== @@ -96,8 +96,41 @@ Method not implemented:: (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_probes_config ... test/unit/test_getters.py::TestGetter::test_get_probes_config[no_test_case_found] <- ../napalm/napalm.base/test/getters.py SKIPPED - + ================================================= 1 skipped in 0.09 seconds ================================================= +Testing Matrix +-------------- + +NAPALM leverages [Github Actions](https://docs.github.com/en/actions) to test and lint code on commits and pull requests. +If you want to test prior to opening a pull request, you can use [nektos/act](https://github.com/nektos/act) and Docker to locally run the tests + +.. code-block:: console + + $ act -j std_tests + [build/std_tests-4] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-3] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-1] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-2] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-5] 🚀 Start image=catthehacker/ubuntu:act-latest + [build/std_tests-4] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-1] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-3] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-5] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + [build/std_tests-2] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true + + ... + + | --------------------------------------------------------------------- + | TOTAL 9258 1836 80% + | + | ================= 619 passed, 80 skipped, 3 warnings in 19.97s ================= + [build/std_tests-5] ✅ Success - Main Run Tests + [build/std_tests-5] ⭐ Run Post Setup Python 3.11 + [build/std_tests-5] 🐳 docker exec cmd=[node /var/run/act/actions/actions-setup-python@v2/dist/cache-save/index.js] user= workdir= + [build/std_tests-5] ✅ Success - Post Setup Python 3.11 + [build/std_tests-5] 🏁 Job succeeded + + .. _`test_getters.py`: https://github.com/napalm-automation/napalm-eos/blob/a2fc2cf6a98b0851efe4cba907086191b8f1df02/test/unit/test_getters.py .. _`conftest.py`: https://github.com/napalm-automation/napalm-eos/blob/a2fc2cf6a98b0851efe4cba907086191b8f1df02/test/unit/conftest.py diff --git a/docs/requirements.txt b/docs/requirements.txt index f822bffdb..24e3fa96b 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,9 @@ -sphinx -sphinx-rtd-theme -sphinxcontrib-napoleon -invoke +urllib3==1.26.15 # https://github.com/readthedocs/readthedocs.org/issues/10290 +sphinx==1.8.6 +sphinx-rtd-theme==1.2.0 +sphinxcontrib-napoleon==0.7 +invoke==2.0.0 +jinja2==2.11.3 +MarkupSafe==2.0.1 +pytest==7.2.2 +ansible==4.10.0 diff --git a/docs/support/index.rst b/docs/support/index.rst index f869f592c..78ad1191a 100644 --- a/docs/support/index.rst +++ b/docs/support/index.rst @@ -13,7 +13,7 @@ General support matrix ===================== ========== ============= ==================== ================== ============ ============ ============ **Driver Name** eos junos iosxr_netconf iosxr nxos nxos_ssh ios **Structured data** Yes Yes Yes No Yes No No - **Minimum version** 4.15.0F 12.1 7.0 5.1.0 6.1 [#g1]_ 12.4(20)T 6.3.2 + **Minimum version** 4.15.0F 12.1 7.0 5.1.0 6.1 [#g1]_ 6.3.2 12.4(20)T **Backend library** `pyeapi`_ `junos-eznc`_ `ncclient`_ `pyIOSXR`_ `pynxos`_ `netmiko`_ `netmiko`_ **Caveats** :doc:`eos` :doc:`iosxr_netconf` :doc:`nxos` :doc:`nxos` :doc:`ios` ===================== ========== ============= ==================== ================== ============ ============ ============ @@ -141,6 +141,7 @@ ____________________________________ * :code:`eos_fn0039_config` (eos) - Transform old style configuration to the new style, available beginning with EOS release 4.23.0, as per FN 0039. Beware that enabling this option will change the configuration you're loading through NAPALM. Default: ``False`` (won't change your configuration commands). .. versionadded:: 3.0.1 +* :code:`force_cfg_session_invalid` (eos) - Force the config_session to be cleared in case of issues, like `discard_config` failure. (default: ``False``) The transport argument ______________________ diff --git a/docs/support/ios.rst b/docs/support/ios.rst index b46a92a54..1bbc5116e 100644 --- a/docs/support/ios.rst +++ b/docs/support/ios.rst @@ -116,7 +116,7 @@ File Operation Prompts ______________________ By default IOS will prompt for confirmation on file operations. These prompts need to be disabled before the NAPALM-ios driver performs any such operation on the device. -This can be controlled using the `auto_file_prompt` optional arguement: +This can be controlled using the `auto_file_prompt` optional argument: * `auto_file_prompt=True` (default): NAPALM will automatically add `file prompt quiet` to the device configuration before performing file operations, and un-configure it again afterwards. If the device already had the command in its configuration then it will be silently removed as a result, and diff --git a/docs/support/nxos.rst b/docs/support/nxos.rst index 0dfff92be..9f9e5ee8b 100644 --- a/docs/support/nxos.rst +++ b/docs/support/nxos.rst @@ -71,7 +71,7 @@ One caveat of using netutils diff of configurations is that the diff is performe Example assuming that the device config contains: -.. code-block:: +.. code-block:: bash interface loopback0 ip address 10.1.4.4/32 diff --git a/docs/test.sh b/docs/test.sh index 78a572fac..3d102c74a 100755 --- a/docs/test.sh +++ b/docs/test.sh @@ -1,14 +1,12 @@ #!/bin/bash CWD=`pwd` TEST_RESULTS_PATH="$CWD/support/tests" +REPOBASE=$CWD/.. -if [ ! -f "report.json" ]; then +if [ ! -f ".report.json" ]; then set -e - pip install -r ../requirements.txt -r ../requirements-dev.txt + pytest --rootdir $REPOBASE -c /dev/null --json-report --cov=./ -vs $REPOBASE/test*/*/test_getters.py - set +e - py.test -c /dev/null --cov=./ -vs --json=report.json ../test*/*/test_getters.py set -e - - cp report.json $TEST_RESULTS_PATH/report.json + cp .report.json $TEST_RESULTS_PATH/report.json fi diff --git a/napalm/base/base.py b/napalm/base/base.py index 1259f6966..7410bf6a8 100644 --- a/napalm/base/base.py +++ b/napalm/base/base.py @@ -19,6 +19,7 @@ from typing_extensions import Literal from netmiko import ConnectHandler, NetMikoTimeoutException +from netutils.interface import canonical_interface_name # local modules import napalm.base.exceptions @@ -647,7 +648,8 @@ def get_bgp_config( :param neighbor: Returns the configuration of a specific BGP neighbor. Main dictionary keys represent the group name and the values represent a dictionary having - the keys below. Neighbors which aren't members of a group will be stored in a key named "_": + the keys below. A default group named "_" will contain information regarding global + settings and any neighbors that are not members of a group. * type (string) * description (string) @@ -1804,8 +1806,6 @@ def compliance_report( def _canonical_int(self, interface: str) -> str: """Expose the helper function within this class.""" if self.use_canonical_interface is True: - return napalm.base.helpers.canonical_interface_name( - interface, addl_name_map=None - ) + return canonical_interface_name(interface, addl_name_map=None) else: return interface diff --git a/napalm/base/canonical_map.py b/napalm/base/canonical_map.py index 29b50e714..fb9658213 100644 --- a/napalm/base/canonical_map.py +++ b/napalm/base/canonical_map.py @@ -1,153 +1,4 @@ -base_interfaces = { - "ATM": "ATM", - "AT": "ATM", - "B": "Bdi", - "Bd": "Bdi", - "Bdi": "Bdi", - "EOBC": "EOBC", - "EO": "EOBC", - "Ethernet": "Ethernet", - "Eth": "Ethernet", - "eth": "Ethernet", - "Et": "Ethernet", - "et": "Ethernet", - "FastEthernet": "FastEthernet", - "FastEth": "FastEthernet", - "FastE": "FastEthernet", - "Fast": "FastEthernet", - "Fas": "FastEthernet", - "FE": "FastEthernet", - "Fa": "FastEthernet", - "fa": "FastEthernet", - "Fddi": "Fddi", - "FD": "Fddi", - "FortyGigabitEthernet": "FortyGigabitEthernet", - "FortyGigEthernet": "FortyGigabitEthernet", - "FortyGigEth": "FortyGigabitEthernet", - "FortyGigE": "FortyGigabitEthernet", - "FortyGig": "FortyGigabitEthernet", - "FGE": "FortyGigabitEthernet", - "FO": "FortyGigabitEthernet", - "Fo": "FortyGigabitEthernet", - "FiftyGigabitEthernet": "FiftyGigabitEthernet", - "FiftyGigEthernet": "FiftyGigabitEthernet", - "FiftyGigEth": "FiftyGigabitEthernet", - "FiftyGigE": "FiftyGigabitEthernet", - "FI": "FiftyGigabitEthernet", - "Fi": "FiftyGigabitEthernet", - "fi": "FiftyGigabitEthernet", - "GigabitEthernet": "GigabitEthernet", - "GigEthernet": "GigabitEthernet", - "GigEth": "GigabitEthernet", - "GigE": "GigabitEthernet", - "Gig": "GigabitEthernet", - "GE": "GigabitEthernet", - "Ge": "GigabitEthernet", - "ge": "GigabitEthernet", - "Gi": "GigabitEthernet", - "gi": "GigabitEthernet", - "HundredGigabitEthernet": "HundredGigabitEthernet", - "HundredGigEthernet": "HundredGigabitEthernet", - "HundredGigEth": "HundredGigabitEthernet", - "HundredGigE": "HundredGigabitEthernet", - "HundredGig": "HundredGigabitEthernet", - "Hu": "HundredGigabitEthernet", - "TwentyFiveGigabitEthernet": "TwentyFiveGigabitEthernet", - "TwentyFiveGigEthernet": "TwentyFiveGigabitEthernet", - "TwentyFiveGigEth": "TwentyFiveGigabitEthernet", - "TwentyFiveGigE": "TwentyFiveGigabitEthernet", - "TwentyFiveGig": "TwentyFiveGigabitEthernet", - "TF": "TwentyFiveGigabitEthernet", - "Tf": "TwentyFiveGigabitEthernet", - "tf": "TwentyFiveGigabitEthernet", - "TwoHundredGigabitEthernet": "TwoHundredGigabitEthernet", - "TwoHundredGigEthernet": "TwoHundredGigabitEthernet", - "TwoHundredGigEth": "TwoHundredGigabitEthernet", - "TwoHundredGigE": "TwoHundredGigabitEthernet", - "TwoHundredGig": "TwoHundredGigabitEthernet", - "TH": "TwoHundredGigabitEthernet", - "Th": "TwoHundredGigabitEthernet", - "th": "TwoHundredGigabitEthernet", - "FourHundredGigabitEthernet": "FourHundredGigabitEthernet", - "FourHundredGigEthernet": "FourHundredGigabitEthernet", - "FourHundredGigEth": "FourHundredGigabitEthernet", - "FourHundredGigE": "FourHundredGigabitEthernet", - "FourHundredGig": "FourHundredGigabitEthernet", - "F": "FourHundredGigabitEthernet", - "f": "FourHundredGigabitEthernet", - "Loopback": "Loopback", - "loopback": "Loopback", - "Lo": "Loopback", - "lo": "Loopback", - "Management": "Management", - "Mgmt": "Management", - "mgmt": "Management", - "Ma": "Management", - "Management_short": "Ma", - "MFR": "MFR", - "Multilink": "Multilink", - "Mu": "Multilink", - "n": "nve", - "nv": "nve", - "nve": "nve", - "PortChannel": "Port-channel", - "Port-channel": "Port-channel", - "Port-Channel": "Port-channel", - "port-channel": "Port-channel", - "po": "Port-channel", - "Po": "Port-channel", - "POS": "POS", - "PO": "POS", - "Serial": "Serial", - "Se": "Serial", - "S": "Serial", - "TenGigabitEthernet": "TenGigabitEthernet", - "TenGigEthernet": "TenGigabitEthernet", - "TenGigEth": "TenGigabitEthernet", - "TenGig": "TenGigabitEthernet", - "TeGig": "TenGigabitEthernet", - "Ten": "TenGigabitEthernet", - "T": "TenGigabitEthernet", - "Te": "TenGigabitEthernet", - "te": "TenGigabitEthernet", - "Tunnel": "Tunnel", - "Tun": "Tunnel", - "Tu": "Tunnel", - "Twe": "TwentyFiveGigE", - "Tw": "TwoGigabitEthernet", - "Two": "TwoGigabitEthernet", - "Virtual-Access": "Virtual-Access", - "Vi": "Virtual-Access", - "Virtual-Template": "Virtual-Template", - "Vt": "Virtual-Template", - "VLAN": "VLAN", - "V": "VLAN", - "Vl": "VLAN", - "Wlan-GigabitEthernet": "Wlan-GigabitEthernet", -} - -reverse_mapping = { - "ATM": "At", - "EOBC": "EO", - "Ethernet": "Et", - "FastEthernet": "Fa", - "Fddi": "FD", - "FortyGigabitEthernet": "Fo", - "GigabitEthernet": "Gi", - "HundredGigabitEthernet": "Hu", - "Loopback": "Lo", - "Management": "Ma", - "MFR": "MFR", - "Multilink": "Mu", - "Port-channel": "Po", - "POS": "PO", - "Serial": "Se", - "TenGigabitEthernet": "Te", - "Tunnel": "Tu", - "TwoGigabitEthernet": "Two", - "TwentyFiveGigE": "Twe", - "Virtual-Access": "Vi", - "Virtual-Template": "Vt", - "VLAN": "Vl", - "Wlan-GigabitEthernet": "Wl-Gi", -} +# Do not remove the below imports, functions were moved to netutils, but to not +# break backwards compatibility, these should remain +from netutils.constants import BASE_INTERFACES as base_interfaces # noqa +from netutils.constants import REVERSE_MAPPING as reverse_mapping # noqa diff --git a/napalm/base/helpers.py b/napalm/base/helpers.py index 935dfd58d..dd58ddc7a 100644 --- a/napalm/base/helpers.py +++ b/napalm/base/helpers.py @@ -1,4 +1,5 @@ """Helper functions for the NAPALM base.""" +import ipaddress import itertools import logging @@ -14,10 +15,17 @@ import textfsm from lxml import etree from netaddr import EUI -from netaddr import IPAddress from netaddr import mac_unix from netutils.config.parser import IOSConfigParser +# Do not remove the below imports, functions were moved to netutils, but to not +# break backwards compatibility, these should remain +from netutils.interface import abbreviated_interface_name # noqa +from netutils.interface import canonical_interface_name # noqa +from netutils.constants import BASE_INTERFACES as base_interfaces # noqa +from netutils.constants import REVERSE_MAPPING as reverse_mapping # noqa +from netutils.interface import split_interface as _split_interface + try: from ttp import quick_parse as ttp_quick_parse @@ -30,7 +38,6 @@ from napalm.base import constants from napalm.base.models import ConfigDict from napalm.base.utils.jinja_filters import CustomJinjaFilters -from napalm.base.canonical_map import base_interfaces, reverse_mapping T = TypeVar("T") R = TypeVar("R") @@ -537,10 +544,19 @@ def ip(addr: str, version: Optional[int] = None) -> str: >>> ip('2001:0dB8:85a3:0000:0000:8A2e:0370:7334') u'2001:db8:85a3::8a2e:370:7334' """ - addr_obj = IPAddress(addr) + scope = "" + if "%" in addr: + addr, scope = addr.split("%", 1) + addr_obj = ipaddress.ip_address(addr) if version and addr_obj.version != version: raise ValueError("{} is not an ipv{} address".format(addr, version)) - return str(addr_obj) + if addr_obj.version == 6 and addr_obj.ipv4_mapped is not None: + return_addr = "%s:%s" % ("::ffff", addr_obj.ipv4_mapped) + else: + return_addr = str(addr_obj) + if scope: + return_addr = "%s%%%s" % (return_addr, scope) + return return_addr def as_number(as_number_val: str) -> int: @@ -555,92 +571,7 @@ def as_number(as_number_val: str) -> int: def split_interface(intf_name: str) -> Tuple[str, str]: """Split an interface name based on first digit, slash, or space match.""" - head = intf_name.rstrip(r"/\0123456789. ") - tail = intf_name[len(head) :].lstrip() - return (head, tail) - - -def canonical_interface_name( - interface: str, addl_name_map: Optional[Dict[str, str]] = None -) -> str: - """Function to return an interface's canonical name (fully expanded name). - - Use of explicit matches used to indicate a clear understanding on any potential - match. Regex and other looser matching methods were not implmented to avoid false - positive matches. As an example, it would make sense to do "[P|p][O|o]" which would - incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not - easily troubleshot, found, or known. - - :param interface: The interface you are attempting to expand. - :param addl_name_map: A dict containing key/value pairs that updates - the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs - {"Po": "Port-Channel"} - :type addl_name_map: optional - """ - - name_map = {} - name_map.update(base_interfaces) - interface_type, interface_number = split_interface(interface) - - if isinstance(addl_name_map, dict): - name_map.update(addl_name_map) - # check in dict for mapping - if name_map.get(interface_type): - long_int = name_map.get(interface_type) - assert isinstance(long_int, str) - return long_int + str(interface_number) - # if nothing matched, return the original name - else: - return interface - - -def abbreviated_interface_name( - interface: str, - addl_name_map: Optional[Dict[str, str]] = None, - addl_reverse_map: Optional[Dict[str, str]] = None, -) -> str: - """Function to return an abbreviated representation of the interface name. - - :param interface: The interface you are attempting to abbreviate. - :param addl_name_map: A dict containing key/value pairs that updates - the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs - {"Po": "Port-Channel"} - :type addl_name_map: optional - :param addl_reverse_map: A dict containing key/value pairs that updates - the reverse mapping. Used if an OS has specific differences. e.g. {"PortChannel": "Po"} vs - {"PortChannel": "po"} - :type addl_reverse_map: optional - """ - - name_map = {} - name_map.update(base_interfaces) - interface_type, interface_number = split_interface(interface) - - if isinstance(addl_name_map, dict): - name_map.update(addl_name_map) - - rev_name_map = {} - rev_name_map.update(reverse_mapping) - - if isinstance(addl_reverse_map, dict): - rev_name_map.update(addl_reverse_map) - - # Try to ensure canonical type. - if name_map.get(interface_type): - canonical_type = name_map.get(interface_type) - else: - canonical_type = interface_type - - assert isinstance(canonical_type, str) - - try: - abbreviated_name = rev_name_map[canonical_type] + str(interface_number) - return abbreviated_name - except KeyError: - pass - - # If abbreviated name lookup fails, return original name - return interface + return _split_interface(interface=intf_name) def transform_lldp_capab(capabilities: Union[str, Any]) -> List[str]: diff --git a/napalm/base/test/getters.py b/napalm/base/test/getters.py index cc64f551e..0a2e47a66 100644 --- a/napalm/base/test/getters.py +++ b/napalm/base/test/getters.py @@ -244,7 +244,7 @@ def test_get_lldp_neighbors_detail(self, test_case): def test_get_bgp_config(self, test_case): """Test get_bgp_config.""" get_bgp_config = self.device.get_bgp_config() - assert len(get_bgp_config) > 0 + assert get_bgp_config == {} or len(get_bgp_config) > 0 for bgp_group in get_bgp_config.values(): assert helpers.test_model(models.BPGConfigGroupDict, bgp_group) diff --git a/napalm/base/utils/string_parsers.py b/napalm/base/utils/string_parsers.py index c7dd8f376..f14f10e8b 100644 --- a/napalm/base/utils/string_parsers.py +++ b/napalm/base/utils/string_parsers.py @@ -1,6 +1,7 @@ """ Common methods to normalize a string """ import re -from typing import Union, List, Iterable, Dict, Optional +import struct +from typing import Union, List, Iterable, Dict, Optional, Tuple def convert(text: str) -> Union[str, int]: @@ -50,7 +51,7 @@ def colon_separated_string_to_dict( dictionary[line_data[0].strip()] = None else: raise Exception( - "Something went wrong parsing the colo separated string {}".format(line) + f"Something went wrong parsing the colon separated string:\n\n{line}" ) return dictionary @@ -133,3 +134,14 @@ def convert_uptime_string_seconds(uptime: str) -> int: raise Exception("Unrecognized uptime string:{}".format(uptime)) return uptime_seconds + + +def parse_fixed_width(text: str, *fields: int) -> List[Tuple[str, ...]]: + len = sum(fields) + fmtstring = " ".join(f"{fw}s" for fw in fields) + unpack = struct.Struct(fmtstring).unpack_from + + def parse(line: str) -> Tuple[str, ...]: + return tuple([str(s.decode()) for s in unpack(line.ljust(len).encode())]) + + return [parse(s) for s in text.splitlines()] diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index b38ae4e7d..d5554f434 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -23,15 +23,12 @@ import time import importlib import inspect +import ipaddress import json import socket from datetime import datetime from collections import defaultdict -from netaddr import IPAddress -from netaddr import IPNetwork - -from netaddr.core import AddrFormatError # third party libs import pyeapi @@ -40,6 +37,7 @@ # NAPALM base import napalm.base.helpers +from napalm.base.netmiko_helpers import netmiko_args from napalm.base.base import NetworkDriver from napalm.base.utils import string_parsers from napalm.base.exceptions import ( @@ -98,9 +96,12 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) Optional args: * lock_disable (True/False): force configuration lock to be disabled (for external lock management). + * force_cfg_session_invalid (True/False): force invalidation of the config session + in case of failure. * enable_password (True/False): Enable password for privilege elevation * eos_autoComplete (True/False): Allow for shortening of cli commands - * transport (string): pyeapi transport, defaults to eos_transport if set + * transport (string): transport, eos_transport is a fallback for compatibility. + - ssh (uses Netmiko) - socket - http_local - http @@ -126,45 +127,47 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.platform = "eos" self.profile = [self.platform] + self.optional_args = optional_args or {} - self._process_optional_args(optional_args or {}) + self.enablepwd = self.optional_args.pop("enable_password", "") + self.eos_autoComplete = self.optional_args.pop("eos_autoComplete", None) + self.fn0039_config = self.optional_args.pop("eos_fn0039_config", False) - def _process_optional_args(self, optional_args): # Define locking method - self.lock_disable = optional_args.get("lock_disable", False) + self.lock_disable = self.optional_args.pop("lock_disable", False) + + self.force_cfg_session_invalid = self.optional_args.pop( + "force_cfg_session_invalid", False + ) - self.enablepwd = optional_args.pop("enable_password", "") - self.eos_autoComplete = optional_args.pop("eos_autoComplete", None) # eos_transport is there for backwards compatibility, transport is the preferred method - transport = optional_args.get( - "transport", optional_args.get("eos_transport", "https") + transport = self.optional_args.get( + "transport", self.optional_args.get("eos_transport", "https") ) - self.fn0039_config = optional_args.pop("eos_fn0039_config", False) self.transport = transport - if transport == "ssh": - self.transport_class = "ssh" - init_args = ["port"] - else: - # Parse pyeapi transport class - self.transport_class = self._parse_transport(transport) - # ([1:]) to omit self - init_args = inspect.getfullargspec(self.transport_class.__init__)[0][1:] - - filter_args = ["host", "username", "password", "timeout", "lock_disable"] if transport == "ssh": - self.netmiko_optional_args = { - k: v - for k, v in optional_args.items() - if k in init_args and k not in filter_args - } + self._process_optional_args_ssh(self.optional_args) else: - init_args.append("enforce_verification") # Not an arg for unknown reason - self.eapi_kwargs = { - k: v - for k, v in optional_args.items() - if k in init_args and k not in filter_args - } + self._process_optional_args_eapi(self.optional_args) + + def _process_optional_args_ssh(self, optional_args): + self.transport_class = None + self.netmiko_optional_args = netmiko_args(optional_args) + + def _process_optional_args_eapi(self, optional_args): + # Parse pyeapi transport class + self.transport_class = self._parse_transport(self.transport) + + # ([1:]) to omit self + init_args = inspect.getfullargspec(self.transport_class.__init__)[0][1:] + filter_args = ["host", "username", "password", "timeout"] + init_args.append("enforce_verification") # Not an arg for unknown reason + self.eapi_kwargs = { + k: v + for k, v in optional_args.items() + if k in init_args and k not in filter_args + } def _parse_transport(self, transport): if inspect.isclass(transport) and issubclass(transport, EapiConnection): @@ -195,7 +198,8 @@ def open(self): """Implementation of NAPALM method open.""" if self.transport == "ssh": self.device = self._netmiko_open( - "arista_eos", netmiko_optional_args=self.netmiko_optional_args + device_type="arista_eos", + netmiko_optional_args=self.netmiko_optional_args, ) # let's try to determine if we need to use new EOS cli syntax sh_ver = self._run_commands(["show version"]) @@ -208,7 +212,7 @@ def open(self): username=self.username, password=self.password, timeout=self.timeout, - **self.eapi_kwargs + **self.eapi_kwargs, ) if self.device is None: @@ -231,7 +235,9 @@ def open(self): def close(self): """Implementation of NAPALM method close.""" self.discard_config() - if hasattr(self.device.connection, "close") and callable( + if self.transport == "ssh": + self._netmiko_close() + elif hasattr(self.device.connection, "close") and callable( self.device.connection.close ): self.device.connection.close() @@ -282,6 +288,27 @@ def _run_commands(self, commands, **kwargs): else: return self.device.run_commands(commands, **kwargs) + def _obtain_lock(self, wait_time=None): + """ + EOS internally creates config sessions when using commit-confirm. + + This can cause issues obtaining the configuration lock: + + cfg-2034--574620864-0 completed + cfg-2034--574620864-1 pending + """ + if wait_time: + start_time = time.time() + while time.time() - start_time < wait_time: + try: + self._lock() + return + except SessionLockedException: + time.sleep(1) + + # One last try + return self._lock() + def _lock(self): sess = self._run_commands(["show configuration sessions"])[0]["sessions"] if [ @@ -385,7 +412,7 @@ def _load_config(self, filename=None, config=None, replace=True): self.config_session = "napalm_{}".format(datetime.now().microsecond) if not self.lock_disable: - self._lock() + self._obtain_lock(wait_time=10) commands = [] commands.append("configure session {}".format(self.config_session)) @@ -430,7 +457,7 @@ def _load_config(self, filename=None, config=None, replace=True): return None try: - if not any(l == "end" for l in commands): + if not any(cmd == "end" for cmd in commands): commands.append("end") # exit config mode if self.eos_autoComplete is not None: self._run_commands( @@ -521,13 +548,15 @@ def confirm_commit(self): def discard_config(self): """Implementation of NAPALM method discard_config.""" if self.config_session is not None: - commands = ["configure session {}".format(self.config_session), "abort"] - if self.transport == "ssh": - # For some reason when testing with vEOS 4.26.1F this - # doesn't work with the normal wrapper. - self._run_commands(["", commands[0]]) - else: - self.device.run_commands(commands) + try: + commands = [f"configure session {self.config_session} abort"] + self._run_commands(commands, encoding="text") + except Exception: + # If discard fails, you might want to invalidate the config_session (esp. Salt) + # The config_session in EOS is used as the config lock. + if self.force_cfg_session_invalid: + self.config_session = None + raise self.config_session = None def rollback(self): @@ -656,13 +685,13 @@ def get_interfaces_counters(self): def get_bgp_neighbors(self): def get_re_group(res, key, default=None): - """Small helper to retrive data from re match groups""" + """Small helper to retrieve data from re match groups""" try: return res.group(key) except KeyError: return default - NEIGHBOR_FILTER = "bgp neighbors vrf all | include remote AS | remote router ID |IPv[46] (Unicast|6PE):.*[0-9]+|^Local AS|Desc|BGP state" # noqa + NEIGHBOR_FILTER = "bgp neighbors vrf all | include IPv[46] (Unicast|6PE):.*[0-9]+ | grep -v ' IPv[46] Unicast:/.' | remote AS |^Local AS|Desc|BGP state |remote router ID" # noqa output_summary_cmds = self._run_commands( ["show ipv6 bgp summary vrf all", "show ip bgp summary vrf all"], encoding="json", @@ -977,6 +1006,7 @@ def get_bgp_config(self, group="", neighbor=""): "local-v4-addr": "local_address", "local-v6-addr": "local_address", "local-as": "local_as", + "next-hop-self": "nhs", "description": "description", "import-policy": "import_policy", "export-policy": "export_policy", @@ -1034,7 +1064,7 @@ def default_group_dict(local_as): ) # few more default values return group_dict - def default_neighbor_dict(local_as): + def default_neighbor_dict(local_as, group_dict): neighbor_dict = {} neighbor_dict.update( { @@ -1045,6 +1075,13 @@ def default_neighbor_dict(local_as): neighbor_dict.update( {"prefix_limit": {}, "local_as": local_as, "authentication_key": ""} ) # few more default values + neighbor_dict.update( + { + key: group_dict.get(key) + for key in _GROUP_FIELD_MAP_.values() + if key in group_dict and key in _PEER_FIELD_MAP_.values() + } + ) # copy in values from group dict if present return neighbor_dict def parse_options(options, default_value=False): @@ -1132,17 +1169,23 @@ def parse_options(options, default_value=False): # will try to parse the neighbor name # which sometimes is the IP Address of the neigbor # or the name of the BGP group - IPAddress(group_or_neighbor) + ipaddress.ip_address(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) + group_name = None if options[0] == "peer-group": - bgp_neighbors[peer_address]["__group"] = options[1] + group_name = options[1] # EOS > 4.23.0 only supports the new syntax # https://www.arista.com/en/support/advisories-notices/fieldnotices/7097-field-notice-39 elif options[0] == "peer" and options[1] == "group": - bgp_neighbors[peer_address]["__group"] = options[2] + group_name = options[2] + if peer_address not in bgp_neighbors: + bgp_neighbors[peer_address] = default_neighbor_dict( + local_as, bgp_config.get(group_name, {}) + ) + + if group_name: + bgp_neighbors[peer_address]["__group"] = group_name # in the config, neighbor details are lister after # the group is specified for the neighbor: @@ -1160,7 +1203,7 @@ def parse_options(options, default_value=False): bgp_neighbors[peer_address].update( parse_options(options, default_value) ) - except AddrFormatError: + except ValueError: # exception trying to parse group name # group_or_neighbor represents the name of the group group_name = group_or_neighbor @@ -1170,6 +1213,8 @@ def parse_options(options, default_value=False): bgp_config[group_name] = default_group_dict(local_as) bgp_config[group_name].update(parse_options(options, default_value)) + bgp_config["_"] = default_group_dict(local_as) + for peer, peer_details in bgp_neighbors.items(): peer_group = peer_details.pop("__group", None) if not peer_group: @@ -1178,6 +1223,14 @@ def parse_options(options, default_value=False): bgp_config[peer_group] = default_group_dict(local_as) bgp_config[peer_group]["neighbors"][peer] = peer_details + [ + v.pop("nhs", None) for v in bgp_config.values() + ] # remove NHS from group-level dictionary + + if local_as == 0: + # BGP not running + return {} + return bgp_config def get_arp_table(self, vrf=""): @@ -1423,7 +1476,7 @@ def get_route_to(self, destination="", protocol="", longer=False): protocol = "connected" ipv = "" - if IPNetwork(destination).version == 6: + if ipaddress.ip_network(destination).version == 6: ipv = "v6" commands = [] @@ -1530,7 +1583,7 @@ def get_route_to(self, destination="", protocol="", longer=False): .get("peerEntry", {}) .get("peerAddr", "") ) - except AddrFormatError: + except ValueError: remote_address = napalm.base.helpers.ip( bgp_route_details.get("peerEntry", {}).get( "peerAddr", "" @@ -1909,7 +1962,7 @@ def _append(bgp_dict, peer_info): summary_commands.append("show ipv6 bgp summary vrf all") else: try: - peer_ver = IPAddress(neighbor_address).version + peer_ver = ipaddress.ip_address(neighbor_address).version except Exception as e: raise e @@ -2077,15 +2130,59 @@ def get_config(self, retrieve="all", full=False, sanitized=False): else: raise Exception("Wrong retrieve filter: {}".format(retrieve)) - def _show_vrf(self): + def _show_vrf_json(self): + commands = ["show vrf"] + + vrfs = self._run_commands(commands)[0]["vrfs"] + return [ + { + "name": k, + "interfaces": [i for i in v["interfaces"]], + "route_distinguisher": v["routeDistinguisher"], + } + for k, v in vrfs.items() + ] + + def _show_vrf_text(self): commands = ["show vrf"] - # This command has no JSON yet + # This command has no JSON in EOS < 4.23 raw_output = self._run_commands(commands, encoding="text")[0].get("output", "") - output = napalm.base.helpers.textfsm_extractor(self, "vrf", raw_output) + width_line = raw_output.splitlines()[2] # Line with dashes + fields = width_line.split(" ") + widths = [len(f) + 1 for f in fields] + widths[-1] -= 1 + + parsed_lines = string_parsers.parse_fixed_width(raw_output, *widths) + + vrfs = [] + vrf = {} + current_vrf = None + for line in parsed_lines[3:]: + line = [t.strip() for t in line] + if line[0]: + if current_vrf: + vrfs.append(vrf) + current_vrf = line[0] + vrf = { + "name": current_vrf, + "interfaces": list(), + } + if line[1]: + vrf["route_distinguisher"] = line[1] + if line[4]: + vrf["interfaces"].extend([t.strip() for t in line[4].split(",") if t]) + if current_vrf: + vrfs.append(vrf) + + return vrfs - return output + def _show_vrf(self): + if self.cli_version == 2: + return self._show_vrf_json() + else: + return self._show_vrf_text() def _get_vrfs(self): output = self._show_vrf() @@ -2118,23 +2215,26 @@ def get_network_instances(self, name=""): interfaces[str(line.strip())] = {} all_vrf_interfaces[str(line.strip())] = {} - vrfs[str(vrf["name"])] = { - "name": str(vrf["name"]), - "type": "L3VRF", + vrfs[vrf["name"]] = { + "name": vrf["name"], + "type": "DEFAULT_INSTANCE" if vrf["name"] == "default" else "L3VRF", "state": {"route_distinguisher": vrf["route_distinguisher"]}, "interfaces": {"interface": interfaces}, } - all_interfaces = self.get_interfaces_ip().keys() - vrfs["default"] = { - "name": "default", - "type": "DEFAULT_INSTANCE", - "state": {"route_distinguisher": ""}, - "interfaces": { - "interface": { - k: {} for k in all_interfaces if k not in all_vrf_interfaces.keys() - } - }, - } + if "default" not in vrfs: + all_interfaces = self.get_interfaces_ip().keys() + vrfs["default"] = { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": {"route_distinguisher": ""}, + "interfaces": { + "interface": { + k: {} + for k in all_interfaces + if k not in all_vrf_interfaces.keys() + } + }, + } if name: if name in vrfs: diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 59284a362..5e31c49f8 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -14,6 +14,7 @@ # the License. import copy import functools +import ipaddress import os import re import socket @@ -22,8 +23,6 @@ import uuid from collections import defaultdict -from netaddr import IPNetwork -from netaddr.core import AddrFormatError from netmiko import FileTransfer, InLineTransfer import napalm.base.constants as C @@ -37,14 +36,17 @@ CommitConfirmException, ) from napalm.base.helpers import ( - canonical_interface_name, transform_lldp_capab, textfsm_extractor, - split_interface, - abbreviated_interface_name, generate_regex_or, sanitize_configs, ) +from netaddr.core import AddrFormatError +from netutils.interface import ( + abbreviated_interface_name, + canonical_interface_name, + split_interface, +) from napalm.base.netmiko_helpers import netmiko_args # Easier to store these as constants @@ -481,10 +483,10 @@ def _commit_handler(self, cmd): # Handle special username removal pattern pattern2 = r".*all username.*confirm" patterns = rf"(?:{pattern1}|{pattern2})" - output = self.device.send_command(cmd, expect_string=patterns) + output = self.device.send_command(cmd, expect_string=patterns, read_timeout=90) loop_count = 50 new_output = output - for i in range(loop_count): + for _ in range(loop_count): if re.search(pattern2, new_output): # Send confirmation if username removal new_output = self.device.send_command_timing( @@ -985,10 +987,26 @@ def get_lldp_neighbors(self): hostname = lldp_entry["remote_system_name"] port = lldp_entry["remote_port"] # Match IOS behaviour of taking remote chassis ID - # When lacking a system name (in show lldp neighbors) + # when lacking a system name (in show lldp neighbors) + + # We can't assume remote_chassis_id or remote_port are MAC Addresses + # See IEEE 802.1AB-2005 and rfc2922, specifically PtopoChassisId if not hostname: - hostname = napalm.base.helpers.mac(lldp_entry["remote_chassis_id"]) - port = napalm.base.helpers.mac(port) + try: + hostname = napalm.base.helpers.mac( + lldp_entry["remote_chassis_id"] + ) + except AddrFormatError: + hostname = lldp_entry["remote_chassis_id"] + + # If port is a mac-address, normalize it. + # The MAC helper library will normalize "15" to "00:00:00:00:00:0F" + if port.count(":") == 5 or port.count("-") == 5 or port.count(".") == 2: + try: + port = napalm.base.helpers.mac(port) + except AddrFormatError: + pass + lldp_dict = {"port": port, "hostname": hostname} lldp[intf_name].append(lldp_dict) @@ -1445,6 +1463,11 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): bgp_config_list = napalm.base.helpers.netutils_parse_objects( "router bgp", cfg["running"] ) + + # No BGP configuration + if not bgp_config_list: + return {} + bgp_asn = napalm.base.helpers.regex_find_txt( r"router bgp (\d+)", bgp_config_list, default=0 ) @@ -1515,7 +1538,9 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): r" update-source (\w+)", neighbor_config ) local_as = napalm.base.helpers.regex_find_txt( - r"local-as (\d+)", neighbor_config, default=0 + r"local-as (\d+)", + neighbor_config, + default=bgp_asn, ) password = napalm.base.helpers.regex_find_txt( r"password (?:[0-9] )?([^\']+\')", neighbor_config @@ -1549,29 +1574,32 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): "route_reflector_client": route_reflector_client, } + # Do not include the no-group ("_") if a group argument is passed in + # unless group argument is "_" + if not group or group == "_": + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("_", {}), + } + # Get the peer-group level config for each group for group_name in bgp_group_neighbors.keys(): # If a group is passed in params, only continue on that group if group: if group_name != group: continue - # Default no group if group_name == "_": - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": 0, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("_", {}), - } continue neighbor_config = napalm.base.helpers.netutils_parse_objects( group_name, bgp_config_list @@ -1593,7 +1621,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): r" description ([^\']+)\'", neighbor_config ) local_as = napalm.base.helpers.regex_find_txt( - r"local-as (\d+)", neighbor_config, default=0 + r"local-as (\d+)", neighbor_config, default=bgp_asn ) import_policy = napalm.base.helpers.regex_find_txt( r"route-map ([^\s]+) in", neighbor_config @@ -3005,7 +3033,7 @@ def _get_bgp_route_attr(self, destination, vrf, next_hop, ip_version=4): # next-hop is not known in this vrf, route leaked from # other vrf or from vpnv4 table? # get remote AS nr. from as-path if it is ebgp neighbor - # localy sourced prefix is not in routing table as a bgp route (i hope...) + # locally sourced prefix is not in routing table as a bgp route (i hope...) if search_re_dict["bgpie"]["result"] == "external": bgpras = ( search_re_dict["aspath"]["result"] @@ -3074,8 +3102,8 @@ def get_route_to(self, destination="", protocol="", longer=False): vrf = "" ip_version = None try: - ip_version = IPNetwork(destination).version - except AddrFormatError: + ip_version = ipaddress.ip_network(destination).version + except ValueError: return "Please specify a valid destination!" if ip_version == 4: # process IPv4 routing table if vrf == "": @@ -3083,8 +3111,8 @@ def get_route_to(self, destination="", protocol="", longer=False): else: vrfs = [vrf] # VRFs where IPv4 is enabled vrfs.append("default") # global VRF - ipnet_dest = IPNetwork(destination) - prefix = str(ipnet_dest.network) + ipnet_dest = ipaddress.ip_network(destination) + prefix = str(ipnet_dest.network_address) netmask = "" routes = {} if "/" in destination: diff --git a/napalm/iosxr/iosxr.py b/napalm/iosxr/iosxr.py index e8e4e5921..383e8ae00 100644 --- a/napalm/iosxr/iosxr.py +++ b/napalm/iosxr/iosxr.py @@ -16,15 +16,13 @@ # import stdlib import re import copy +import ipaddress from collections import defaultdict import logging # import third party lib from lxml import etree as ETREE -from netaddr import IPAddress # needed for traceroute, to check IP version -from netaddr.core import AddrFormatError - from napalm.pyIOSXR import IOSXR from napalm.pyIOSXR.exceptions import ConnectError from napalm.pyIOSXR.exceptions import TimeoutError @@ -989,6 +987,22 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): default" result_tree = ETREE.fromstring(self.device.make_rpc_call(rpc_command)) + # Check if BGP is not configured. + get_tag = result_tree.find("./Get") + if get_tag is not None: + bgp_not_found = get_tag.attrib.get("ItemNotFound") + if bgp_not_found: + return {} + + bgp_asn = napalm.base.helpers.convert( + int, + napalm.base.helpers.find_txt( + result_tree, + "Get/Configuration/BGP/Instance[1]/InstanceAS/FourByteAS/Naming/AS", + ), + 0, + ) + if not group: neighbor = "" @@ -1012,7 +1026,9 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): int, napalm.base.helpers.find_txt(bgp_neighbor, "RemoteAS/AS_YY"), 0 ) local_as = napalm.base.helpers.convert( - int, napalm.base.helpers.find_txt(bgp_neighbor, "LocalAS/AS_YY"), 0 + int, + napalm.base.helpers.find_txt(bgp_neighbor, "LocalAS/AS_YY"), + bgp_asn, ) af_table = napalm.base.helpers.find_txt( bgp_neighbor, "NeighborAFTable/NeighborAF/Naming/AFName" @@ -1104,7 +1120,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): int, napalm.base.helpers.find_txt(bgp_group, "RemoteAS/AS_YY"), 0 ) local_as = napalm.base.helpers.convert( - int, napalm.base.helpers.find_txt(bgp_group, "LocalAS/AS_YY"), 0 + int, napalm.base.helpers.find_txt(bgp_group, "LocalAS/AS_YY"), bgp_asn ) multihop_ttl = napalm.base.helpers.convert( int, @@ -1166,22 +1182,22 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): } if group and group == group_name: break - if "" in bgp_group_neighbors.keys(): - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": 0, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("", {}), - } + + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("", {}), + } return bgp_config @@ -1733,8 +1749,8 @@ def get_route_to(self, destination="", protocol="", longer=False): ipv = 4 try: - ipv = IPAddress(network).version - except AddrFormatError: + ipv = ipaddress.ip_address(network).version + except ValueError: logger.error("Wrong destination IP Address format supplied to get_route_to") raise TypeError("Wrong destination IP Address!") @@ -2187,8 +2203,8 @@ def traceroute( ipv = 4 try: - ipv = IPAddress(destination).version - except AddrFormatError: + ipv = ipaddress.ip_address(destination).version + except ValueError: logger.error( "Incorrect format of IP Address in traceroute \ with value provided:%s" diff --git a/napalm/iosxr_netconf/iosxr_netconf.py b/napalm/iosxr_netconf/iosxr_netconf.py index 656078880..ff7a06ef8 100644 --- a/napalm/iosxr_netconf/iosxr_netconf.py +++ b/napalm/iosxr_netconf/iosxr_netconf.py @@ -22,6 +22,7 @@ import re import copy import difflib +import ipaddress import logging # import third party lib @@ -31,8 +32,6 @@ from ncclient.operations.errors import TimeoutExpiredError from lxml import etree as ETREE from lxml.etree import XMLSyntaxError -from netaddr import IPAddress # needed for traceroute, to check IP version -from netaddr.core import AddrFormatError # import NAPALM base from napalm.iosxr_netconf import constants as C @@ -1367,9 +1366,25 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): # Converts string to etree result_tree = ETREE.fromstring(rpc_reply) + data_ele = result_tree.find("./{*}data") + # If there are no children in "", then there is no BGP configured + bgp_configured = bool(len(data_ele.getchildren())) + if not bgp_configured: + return {} + if not group: neighbor = "" + bgp_asn = napalm.base.helpers.convert( + int, + self._find_txt( + result_tree, + ".//bgpc:bgp/bgpc:instance/bgpc:instance-as/bgpc:four-byte-as/bgpc:as", + default=0, + namespaces=C.NS, + ), + ) + bgp_group_neighbors = {} bgp_neighbor_xpath = ".//bgpc:bgp/bgpc:instance/bgpc:instance-as/\ bgpc:four-byte-as/bgpc:default-vrf/bgpc:bgp-entity/bgpc:neighbors/bgpc:neighbor" @@ -1431,7 +1446,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): ), 0, ) - local_as = local_as_x * 65536 + local_as_y + local_as = (local_as_x * 65536 + local_as_y) or bgp_asn af_table = self._find_txt( bgp_neighbor, "./bgpc:neighbor-afs/bgpc:neighbor-af/bgpc:af-name", @@ -1598,7 +1613,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): ), 0, ) - local_as = local_as_x * 65536 + local_as_y + local_as = (local_as_x * 65536 + local_as_y) or bgp_asn multihop_ttl = napalm.base.helpers.convert( int, self._find_txt( @@ -1680,22 +1695,22 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): } if group and group == group_name: break - if "" in bgp_group_neighbors.keys(): - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": 0, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("", {}), - } + + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("", {}), + } return bgp_config @@ -2481,8 +2496,8 @@ def get_route_to(self, destination="", protocol="", longer=False): ipv = 4 try: - ipv = IPAddress(network).version - except AddrFormatError: + ipv = ipaddress.ip_address(network).version + except ValueError: logger.error("Wrong destination IP Address format supplied to get_route_to") raise TypeError("Wrong destination IP Address!") @@ -2952,8 +2967,8 @@ def traceroute( ipv = 4 try: - ipv = IPAddress(destination).version - except AddrFormatError: + ipv = ipaddress.ip_address(destination).version + except ValueError: logger.error( "Incorrect format of IP Address in traceroute \ with value provided:%s" @@ -3139,7 +3154,7 @@ def get_config(self, retrieve="all", full=False, sanitized=False): if config[datastore] != "": if encoding == "cli": cli_tree = ETREE.XML(config[datastore], parser=parser)[0] - if cli_tree: + if len(cli_tree): config[datastore] = cli_tree[0].text.strip() else: config[datastore] = "" diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index d274dac91..74b6e5efe 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -176,10 +176,10 @@ def _unlock(self): def _rpc(self, get, child=None, **kwargs): """ - This allows you to construct an arbitrary RPC call to retreive common stuff. For example: + This allows you to construct an arbitrary RPC call to retrieve common stuff. For example: Configuration: get: "" Interface information: get: "" - A particular interfacece information: + A particular interface information: get: "" child: "ge-0/0/0" """ @@ -1169,7 +1169,7 @@ def update_dict(d, u): # for deep dictionary update def build_prefix_limit(**args): """ - Transform the lements of a dictionary into nested dictionaries. + Transform the elements of a dictionary into nested dictionaries. Example: { @@ -1250,13 +1250,40 @@ def build_prefix_limit(**args): bgp_config = {} - if group: + routing_options = junos_views.junos_routing_config_table(self.device) + routing_options.get(options=self.junos_config_options) + + bgp_asn_obj = routing_options.xml.find( + "./routing-options/autonomous-system/as-number" + ) + system_bgp_asn = int(bgp_asn_obj.text) if bgp_asn_obj is not None else 0 + + # No BGP peer-group i.e. "_" key is a special case. + if group and group != "_": bgp = junos_views.junos_bgp_config_group_table(self.device) bgp.get(group=group, options=self.junos_config_options) else: bgp = junos_views.junos_bgp_config_table(self.device) bgp.get(options=self.junos_config_options) neighbor = "" # if no group is set, no neighbor should be set either + + # Only set no peer-group if BGP is actually configured. + if bgp.items() or system_bgp_asn: + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": system_bgp_asn, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": {}, + } bgp_items = bgp.items() if neighbor: @@ -1283,13 +1310,17 @@ def build_prefix_limit(**args): for field, datatype in _GROUP_FIELDS_DATATYPE_MAP_.items() if "_prefix_limit" not in field } - for elem in bgp_group_details: - if not ("_prefix_limit" not in elem[0] and elem[1] is not None): + + # Always overwrite with the system local_as (this will either be + # valid or will be zero i.e. the same as the default value). + bgp_config[bgp_group_name]["local_as"] = system_bgp_asn + + for key, value in bgp_group_details: + if "_prefix_limit" in key or value is None: continue - datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0]) + datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) - key = elem[0] - value = elem[1] + if key in ["export_policy", "import_policy"]: if isinstance(value, list): value = " ".join(value) @@ -1297,6 +1328,10 @@ def build_prefix_limit(**args): value = napalm.base.helpers.convert( napalm.base.helpers.ip, value, value ) + if key == "apply_groups": + # Ensure apply_groups value is wrapped in a list + if isinstance(value, str): + value = [value] if key == "neighbors": bgp_group_peers = value continue @@ -1304,15 +1339,15 @@ def build_prefix_limit(**args): {key: napalm.base.helpers.convert(datatype, value, default)} ) prefix_limit_fields = {} - for elem in bgp_group_details: - if "_prefix_limit" in elem[0] and elem[1] is not None: - datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0]) + for key, value in bgp_group_details: + if "_prefix_limit" in key and value is not None: + datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) prefix_limit_fields.update( { - elem[0].replace( + key.replace( "_prefix_limit", "" - ): napalm.base.helpers.convert(datatype, elem[1], default) + ): napalm.base.helpers.convert(datatype, value, default) } ) bgp_config[bgp_group_name]["prefix_limit"] = build_prefix_limit( @@ -1326,23 +1361,31 @@ def build_prefix_limit(**args): bgp_config[bgp_group_name]["multihop_ttl"] = 64 bgp_config[bgp_group_name]["neighbors"] = {} + bgp_group_remote_as = bgp_config[bgp_group_name]["remote_as"] for bgp_group_neighbor in bgp_group_peers.items(): bgp_peer_address = napalm.base.helpers.ip(bgp_group_neighbor[0]) if neighbor and bgp_peer_address != neighbor: continue # if filters applied, jump over all other neighbors bgp_group_details = bgp_group_neighbor[1] + + # Set defaults for this BGP peer bgp_peer_details = { field: _DATATYPE_DEFAULT_.get(datatype) for field, datatype in _PEER_FIELDS_DATATYPE_MAP_.items() if "_prefix_limit" not in field } - for elem in bgp_group_details: - if not ("_prefix_limit" not in elem[0] and elem[1] is not None): + + # Always overwrite with the system local_as (this will either be + # valid or will be zero i.e. the same as the default value). + bgp_peer_details["local_as"] = system_bgp_asn + # Always set the default remote-as as the Peer-Group remote-as + bgp_peer_details["remote_as"] = bgp_group_remote_as + + for key, value in bgp_group_details: + if "_prefix_limit" in key or value is None: continue - datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0]) + datatype = _PEER_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) - key = elem[0] - value = elem[1] if key in ["export_policy"]: # next-hop self is applied on export IBGP sessions bgp_peer_details["nhs"] = _check_nhs(value, nhs_policies) @@ -1370,17 +1413,15 @@ def build_prefix_limit(**args): if "cluster" in bgp_config[bgp_group_name].keys(): bgp_peer_details["route_reflector_client"] = True prefix_limit_fields = {} - for elem in bgp_group_details: - if "_prefix_limit" in elem[0] and elem[1] is not None: - datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0]) + for key, value in bgp_group_details: + if "_prefix_limit" in key and value is not None: + datatype = _PEER_FIELDS_DATATYPE_MAP_.get(key) default = _DATATYPE_DEFAULT_.get(datatype) prefix_limit_fields.update( { - elem[0].replace( + key.replace( "_prefix_limit", "" - ): napalm.base.helpers.convert( - datatype, elem[1], default - ) + ): napalm.base.helpers.convert(datatype, value, default) } ) bgp_peer_details["prefix_limit"] = build_prefix_limit( @@ -1824,7 +1865,7 @@ def get_route_to(self, destination="", protocol="", longer=False): try: routes_table.get(**rt_kargs) except RpcTimeoutError: - # on devices with milions of routes + # on devices with millions of routes # in case the destination is too generic (e.g.: 10/8) # will take very very long to determine all routes and # moreover will return a huge list diff --git a/napalm/junos/utils/junos_views.yml b/napalm/junos/utils/junos_views.yml index 5d81ae2fc..3fd60b1f4 100644 --- a/napalm/junos/utils/junos_views.yml +++ b/napalm/junos/utils/junos_views.yml @@ -402,6 +402,15 @@ junos_bgp_config_peers_view: inet6_flow_teardown_timeout_prefix_limit: {family/inet6/flow/prefix-limit/teardown/idle-timeout/timeout: int} inet6_flow_novalidate_prefix_limit: {family/inet6/flow/prefix-limit/no-validate: unicode} +junos_routing_config_table: + get: "routing-options/autonomous-system" + view: junos_routing_config_view + +junos_routing_config_view: + fields: + local_system_as: autonomous-system + + #### #### BGP Neighbors and Routing Tables Stats #### diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index d857832e4..9668569ff 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations under # the License. +import ipaddress import json import os import re @@ -42,11 +43,10 @@ DefaultDict, ) -from netaddr import IPAddress -from netaddr.core import AddrFormatError from netmiko import file_transfer from requests.exceptions import ConnectionError from netutils.config.compliance import diff_network_config +from netutils.interface import canonical_interface_name import napalm.base.constants as c @@ -233,7 +233,7 @@ def _get_merge_diff(self) -> str: interface loopback0 ip address 10.1.4.5/32 """ - running_config = self.get_config(retrieve="running")["running"] + running_config = self.get_config(retrieve="running", full=True)["running"] return diff_network_config(self.merge_candidate, running_config, "cisco_nxos") def _get_diff(self) -> str: @@ -356,8 +356,8 @@ def ping( version = "" try: - version = "6" if IPAddress(destination).version == 6 else "" - except AddrFormatError: + version = "6" if ipaddress.ip_address(destination).version == 6 else "" + except ValueError: # Allow use of DNS names pass @@ -470,8 +470,8 @@ def traceroute( version = "" try: - version = "6" if IPAddress(destination).version == 6 else "" - except AddrFormatError: + version = "6" if ipaddress.ip_address(destination).version == 6 else "" + except ValueError: # Allow use of DNS names pass @@ -683,7 +683,7 @@ def get_lldp_neighbors_detail( lldp_entry["remote_system_enable_capab"] ) # Turn the interfaces into their long version - local_intf = napalm.base.helpers.canonical_interface_name(local_intf) + local_intf = canonical_interface_name(local_intf) lldp.setdefault(local_intf, []) lldp[local_intf].append(lldp_entry) # type: ignore @@ -739,13 +739,9 @@ def _parse_vlan_ports(self, vlan_s: Union[str, List]) -> List: find = re.findall(find_regexp, vls.strip()) if find: for i in range(int(find[0][1]), int(find[0][2]) + 1): - vlans.append( - napalm.base.helpers.canonical_interface_name( - find[0][0] + str(i) - ) - ) + vlans.append(canonical_interface_name(find[0][0] + str(i))) else: - vlans.append(napalm.base.helpers.canonical_interface_name(vls.strip())) + vlans.append(canonical_interface_name(vls.strip())) return vlans @abstractmethod diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index 01147d0e6..bdb01f5a9 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -15,12 +15,13 @@ # import stdlib from builtins import super +import ipaddress import re import socket +from collections import defaultdict -# import third party lib -from netaddr import IPAddress, IPNetwork -from netaddr.core import AddrFormatError +# import external lib +from netutils.interface import canonical_interface_name # import NAPALM Base from napalm.base import helpers @@ -118,7 +119,7 @@ def parse_intf_section(interface): else: # More standard is up, next line admin state is lines match = re.search(re_intf_name_state, interface) - intf_name = helpers.canonical_interface_name(match.group("intf_name")) + intf_name = canonical_interface_name(match.group("intf_name")) intf_state = match.group("intf_state").strip() is_up = True if intf_state == "up" else False @@ -456,21 +457,15 @@ def _send_command(self, command, raw_text=False, cmd_verify=True): """ return self.device.send_command(command, cmd_verify=cmd_verify) - def _send_command_list(self, commands, expect_string=None): - """Wrapper for Netmiko's send_command method (for list of commands.""" - output = "" - for command in commands: - output += self.device.send_command( - command, - strip_prompt=False, - strip_command=False, - expect_string=expect_string, - ) - return output + def _send_command_list(self, commands, expect_string=None, **kwargs): + """Send a list of commands using Netmiko""" + return self.device.send_multiline( + commands, expect_string=expect_string, **kwargs + ) def _send_config(self, commands): if isinstance(commands, str): - commands = (command for command in commands.splitlines() if command) + commands = [command for command in commands.splitlines() if command] return self.device.send_config_set(commands) @staticmethod @@ -524,7 +519,6 @@ def is_alive(self): return {"is_alive": self.device.remote_conn.transport.is_active()} def _copy_run_start(self): - output = self.device.save_config() if "complete" in output.lower(): return True @@ -533,7 +527,6 @@ def _copy_run_start(self): raise CommandErrorException(msg) def _load_cfg_from_checkpoint(self): - commands = [ "terminal dont-ask", "rollback running-config file {}".format(self.candidate_cfg), @@ -541,7 +534,9 @@ def _load_cfg_from_checkpoint(self): ] try: - rollback_result = self._send_command_list(commands, expect_string=r"[#>]") + rollback_result = self._send_command_list( + commands, expect_string=r"[#>]", read_timeout=90 + ) finally: self.changed = True msg = rollback_result @@ -555,7 +550,9 @@ def rollback(self): "rollback running-config file {}".format(self.rollback_cfg), "no terminal dont-ask", ] - result = self._send_command_list(commands, expect_string=r"[#>]") + result = self._send_command_list( + commands, expect_string=r"[#>]", read_timeout=90 + ) if "completed" not in result.lower(): raise ReplaceConfigException(result) # If hostname changes ensure Netmiko state is updated properly @@ -659,7 +656,7 @@ def get_facts(self): continue interface = line.split()[0] # Return canonical interface name - interface_list.append(helpers.canonical_interface_name(interface)) + interface_list.append(canonical_interface_name(interface)) return { "uptime": float(uptime), @@ -799,6 +796,61 @@ def cli(self, commands, encoding="text"): cli_output[str(command)] = output return cli_output + def get_network_instances(self, name=""): + """ + get_network_instances implementation for NX-OS + """ + + # command 'show vrf detail | json' returns all VRFs with detailed information in JSON format + # format: list of dictionaries with keys such as 'vrf_name' and 'rd' + vrf_table_raw = self._get_command_table( + "show vrf detail | json", "TABLE_vrf", "ROW_vrf" + ) + + # command 'show vrf interface' returns all interfaces including their assigned VRF + # format: list of dictionaries with keys 'if_name', 'vrf_name', 'vrf_id' and 'soo' + intf_table_raw = self._get_command_table( + "show vrf interface | json", "TABLE_if", "ROW_if" + ) + + # create a dictionary with key = 'vrf_name' and value = list of interfaces + vrf_intfs = defaultdict(list) + for intf in intf_table_raw: + vrf_intfs[intf["vrf_name"]].append(str(intf["if_name"])) + + vrfs = {} + for vrf in vrf_table_raw: + vrf_name = str(vrf.get("vrf_name")) + vrfs[vrf_name] = {} + vrfs[vrf_name]["name"] = vrf_name + + # differentiate between VRF type 'DEFAULT_INSTANCE' and 'L3VRF' + if vrf_name == "default": + vrfs[vrf_name]["type"] = "DEFAULT_INSTANCE" + else: + vrfs[vrf_name]["type"] = "L3VRF" + + vrfs[vrf_name]["state"] = {"route_distinguisher": str(vrf.get("rd"))} + + # convert list of interfaces (vrf_intfs[vrf_name]) to expected format + # format = dict with key = interface name and empty values + vrfs[vrf_name]["interfaces"] = {} + vrfs[vrf_name]["interfaces"]["interface"] = dict.fromkeys( + vrf_intfs[vrf_name], {} + ) + + # if name of a specific VRF was passed as an argument + # only return results for this particular VRF + + if name: + if name in vrfs.keys(): + return {str(name): vrfs[name]} + else: + return {} + # else return results for all VRFs + else: + return vrfs + def get_environment(self): """ Get environment facts. @@ -953,7 +1005,7 @@ def _get_ntp_entity(self, peer_type): # Skip first two lines and last line of command output if line == "" or "-----" in line or "Peer IP Address" in line: continue - elif IPAddress(len(line.split()[0])).is_unicast: + elif not ipaddress.ip_address(len(line.split()[0])).is_multicast: peer_addr = line.split()[0] ntp_entities[peer_addr] = {} else: @@ -1139,7 +1191,7 @@ def process_mac_fields(vlan, mac, mac_type, interface): active = False return { "mac": helpers.mac(mac), - "interface": helpers.canonical_interface_name(interface), + "interface": canonical_interface_name(interface), "vlan": int(vlan), "static": static, "active": active, @@ -1158,7 +1210,6 @@ def process_mac_fields(vlan, mac, mac_type, interface): output = re.sub(r"vPC Peer-Link", "vPC-Peer-Link", output, flags=re.M) for line in output.splitlines(): - # Every 500 Mac's Legend is reprinted, regardless of terminal length if re.search(r"^Legend", line): continue @@ -1340,8 +1391,8 @@ def get_route_to(self, destination="", protocol="", longer=False): ip_version = None try: - ip_version = IPNetwork(destination).version - except AddrFormatError: + ip_version = ipaddress.ip_network(destination).version + except ValueError: return "Please specify a valid destination!" if ip_version == 4: # process IPv4 routing table routes = {} @@ -1409,7 +1460,7 @@ def get_route_to(self, destination="", protocol="", longer=False): # routing protocol process number, for future use # nh_source_proc_nr = viastr.group('procnr) if nh_int: - nh_int_canon = helpers.canonical_interface_name(nh_int) + nh_int_canon = canonical_interface_name(nh_int) else: nh_int_canon = "" route_entry = { diff --git a/napalm/pyIOSXR/iosxr.py b/napalm/pyIOSXR/iosxr.py index 694a73227..a1ddc2215 100644 --- a/napalm/pyIOSXR/iosxr.py +++ b/napalm/pyIOSXR/iosxr.py @@ -690,7 +690,7 @@ def commit_replace_config(self, label=None, comment=None, confirmed=None): def discard_config(self): """ - Clear uncommited changes in the current session. + Clear uncommitted changes in the current session. Clear previously loaded configuration on the device without committing it. """ diff --git a/requirements-dev.txt b/requirements-dev.txt index b1197ced2..62923790b 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,17 +1,17 @@ black==22.6.0 coveralls==3.3.1 -ddt==1.5.0 -flake8-import-order==0.18.1 -pytest==7.1.2 -pytest-cov==3.0.0 -pytest-json==0.4.0 -pylama==8.2.1 -mock==4.0.3 -tox==3.25.1 -mypy==0.961 -types-requests==2.28.0 -types-six==1.16.17 -types-setuptools==57.4.18 -types-PyYAML==6.0.9 -ttp==0.9.0 -ttp_templates==0.3.0 \ No newline at end of file +ddt==1.6.0 +flake8-import-order==0.18.2 +pytest==7.3.1 +pytest-cov==4.0.0 +pytest-json-report==1.5.0 +pyflakes==3.0.1 +pylama==8.4.1 +mock==5.0.2 +mypy==0.982 +types-PyYAML==6.0.12.10 +types-requests==2.28.11.17 +types-six==1.16.21.8 +types-setuptools==67.8.0.0 +ttp==0.9.4 +ttp_templates==0.3.5 diff --git a/requirements.txt b/requirements.txt index 18530cdd5..57ecd72eb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,12 +3,12 @@ cffi>=1.11.3 paramiko>=2.6.0 requests>=2.7.0 future -textfsm<=1.1.2 +textfsm jinja2 netaddr pyYAML pyeapi>=0.8.2 -netmiko>=4.0.0 +netmiko>=4.1.0 junos-eznc>=2.6.3 scp lxml>=4.3.0 diff --git a/setup.cfg b/setup.cfg index 272f56d7f..871c4c939 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,11 +5,11 @@ universal = 1 license_file = LICENSE [pylama] -linters = mccabe,pep8,pyflakes +linters = mccabe,pycodestyle,pyflakes ignore = D203,C901,E203 skip = .tox/*,.env/*,.venv/* -[pylama:pep8] +[pylama:pycodestyle] max_line_length = 100 [tool:pytest] diff --git a/setup.py b/setup.py index 9eb0865d0..0a3bbe374 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="napalm", - version="4.0.0", + version="4.1.0", packages=find_packages(exclude=("test*",)), test_suite="test_base", author="David Barroso, Kirk Byers, Mircea Ulinic", diff --git a/test/base/test_helpers.py b/test/base/test_helpers.py index f6ca9717b..cd2226877 100644 --- a/test/base/test_helpers.py +++ b/test/base/test_helpers.py @@ -57,7 +57,10 @@ from napalm.base.netmiko_helpers import netmiko_args import napalm.base.exceptions from napalm.base.base import NetworkDriver -from napalm.base.utils.string_parsers import convert_uptime_string_seconds +from napalm.base.utils.string_parsers import ( + convert_uptime_string_seconds, + parse_fixed_width, +) class TestBaseHelpers(unittest.TestCase): @@ -81,7 +84,7 @@ def test_load_template(self): custom path * check if can load correct template from custom path * check if template passed as string can be loaded - * check that the search path setup by MRO is correct when loading an incorrecet template + * check that the search path setup by MRO is correct when loading an incorrect template """ self.assertTrue(HAS_JINJA) # firstly check if jinja2 is installed @@ -375,10 +378,8 @@ def test_ip(self): * check if IPv6 address returned as expected """ - self.assertTrue(HAS_NETADDR) - - # test that raises AddrFormatError when wrong format - self.assertRaises(AddrFormatError, napalm.base.helpers.ip, "fake") + # test that raises ValueError when wrong format + self.assertRaises(ValueError, napalm.base.helpers.ip, "fake") self.assertRaises( ValueError, napalm.base.helpers.ip, @@ -495,87 +496,6 @@ def test_convert_uptime_string_seconds(self): self.assertEqual(convert_uptime_string_seconds("95w2d10h58m"), 57668280) self.assertEqual(convert_uptime_string_seconds("1h5m"), 3900) - def test_canonical_interface_name(self): - """Test the canonical_interface_name helper function.""" - self.assertEqual( - napalm.base.helpers.canonical_interface_name("Fa0/1"), "FastEthernet0/1" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("FastEthernet0/1"), - "FastEthernet0/1", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("TenGig1/1/1.5"), - "TenGigabitEthernet1/1/1.5", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("Gi1/2"), "GigabitEthernet1/2" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("HundredGigE105/1/1"), - "HundredGigabitEthernet105/1/1", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("Lo0"), "Loopback0" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("lo0"), "Loopback0" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name("no_match0/1"), "no_match0/1" - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name( - "lo10", addl_name_map={"lo": "something_custom"} - ), - "something_custom10", - ) - self.assertEqual( - napalm.base.helpers.canonical_interface_name( - "uniq0/1/1", addl_name_map={"uniq": "something_custom"} - ), - "something_custom0/1/1", - ) - - def test_abbreviated_interface_name(self): - """Test the abbreviated_interface_name helper function.""" - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("Fa0/1"), "Fa0/1" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("FastEthernet0/1"), "Fa0/1" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("TenGig1/1/1.5"), "Te1/1/1.5" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("Gi1/2"), "Gi1/2" - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("HundredGigE105/1/1"), - "Hu105/1/1", - ) - self.assertEqual(napalm.base.helpers.abbreviated_interface_name("Lo0"), "Lo0") - self.assertEqual(napalm.base.helpers.abbreviated_interface_name("lo0"), "Lo0") - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name("something_custom0/1"), - "something_custom0/1", - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name( - "loop10", addl_name_map={"loop": "Loopback"} - ), - "Lo10", - ) - self.assertEqual( - napalm.base.helpers.abbreviated_interface_name( - "loop10", - addl_name_map={"loop": "Loopback"}, - addl_reverse_map={"Loopback": "lo"}, - ), - "lo10", - ) - def test_netmiko_arguments(self): """Test the netmiko argument processing.""" self.assertEqual(netmiko_args(optional_args={}), {}) @@ -755,6 +675,37 @@ def test_ttp_parse(self): ) self.assertEqual(result, _EXPECTED_RESULT) + def test_parse_fixed_width(self): + _TEST_STRING = """ VRF RD Protocols State Interfaces +---------------- --------------- --------------- ------------------- --------------------------- +123456789012345671234567890123456123456789012345612345678901234567890123456789012345678901234567 +""" # noqa: E501 + _EXPECTED_RESULT = [ + ( + " VRF ", + " RD ", + " Protocols ", + " State ", + "Interfaces ", + ), + ( + "---------------- ", + "--------------- ", + "--------------- ", + "------------------- ", + "---------------------------", + ), + ( + "12345678901234567", + "1234567890123456", + "1234567890123456", + "12345678901234567890", + "123456789012345678901234567", + ), + ] + result = parse_fixed_width(_TEST_STRING, 17, 16, 16, 20, 27) + self.assertEqual(result, _EXPECTED_RESULT) + class FakeNetworkDriver(NetworkDriver): def __init__(self): diff --git a/test/eos/conftest.py b/test/eos/conftest.py index 7cf515f31..aff8e78a1 100644 --- a/test/eos/conftest.py +++ b/test/eos/conftest.py @@ -37,6 +37,19 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.patched_attrs = ["device"] self.device = FakeEOSDevice() + self._cli_version = 1 + + @property + def cli_version(self): + try: + full_path = self.device.find_file("cli_version.txt") + except IOError: + return self._cli_version + return int(self.device.read_txt_file(full_path)) + + @cli_version.setter + def cli_version(self, value): + self._cli_version = value class FakeEOSDevice(BaseTestDouble): diff --git a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json index 8354f24ba..1dbf0d43b 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json @@ -1,4 +1,19 @@ { + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 64496, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, "IPv6-PEERS-GROUP-NAME": { "type": "", "multipath": false, @@ -20,8 +35,8 @@ "local_as": 64496, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} }, @@ -32,8 +47,8 @@ "local_as": 64496, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} } diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json index 84f8c3bd8..1f885538c 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json @@ -1,4 +1,19 @@ { + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 4266524237, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, "IPv4-PEERS-GROUP-NAME": { "type": "", "multipath": false, @@ -20,8 +35,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "4-public-peer-anycast-out", "authentication_key": "", "prefix_limit": {} }, @@ -32,8 +47,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "4-public-peer-anycast-out", "authentication_key": "", "prefix_limit": {} } @@ -60,8 +75,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} }, @@ -72,8 +87,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "", - "export_policy": "", + "import_policy": "reject-all", + "export_policy": "reject-all", "authentication_key": "", "prefix_limit": {} } diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json new file mode 100644 index 000000000..4f2f36e4e --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json @@ -0,0 +1,57 @@ +{ + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 65534, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, + "FOO-GROUP": { + "local_address": "", + "description": "FOO", + "type": "", + "local_as": 65534, + "apply_groups": [], + "multihop_ttl": 0, + "remove_private_as": false, + "remote_as": 65534, + "import_policy": "", + "export_policy": "", + "neighbors": { + "192.0.2.2": { + "local_address": "", + "authentication_key": "", + "description": "FOO", + "nhs": false, + "local_as": 65534, + "route_reflector_client": false, + "remote_as": 65534, + "import_policy": "", + "export_policy": "", + "prefix_limit": {} + }, + "192.0.2.3": { + "local_address": "", + "authentication_key": "", + "description": "SECOND-PEER", + "nhs": true, + "local_as": 65534, + "route_reflector_client": false, + "remote_as": 65534, + "import_policy": "", + "export_policy": "", + "prefix_limit": {} + } + }, + "prefix_limit": {}, + "multipath": false + } +} diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text new file mode 100644 index 000000000..0db6d0c27 --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text @@ -0,0 +1,11 @@ +router bgp 65534 + router-id 192.0.2.1 + neighbor FOO-GROUP peer group + neighbor FOO-GROUP next-hop-self + neighbor FOO-GROUP description FOO + neighbor FOO-GROUP remote-as 65534 + neighbor 192.0.2.2 peer group FOO-GROUP + no neighbor 192.0.2.2 next-hop-self + neighbor 192.0.2.3 peer group FOO-GROUP + neighbor 192.0.2.3 description SECOND-PEER +! diff --git a/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text diff --git a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json index de52578fe..bdf8f2657 100644 --- a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1 +1,97 @@ -{"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}} +{ + "_": { + "type": "", + "multipath": false, + "apply_groups": [], + "remove_private_as": false, + "multihop_ttl": 0, + "remote_as": 0, + "local_address": "", + "local_as": 13335, + "description": "", + "import_policy": "", + "export_policy": "", + "prefix_limit": {}, + "neighbors": {} + }, + "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": "reject-all", + "export_policy": "4-public-peer-anycast-out", + "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": "reject-all", + "export_policy": "4-public-peer-anycast-out", + "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": "reject-all", + "export_policy": "reject-all", + "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": "reject-all", + "export_policy": "reject-all", + "prefix_limit": {} + } + }, + "prefix_limit": {}, + "multipath": false + } +} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text new file mode 100644 index 000000000..e69de29bb diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json new file mode 100644 index 000000000..ee7922393 --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json @@ -0,0 +1,112 @@ +{ + "global": { + "peers": { + "fe80::a8c1:abff:fe0b:7b5f%Et5": { + "is_up": true, + "is_enabled": true, + "uptime": "...", + "description": "", + "remote_as": 4259840008, + "remote_id": "172.18.0.8", + "local_as": 4259906562, + "address_family": { + "ipv4": { + "sent_prefixes": 9, + "received_prefixes": 2, + "accepted_prefixes": -1 + }, + "ipv6": { + "sent_prefixes": 9, + "received_prefixes": 2, + "accepted_prefixes": -1 + } + } + }, + "fe80::a8c1:abff:fe27:69e9%Et2": { + "is_up": true, + "is_enabled": true, + "uptime": "...", + "description": "", + "remote_as": 4259973121, + "remote_id": "172.18.8.1", + "local_as": 4259906562, + "address_family": { + "ipv4": { + "sent_prefixes": 9, + "received_prefixes": 5, + "accepted_prefixes": -1 + }, + "ipv6": { + "sent_prefixes": 9, + "received_prefixes": 5, + "accepted_prefixes": -1 + } + } + }, + "fe80::a8c1:abff:fe35:51d9%Et1": { + "is_up": true, + "is_enabled": true, + "uptime": "...", + "description": "", + "remote_as": 4259973120, + "remote_id": "172.18.8.0", + "local_as": 4259906562, + "address_family": { + "ipv4": { + "sent_prefixes": 6, + "received_prefixes": 5, + "accepted_prefixes": -1 + }, + "ipv6": { + "sent_prefixes": 6, + "received_prefixes": 5, + "accepted_prefixes": -1 + } + } + }, + "fe80::a8c1:abff:fe5d:9706%Et4": { + "is_up": true, + "is_enabled": true, + "uptime": "...", + "description": "", + "remote_as": 4259840007, + "remote_id": "172.18.0.7", + "local_as": 4259906562, + "address_family": { + "ipv4": { + "sent_prefixes": 9, + "received_prefixes": 2, + "accepted_prefixes": -1 + }, + "ipv6": { + "sent_prefixes": 9, + "received_prefixes": 2, + "accepted_prefixes": -1 + } + } + }, + "fe80::a8c1:abff:fe95:fa49%Et3": { + "is_up": true, + "is_enabled": true, + "uptime": "...", + "description": "", + "remote_as": 4259840005, + "remote_id": "172.18.0.5", + "local_as": 4259906562, + "address_family": { + "ipv4": { + "sent_prefixes": 9, + "received_prefixes": 2, + "accepted_prefixes": -1 + }, + "ipv6": { + "sent_prefixes": 9, + "received_prefixes": 2, + "accepted_prefixes": -1 + } + } + } + }, + "router_id": "172.18.4.2" + } +} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text new file mode 100644 index 000000000..e69de29bb diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json new file mode 100644 index 000000000..0155ea42a --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json @@ -0,0 +1,76 @@ +{ + "vrfs": { + "default": { + "routerId": "172.18.4.2", + "peers": { + "fe80::a8c1:abff:fe0b:7b5f%Et5": { + "msgSent": 239229, + "inMsgQueue": 0, + "prefixReceived": 2, + "upDownTime": 1664912777.128896, + "version": 4, + "prefixAccepted": 2, + "msgReceived": 203694, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65000.8" + }, + "fe80::a8c1:abff:fe27:69e9%Et2": { + "msgSent": 11997, + "inMsgQueue": 0, + "prefixReceived": 5, + "upDownTime": 1664912780.356704, + "version": 4, + "prefixAccepted": 5, + "msgReceived": 11972, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65002.2049" + }, + "fe80::a8c1:abff:fe35:51d9%Et1": { + "msgSent": 11984, + "inMsgQueue": 0, + "prefixReceived": 5, + "upDownTime": 1664912783.670673, + "version": 4, + "prefixAccepted": 5, + "msgReceived": 11979, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65002.2048" + }, + "fe80::a8c1:abff:fe5d:9706%Et4": { + "msgSent": 239170, + "inMsgQueue": 0, + "prefixReceived": 2, + "upDownTime": 1664912777.50903, + "version": 4, + "prefixAccepted": 2, + "msgReceived": 203718, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65000.7" + }, + "fe80::a8c1:abff:fe95:fa49%Et3": { + "msgSent": 239116, + "inMsgQueue": 0, + "prefixReceived": 2, + "upDownTime": 1664912777.604791, + "version": 4, + "prefixAccepted": 2, + "msgReceived": 203718, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65000.5" + } + }, + "vrf": "default", + "asn": "65001.1026" + } + } +} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text new file mode 100644 index 000000000..f1d5ed371 --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text @@ -0,0 +1,30 @@ +BGP neighbor is fe80::a8c1:abff:fe0b:7b5f%Et5, remote AS 65000.8, external link + BGP version 4, remote router ID 172.18.0.8, VRF default + BGP state is Established, up for 7d01h + IPv4 Unicast: 9 2 1 0 + IPv6 Unicast: 9 2 1 0 +Local AS is 65001.1026, local router ID 172.18.4.2 +BGP neighbor is fe80::a8c1:abff:fe27:69e9%Et2, remote AS 65002.2049, external link + BGP version 4, remote router ID 172.18.8.1, VRF default + BGP state is Established, up for 7d01h + IPv4 Unicast: 9 5 1 0 + IPv6 Unicast: 9 5 1 0 +Local AS is 65001.1026, local router ID 172.18.4.2 +BGP neighbor is fe80::a8c1:abff:fe35:51d9%Et1, remote AS 65002.2048, external link + BGP version 4, remote router ID 172.18.8.0, VRF default + BGP state is Established, up for 7d01h + IPv4 Unicast: 6 5 4 0 + IPv6 Unicast: 6 5 4 0 +Local AS is 65001.1026, local router ID 172.18.4.2 +BGP neighbor is fe80::a8c1:abff:fe5d:9706%Et4, remote AS 65000.7, external link + BGP version 4, remote router ID 172.18.0.7, VRF default + BGP state is Established, up for 7d01h + IPv4 Unicast: 9 2 1 0 + IPv6 Unicast: 9 2 1 0 +Local AS is 65001.1026, local router ID 172.18.4.2 +BGP neighbor is fe80::a8c1:abff:fe95:fa49%Et3, remote AS 65000.5, external link + BGP version 4, remote router ID 172.18.0.5, VRF default + BGP state is Established, up for 7d01h + IPv4 Unicast: 9 2 1 0 + IPv6 Unicast: 9 2 1 0 +Local AS is 65001.1026, local router ID 172.18.4.2 diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json new file mode 100644 index 000000000..aa96e6d48 --- /dev/null +++ b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json @@ -0,0 +1,76 @@ +{ + "vrfs": { + "default": { + "routerId": "172.18.4.2", + "peers": { + "fe80::a8c1:abff:fe0b:7b5f%Et5": { + "msgSent": 239193, + "inMsgQueue": 0, + "prefixReceived": 2, + "upDownTime": 1664912777.128896, + "version": 4, + "prefixAccepted": 2, + "msgReceived": 203664, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65000.8" + }, + "fe80::a8c1:abff:fe27:69e9%Et2": { + "msgSent": 11995, + "inMsgQueue": 0, + "prefixReceived": 5, + "upDownTime": 1664912780.356703, + "version": 4, + "prefixAccepted": 5, + "msgReceived": 11970, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65002.2049" + }, + "fe80::a8c1:abff:fe35:51d9%Et1": { + "msgSent": 11982, + "inMsgQueue": 0, + "prefixReceived": 5, + "upDownTime": 1664912783.670674, + "version": 4, + "prefixAccepted": 5, + "msgReceived": 11977, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65002.2048" + }, + "fe80::a8c1:abff:fe5d:9706%Et4": { + "msgSent": 239135, + "inMsgQueue": 0, + "prefixReceived": 2, + "upDownTime": 1664912777.50903, + "version": 4, + "prefixAccepted": 2, + "msgReceived": 203688, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65000.7" + }, + "fe80::a8c1:abff:fe95:fa49%Et3": { + "msgSent": 239080, + "inMsgQueue": 0, + "prefixReceived": 2, + "upDownTime": 1664912777.604791, + "version": 4, + "prefixAccepted": 2, + "msgReceived": 203688, + "peerState": "Established", + "outMsgQueue": 0, + "underMaintenance": false, + "asn": "65000.5" + } + }, + "vrf": "default", + "asn": "65001.1026" + } + } +} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text b/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text rename to test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json b/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json new file mode 100644 index 000000000..413d219c4 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json @@ -0,0 +1,30 @@ +{ + "management": { + "name": "management", + "type": "L3VRF", + "state": { "route_distinguisher": "" }, + "interfaces": { "interface": { "Management1": {} } } + }, + "default": { + "interfaces": { + "interface": { + "Ethernet1": {}, + "Ethernet2": {}, + "Ethernet3": {}, + "Ethernet4": {}, + "Ethernet49/1": {}, + "Ethernet5": {}, + "Ethernet50/1": {}, + "Ethernet52/1": {}, + "Ethernet53/1": {}, + "Ethernet54/1": {}, + "Ethernet55/1": {}, + "Ethernet56/1": {}, + "Loopback0": {} + } + }, + "state": { "route_distinguisher": "" }, + "type": "DEFAULT_INSTANCE", + "name": "default" + } +} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text new file mode 100644 index 000000000..cd1dbbba4 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text @@ -0,0 +1,12 @@ +Maximum number of vrfs allowed: 1023 + VRF RD Protocols State Interfaces +---------------- --------------- --------------- ------------------- --------------------------- + default ipv4,ipv6 v4:routing, Ethernet1, Ethernet2, + v6:no routing Ethernet3, Ethernet4, + Ethernet49/1, Ethernet5, + Ethernet50/1, Ethernet52/1, + Ethernet53/1, Ethernet54/1, + Ethernet55/1, Ethernet56/1, + Loopback0 + management ipv4,ipv6 v4:routing, Management1 + v6:no routing diff --git a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text index e81cd6e11..65fdb6529 100644 --- a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text +++ b/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text @@ -1,11 +1,11 @@ Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- ------------ ------------ ------------------- ------------------- -VRFA0 201:201 ipv4 v4:routing; multicast, Vlan2, Vlan102 - v6:no routing + Vrf RD Protocols State Interfaces +------- --------- ------------ ------------------------ ------------------- + VRFA0 201:201 ipv4 v4:routing; multicast, Vlan2, Vlan102 + v6:no routing -VRFA1 203:203 ipv4 v4:routing; multicast, Vlan3, Vlan103 - v6:no routing + VRFA1 203:203 ipv4 v4:routing; multicast, Vlan3, Vlan103 + v6:no routing -VRFA2 205:205 ipv4 v4:routing; multicast, Ethernet1, Vlan100 - v6:no routing + VRFA2 205:205 ipv4 v4:routing; multicast, Ethernet1, Vlan100 + v6:no routing diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt b/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt @@ -0,0 +1 @@ +2 diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json b/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json new file mode 100644 index 000000000..dc3f3d294 --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json @@ -0,0 +1,31 @@ +{ + "default": { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": { "route_distinguisher": "" }, + "interfaces": { + "interface": { + "Ethernet1": {}, + "Ethernet2": {}, + "Loopback0": {}, + "Management0": {} + } + } + }, + "foo": { + "name": "foo", + "type": "L3VRF", + "state": { "route_distinguisher": "0:1" }, + "interfaces": { + "interface": {} + } + }, + "bar": { + "name": "bar", + "type": "L3VRF", + "state": { "route_distinguisher": "" }, + "interfaces": { + "interface": {} + } + } +} diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json b/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json new file mode 100644 index 000000000..bbc04245a --- /dev/null +++ b/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json @@ -0,0 +1,61 @@ +{ + "vrfs": { + "foo": { + "routeDistinguisher": "0:1", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfacesV4": [], + "interfacesV6": [], + "interfaces": [] + }, + "bar": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "down" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfacesV4": [], + "interfacesV6": [], + "interfaces": [] + }, + "default": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfacesV4": ["Ethernet1", "Ethernet2", "Loopback0", "Management0"], + "interfacesV6": ["Management0"], + "interfaces": ["Ethernet1", "Ethernet2", "Loopback0", "Management0"] + } + } +} diff --git a/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json index f74d5a593..d6a2343ac 100644 --- a/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json @@ -5,7 +5,7 @@ "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +15,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -37,7 +37,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -75,7 +75,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { diff --git a/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json index 6c5a9cbaa..b75943177 100644 --- a/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json @@ -2,7 +2,7 @@ "_": { "apply_groups": [], "description": "", - "local_as": 0, + "local_as": 42, "type": "", "import_policy": "", "export_policy": "", @@ -20,7 +20,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 42, "authentication_key": "", "nhs": false, "route_reflector_client": false diff --git a/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt b/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt new file mode 100644 index 000000000..50e08a544 --- /dev/null +++ b/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt @@ -0,0 +1,150 @@ +! +! Last configuration change at 18:41:02 UTC Thu Nov 24 2016 +! +version 15.5 +service timestamps debug datetime msec +service timestamps log datetime msec +no platform punt-keepalive disable-kernel-core +platform console auto +! +hostname CSR1 +! +boot-start-marker +boot-end-marker +! +! +enable password cisco +! +aaa new-model +! +! +aaa authentication login default local +aaa authorization exec default local +! +! +! +! +! +aaa session-id common +! +ip vrf MGMT +! +! +! +! +! +! +! +! +! + + +ip domain name example.local + +! +! +! +! +! +! +! +! +! +! +subscriber templating +! +multilink bundle-name authenticated +! +! +! +! +! +! +! +! +! +! +! +! +! +license udi pid CSR1000V sn 9OSEGKJXRHE +spanning-tree extend system-id +! +username cisco privilege 15 password 0 cisco +! +redundancy +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +interface Loopback0 + ip address 1.1.1.1 255.255.255.255 +! +interface GigabitEthernet1 + ip vrf forwarding MGMT + ip address 192.168.35.121 255.255.255.0 + negotiation auto +! +interface GigabitEthernet2 + ip address 10.1.1.1 255.255.255.0 + negotiation auto +! +interface GigabitEthernet3 + no ip address + shutdown + negotiation auto +! +router ospf 1 + redistribute connected subnets + network 10.1.1.0 0.0.0.255 area 0 +! +! +! +! +virtual-service csr_mgmt +! +ip forward-protocol nd +! +no ip http server +no ip http secure-server +! +! +! +! +! +! +control-plane +! + ! + ! + ! + ! +! +! +! +! +! +line con 0 +line vty 0 4 +! +! +end diff --git a/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json index 3f4742397..f58f5e0c5 100644 --- a/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,11 +1,26 @@ { + "_": { + "apply_groups": [], + "description": "", + "local_as": 65001, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": false, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": false, + "prefix_limit": {}, + "neighbors": {} + }, "RR-CLIENTS": { "apply_groups": [], "description": "[ibgp - rr clients]", "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +30,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -37,7 +52,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { diff --git a/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json index d2dfbaf32..1f53b03ff 100644 --- a/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json @@ -5,7 +5,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65001, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +15,7 @@ "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 0, + "local_as": 65001, "nhs": false, "prefix_limit": { "inet": { @@ -37,4 +37,4 @@ "remove_private_as": false, "type": "" } -} \ No newline at end of file +} diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json new file mode 100644 index 000000000..49bc80227 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json @@ -0,0 +1,15 @@ +{ + "GigabitEthernet9/48": [ + { + "port": "Gi0", + "hostname": "COMPUTER.company.example.com" + } + ] + , + "GigabitEthernet9/8": [ + { + "port": "A1:8B:95:B5:E4:6F", + "hostname": "NICEHOSTNAME" + } + ] +} diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt new file mode 100644 index 000000000..f7074e0d7 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt @@ -0,0 +1,8 @@ + +Capability codes: + (R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device + (W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other + +Device ID Local Intf Hold-time Capability Port ID +ACOMPUTER.company.exGi9/48 120 B Gi0 +NICEHOSTNAME Gi9/8 3601 a18b.95b5.e46f diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt new file mode 100644 index 000000000..5908277d6 --- /dev/null +++ b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt @@ -0,0 +1,68 @@ +------------------------------------------------ +Local Intf: Gi9/48 +Chassis id: 4a07.d0f3.fbb6 +Port id: Gi0 +Port Description: GigabitEthernet0 +System Name: COMPUTER.company.example.com + +System Description: +Cisco IOS Software, C3600 Software (AP3G2-K9W8-M), Version 15.3(3)JC15, RELEASE SOFTWARE (fc1) +Technical Support: http://www.cisco.com/techsupport +Copyright (c) 1986-2018 by Cisco Systems, Inc. +Compiled Thu 07-Jun-18 16:43 by prod_rel_team + +Time remaining: 95 seconds +System Capabilities: B +Enabled Capabilities: B +Management Addresses: + IP: 10.31.18.65 +Auto Negotiation - supported, enabled +Physical media capabilities: + 1000baseT(FD) + 1000baseT(HD) + 100base-TX(FD) + 100base-TX(HD) + 10base-T(FD) + 10base-T(HD) +Media Attachment Unit type: 30 +Vlan ID: - not advertised +PoE+ Power-via-MDI TLV: + Power Pair: Signal + Power Class: Class 4 + Power Device Type: Type 1 PD + Power Source: PSE + Power Priority: high + Power Requested: 13000 mW + Power Allocated: 13000 mW + +------------------------------------------------ +Local Intf: Gi9/8 +Chassis id: NICEHOSTNAME +Port id: a18b.95b5.e46f +Port Description - not advertised +System Name - not advertised +System Description - not advertised + +Time remaining: 2690 seconds +System Capabilities - not advertised +Enabled Capabilities - not advertised +Management Addresses - not advertised +Auto Negotiation - supported, enabled +Physical media capabilities: + 1000baseT(FD) +Media Attachment Unit type - not advertised +Vlan ID: - not advertised + +MED Information: + + MED Codes: + (NP) Network Policy, (LI) Location Identification + (PS) Power Source Entity, (PD) Power Device + (IN) Inventory + + Inventory information - not advertised + Capabilities: + Device type: Endpoint Class I + Network Policies - not advertised + Power requirements - not advertised + Location - not advertised diff --git a/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json index e39f06c91..60e669b26 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json @@ -8,7 +8,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "pass-all", "local_address": "", "prefix_limit": { @@ -30,7 +30,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "pass-all", "local_address": "", "prefix_limit": { @@ -54,7 +54,7 @@ "remove_private_as": false, "description": "", "export_policy": "", - "local_as": 0, + "local_as": 65900, "apply_groups": [], "multipath": false, "prefix_limit": {} @@ -68,7 +68,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "RP-SPECIAL-SNOWFLAKE-IN", "local_address": "", "prefix_limit": { @@ -90,7 +90,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 0, + "local_as": 65900, "import_policy": "", "local_address": "", "prefix_limit": {}, @@ -104,7 +104,7 @@ "remove_private_as": true, "description": "", "export_policy": "", - "local_as": 0, + "local_as": 65900, "apply_groups": [], "multipath": false, "prefix_limit": {} diff --git a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt new file mode 100644 index 000000000..1bcd305b2 --- /dev/null +++ b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt @@ -0,0 +1,2 @@ + +default diff --git a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json index 20971ddf8..c850fe601 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,13 +1,28 @@ { + "_": { + "local_as": 13335, + "remove_private_as": false, + "import_policy": "", + "multihop_ttl": 0, + "neighbors": {}, + "multipath": false, + "export_policy": "", + "type": "", + "apply_groups": [], + "remote_as": 0, + "prefix_limit": {}, + "description": "", + "local_address": "" + }, "4-public-anycast-peers": { - "local_as": 0, + "local_as": 13335, "remove_private_as": true, "import_policy": "4-public-anycast-peers-in", "multihop_ttl": 0, "neighbors": { "192.168.20.3": { "export_policy": "", - "local_as": 0, + "local_as": 13335, "prefix_limit": { "inet": { "unicast": { @@ -29,7 +44,7 @@ }, "172.17.17.50": { "export_policy": "", - "local_as": 0, + "local_as": 13335, "prefix_limit": { "inet": { "unicast": { @@ -51,7 +66,7 @@ }, "192.168.50.5": { "export_policy": "", - "local_as": 0, + "local_as": 13335, "prefix_limit": { "inet": { "unicast": { diff --git a/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json index bc0239416..30a30dd4c 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json @@ -10,7 +10,7 @@ "remove_private_as": false, "remote_as": 0, "multihop_ttl": 0, - "local_as": 0, + "local_as": 65900, "apply_groups": [], "neighbors": { "10.255.255.2": { @@ -26,7 +26,7 @@ } } }, - "local_as": 0, + "local_as": 65900, "description": "", "local_address": "", "import_policy": "pass-all", @@ -48,7 +48,7 @@ } } }, - "local_as": 0, + "local_as": 65900, "description": "", "local_address": "", "import_policy": "pass-all", diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml new file mode 100644 index 000000000..7a3a0b218 --- /dev/null +++ b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml @@ -0,0 +1,6 @@ + + + + diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json index 1d60e8893..4ed653140 100644 --- a/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,11 +1,26 @@ { + "_": { + "apply_groups": [], + "description": "", + "export_policy": "", + "import_policy": "", + "local_address": "", + "local_as": 65172, + "multihop_ttl": 0, + "multipath": false, + "neighbors": {}, + "prefix_limit": {}, + "remote_as": 0, + "remove_private_as": false, + "type": "" + }, "EBGP": { "apply_groups": [], "description": "", "export_policy": "EBGP-OUT-POLICY", "import_policy": "EBGP-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +30,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet": { @@ -37,7 +52,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet": { @@ -65,7 +80,7 @@ "export_policy": "EBGP-VRF-OUT-POLICY", "import_policy": "EBGP-VRF-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": {}, @@ -80,7 +95,7 @@ "export_policy": "IBGPv6-OUT-POLICY", "import_policy": "IBGPv6-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -90,7 +105,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet6": { @@ -112,7 +127,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet6": { @@ -140,7 +155,7 @@ "export_policy": "EBGPv6-VRF-OUT-POLICY", "import_policy": "EBGPv6-VRF-IN-POLICY", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": {}, @@ -155,7 +170,7 @@ "export_policy": "IBGP-OUT-POLICY", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -165,7 +180,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet": { @@ -193,7 +208,7 @@ "export_policy": "IBGP-OUT-POLICY", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -203,7 +218,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 0, + "local_as": 65172, "nhs": false, "prefix_limit": { "inet6": { diff --git a/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml new file mode 100644 index 000000000..bd581bc2c --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml @@ -0,0 +1,7 @@ + + + + 65001 + + + diff --git a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json index 93c77a2ec..a375a75a0 100644 --- a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json @@ -1 +1,73 @@ -{"internal":{"apply_groups":[],"description":"","export_policy":"","import_policy":"","local_address":"","local_as":0,"multihop_ttl":0,"multipath":false,"neighbors":{"10.10.10.1":{"authentication_key":"","description":"","export_policy":"nhs","import_policy":"","local_address":"","local_as":0,"nhs":true,"prefix_limit":{},"remote_as":0,"route_reflector_client":false}},"prefix_limit":{},"remote_as":0,"remove_private_as":false,"type":"internal"},"internal-2":{"apply_groups":[],"description":"","export_policy":"","import_policy":"","local_address":"","local_as":0,"multihop_ttl":0,"multipath":false,"neighbors":{"10.10.10.2":{"authentication_key":"","description":"","export_policy":"static","import_policy":"","local_address":"","local_as":0,"nhs":false,"prefix_limit":{},"remote_as":0,"route_reflector_client":false}},"prefix_limit":{},"remote_as":0,"remove_private_as":false,"type":"internal"}} +{ + "_": { + "export_policy": "", + "multipath": false, + "prefix_limit": {}, + "description": "", + "local_as": 65001, + "multihop_ttl": 0, + "apply_groups": [], + "remote_as": 0, + "remove_private_as": false, + "local_address": "", + "type": "", + "import_policy": "", + "neighbors": {} + }, + "internal": { + "apply_groups": [], + "description": "", + "export_policy": "", + "import_policy": "", + "local_address": "", + "local_as": 65001, + "multihop_ttl": 0, + "multipath": false, + "neighbors": { + "10.10.10.1": { + "authentication_key": "", + "description": "", + "export_policy": "nhs", + "import_policy": "", + "local_address": "", + "local_as": 65001, + "nhs": true, + "prefix_limit": {}, + "remote_as": 0, + "route_reflector_client": false + } + }, + "prefix_limit": {}, + "remote_as": 0, + "remove_private_as": false, + "type": "internal" + }, + "internal-2": { + "apply_groups": [], + "description": "", + "export_policy": "", + "import_policy": "", + "local_address": "", + "local_as": 65001, + "multihop_ttl": 0, + "multipath": false, + "neighbors": { + "10.10.10.2": { + "authentication_key": "", + "description": "", + "export_policy": "static", + "import_policy": "", + "local_address": "", + "local_as": 65001, + "nhs": false, + "prefix_limit": {}, + "remote_as": 0, + "route_reflector_client": false + } + }, + "prefix_limit": {}, + "remote_as": 0, + "remove_private_as": false, + "type": "internal" + } +} diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml new file mode 100644 index 000000000..83138436e --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml @@ -0,0 +1,2 @@ + + diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml new file mode 100644 index 000000000..83138436e --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml @@ -0,0 +1,2 @@ + + diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml new file mode 100644 index 000000000..83138436e --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml @@ -0,0 +1,2 @@ + + diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json @@ -0,0 +1 @@ +{} diff --git a/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml new file mode 100644 index 000000000..6ad44d234 --- /dev/null +++ b/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml @@ -0,0 +1,7 @@ + + + + 13335 + + + diff --git a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json index 868ef99cc..6c44290dd 100644 --- a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1 +1,69 @@ -{"PEERS-GROUP-NAME": {"neighbors": {"192.168.0.1": {"export_policy": "", "prefix_limit": {"inet": {"unicast": {"limit": 100}}}, "route_reflector_client": false, "description": "Facebook [CDN]", "local_as": 0, "nhs": false, "local_address": "", "remote_as": 32934, "authentication_key": "", "import_policy": ""}, "172.17.17.1": {"export_policy": "", "prefix_limit": {"inet": {"unicast": {"limit": 500}}}, "route_reflector_client": false, "description": "Twitter [CDN]", "local_as": 0, "nhs": false, "local_address": "", "remote_as": 13414, "authentication_key": "", "import_policy": ""}}, "export_policy": "PUBLIC-PEER-OUT", "multipath": true, "prefix_limit": {}, "description": "", "local_as": 13335, "multihop_ttl": 0, "apply_groups": ["B", "G", "P", "-", "P", "R", "E", "F", "I", "X", "-", "L", "I", "M", "I", "T"], "remote_as": 0, "remove_private_as": true, "local_address": "", "type": "external", "import_policy": "PUBLIC-PEER-IN"}} +{ + "_": { + "export_policy": "", + "multipath": false, + "prefix_limit": {}, + "description": "", + "local_as": 13335, + "multihop_ttl": 0, + "apply_groups": [], + "remote_as": 0, + "remove_private_as": false, + "local_address": "", + "type": "", + "import_policy": "", + "neighbors": {} + }, + "PEERS-GROUP-NAME": { + "neighbors": { + "192.168.0.1": { + "export_policy": "", + "prefix_limit": { + "inet": { + "unicast": { + "limit": 100 + } + } + }, + "route_reflector_client": false, + "description": "Facebook [CDN]", + "local_as": 13335, + "nhs": false, + "local_address": "", + "remote_as": 32934, + "authentication_key": "", + "import_policy": "" + }, + "172.17.17.1": { + "export_policy": "", + "prefix_limit": { + "inet": { + "unicast": { + "limit": 500 + } + } + }, + "route_reflector_client": false, + "description": "Twitter [CDN]", + "local_as": 13335, + "nhs": false, + "local_address": "", + "remote_as": 13414, + "authentication_key": "", + "import_policy": "" + } + }, + "export_policy": "PUBLIC-PEER-OUT", + "multipath": true, + "prefix_limit": {}, + "description": "", + "local_as": 13335, + "multihop_ttl": 0, + "apply_groups": ["BGP-PREFIX-LIMIT"], + "remote_as": 0, + "remove_private_as": true, + "local_address": "", + "type": "external", + "import_policy": "PUBLIC-PEER-IN" + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json new file mode 100644 index 000000000..ca3d2f110 --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json @@ -0,0 +1,36 @@ +{ + "management": { + "name": "management", + "type": "L3VRF", + "state": { + "route_distinguisher": "0:0" + }, + "interfaces": { + "interface": { + "mgmt0": {} + } + } + }, + "default": { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": { + "route_distinguisher": "0:0" + }, + "interfaces": { + "interface": { + "Vlan1": {}, + "Vlan100": {}, + "Vlan101": {}, + "Vlan102": {}, + "Vlan103": {}, + "Vlan104": {}, + "Vlan105": {}, + "loopback1": {}, + "Null0": {}, + "Ethernet1/5": {}, + "Ethernet1/5.1": {} + } + } + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt new file mode 100644 index 000000000..637f62365 --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt @@ -0,0 +1,58 @@ +{ + "TABLE_vrf": { + "ROW_vrf": [ + { + "vrf_name": "default", + "vrf_id": 1, + "vrf_state": "Up", + "vpnid": "unknown", + "rd": "0:0", + "vni": 0, + "max_routes": 0, + "mid_threshold": 0, + "TABLE_tib": { + "ROW_tib": [ + { + "tib_id": 80000001, + "tib_af": "IPv6", + "tib_nonce": 80000001, + "tib_state": "Up" + }, + { + "tib_id": 1, + "tib_af": "IPv4", + "tib_nonce": 1, + "tib_state": "Up" + } + ] + } + }, + { + "vrf_name": "management", + "vrf_id": 2, + "vrf_state": "Up", + "vpnid": "unknown", + "rd": "0:0", + "vni": 0, + "max_routes": 0, + "mid_threshold": 0, + "TABLE_tib": { + "ROW_tib": [ + { + "tib_id": 80000002, + "tib_af": "IPv6", + "tib_nonce": 80000002, + "tib_state": "Up" + }, + { + "tib_id": 2, + "tib_af": "IPv4", + "tib_nonce": 2, + "tib_state": "Up" + } + ] + } + } + ] + } +} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt new file mode 100644 index 000000000..72a325a0d --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt @@ -0,0 +1,78 @@ +{ + "TABLE_if": { + "ROW_if": [ + { + "if_name": "Vlan1", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan100", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan101", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan102", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan103", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan104", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Vlan105", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "loopback1", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Null0", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Ethernet1/5", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "Ethernet1/5.1", + "vrf_name": "default", + "vrf_id": 1, + "soo": "--" + }, + { + "if_name": "mgmt0", + "vrf_name": "management", + "vrf_id": 2, + "soo": "--" + } + ] + } +} diff --git a/test/pyiosxr/test_iosxr.py b/test/pyiosxr/test_iosxr.py index 9c8128c45..b8485659d 100755 --- a/test/pyiosxr/test_iosxr.py +++ b/test/pyiosxr/test_iosxr.py @@ -257,7 +257,7 @@ def test__getattr_show_config(self): def test__getattr__no_show(self): - """Test special attribute __getattr__ agains a no-show command""" + """Test special attribute __getattr__ against a no-show command""" raised = False diff --git a/tox.ini b/tox.ini deleted file mode 100644 index a6f11697f..000000000 --- a/tox.ini +++ /dev/null @@ -1,39 +0,0 @@ -[tox] -envlist = py3{6,7,8},black,pylama -skip_missing_interpreters = true - -[testenv] -deps = - -rrequirements.txt - -rrequirements-dev.txt -passenv = * - -commands = - py.test --cov=napalm --cov-report term-missing -vs --pylama {posargs} - -[testenv:black] -deps = black==20.8b1 - -basepython = python3.6 -commands = - black --check . - -[testenv:pylama] -deps = - -rrequirements-dev.txt - -basepython = python3.6 -commands = - pylama . - -[testenv:sphinx] -deps = - -rdocs/requirements.txt - -basepython = python3.6 - -commands = - make doctest - -whitelist_externals = - make From f5000c7e9068206bf86dd576b072ed2c9ad2436d Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 23 May 2023 10:35:30 -0700 Subject: [PATCH 50/76] Revert "NAPALM 4.1.0 Release (#1936)" (#1937) This reverts commit 02a7657b2c80c4474c2ac6938fff99f5802f2cae. --- .github/workflows/commit.yaml | 14 +- .github/workflows/pythonpublish.yml | 17 +- .gitignore | 1 - .readthedocs.yml | 3 +- docs/conf.py | 6 +- docs/development/testing_framework.rst | 55 +--- docs/requirements.txt | 13 +- docs/support/index.rst | 3 +- docs/support/ios.rst | 2 +- docs/support/nxos.rst | 2 +- docs/test.sh | 10 +- napalm/base/base.py | 8 +- napalm/base/canonical_map.py | 157 ++++++++++- napalm/base/helpers.py | 111 ++++++-- napalm/base/test/getters.py | 2 +- napalm/base/utils/string_parsers.py | 16 +- napalm/eos/eos.py | 252 ++++++------------ napalm/ios/ios.py | 94 +++---- napalm/iosxr/iosxr.py | 66 ++--- napalm/iosxr_netconf/iosxr_netconf.py | 65 ++--- napalm/junos/junos.py | 95 ++----- napalm/junos/utils/junos_views.yml | 9 - napalm/nxos/nxos.py | 24 +- napalm/nxos_ssh/nxos_ssh.py | 105 ++------ napalm/pyIOSXR/iosxr.py | 2 +- requirements-dev.txt | 30 +-- requirements.txt | 4 +- setup.cfg | 4 +- setup.py | 2 +- test/base/test_helpers.py | 125 ++++++--- test/eos/conftest.py | 13 - .../expected_result.json | 23 +- .../issue_1113_dot_asn/expected_result.json | 31 +-- .../expected_result.json | 57 ---- ...w_running_config___section_router_bgp.text | 11 - .../no_bgp_config/expected_result.json | 1 - .../normal/expected_result.json | 98 +------ ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ..._AS___Local_AS_Desc_BGP_state__remote.text | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 .../issue1759/expected_result.json | 112 -------- ...S___Local_AS_Desc_BGP_state__remote_r.text | 0 .../show_ip_bgp_summary_vrf_all.json | 76 ------ ..._AS___Local_AS_Desc_BGP_state__remote.text | 30 --- .../show_ipv6_bgp_summary_vrf_all.json | 76 ------ ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 ...E_____0_9____Local_AS_Desc_BGP_state.text} | 0 .../issue-1922/expected_result.json | 30 --- .../issue-1922/show_vrf.text | 12 - .../issue-509/show_vrf.text | 16 +- .../vrf/cli_version.txt | 1 - .../vrf/expected_result.json | 31 --- .../vrf/show_vrf.json | 61 ----- .../expected_result.json | 8 +- .../no_afi/expected_result.json | 4 +- .../no_bgp/expected_result.json | 1 - .../no_bgp/show_running_config.txt | 150 ----------- .../normal/expected_result.json | 21 +- .../peers_without_groups/expected_result.json | 6 +- .../no_mac_support/expected_result.json | 15 -- .../no_mac_support/show_lldp_neighbors.txt | 8 - .../show_lldp_neighbors_detail.txt | 68 ----- .../expected_result.json | 12 +- ..._Instance___BGP___Configuration___Get_.txt | 2 - .../no_bgp/expected_result.json | 1 - .../normal/expected_result.json | 23 +- .../peers_without_groups/expected_result.json | 6 +- .../no_bgp/expected_result.json | 1 - .../no_bgp/ipv4-bgp-cfg_bgp__running.xml | 6 - .../normal/expected_result.json | 39 +-- ...em____routing_options___configuration_.xml | 7 - .../nhs/expected_result.json | 74 +---- ...ent____policy_options___configuration_.xml | 2 - ...up____bgp___protocols___configuration_.xml | 2 - ...em____routing_options___configuration_.xml | 2 - .../no_bgp/expected_result.json | 1 - ...em____routing_options___configuration_.xml | 7 - .../normal/expected_result.json | 70 +---- .../normal/expected_result.json | 36 --- .../normal/show_vrf_detail___json.txt | 58 ---- .../normal/show_vrf_interface___json.txt | 78 ------ test/pyiosxr/test_iosxr.py | 2 +- tox.ini | 39 +++ 89 files changed, 728 insertions(+), 1997 deletions(-) delete mode 100644 test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text delete mode 100644 test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json rename test/eos/mocked_data/test_get_bgp_neighbors/issue1168/{show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text => show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1168/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1356/{show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text => show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) delete mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename test/eos/mocked_data/{test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text => test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) delete mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text delete mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json delete mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text delete mode 100644 test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json rename test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/{show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text => show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue944/{show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text => show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue944/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/normal/{show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text => show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/normal/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text} (100%) delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text delete mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt delete mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json delete mode 100644 test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json delete mode 100644 test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt delete mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json delete mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt delete mode 100644 test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt delete mode 100644 test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt delete mode 100644 test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json delete mode 100644 test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json delete mode 100644 test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml delete mode 100644 test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml delete mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml delete mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml delete mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml delete mode 100644 test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json delete mode 100644 test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml delete mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json delete mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt delete mode 100644 test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt create mode 100644 tox.ini diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index 0329a5554..f7d265f1f 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -10,14 +10,14 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.7, 3.8, 3.9, 3.10.9, 3.11] + python-version: [3.7, 3.8, 3.9, 3.10.0] steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} @@ -54,10 +54,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} @@ -65,9 +65,9 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -e . - python -m pip install -r docs/requirements.txt - pip install -r requirements-dev.txt pip install -r requirements.txt + pip install -r requirements-dev.txt + python -m pip install -r docs/requirements.txt - name: Doctests run: | diff --git a/.github/workflows/pythonpublish.yml b/.github/workflows/pythonpublish.yml index ed1ba114e..1fba0b41b 100644 --- a/.github/workflows/pythonpublish.yml +++ b/.github/workflows/pythonpublish.yml @@ -12,20 +12,19 @@ jobs: deploy: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v1 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v1 with: python-version: '3.x' - name: Install dependencies run: | python -m pip install --upgrade pip - pip install setuptools wheel - - name: Build + pip install setuptools wheel twine + - name: Build and publish + env: + TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} + TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} run: | python setup.py sdist bdist_wheel - - name: Publish - uses: pypa/gh-action-pypi-publish@master - with: - user: __token__ - password: ${{ secrets.PYPI_TOKEN }} + twine upload dist/* diff --git a/.gitignore b/.gitignore index 87330b57c..a00f7f807 100644 --- a/.gitignore +++ b/.gitignore @@ -65,7 +65,6 @@ env test/unit/test_devices.py -.report.json report.json tags .pytest_cache/ diff --git a/.readthedocs.yml b/.readthedocs.yml index 320d0121d..65fd950da 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -14,10 +14,9 @@ formats: all # Optionally set the version of Python and requirements required to build your docs python: - version: 3.8 + version: 3.7 install: - method: pip path: . - requirements: docs/requirements.txt - - requirements: requirements-dev.txt - requirements: requirements.txt diff --git a/docs/conf.py b/docs/conf.py index d9b5774cd..cf56e0537 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -371,13 +371,13 @@ def build_getters_support_matrix(app): if not (m.startswith("_") or m in EXCLUDE_METHODS) } - regex_name = re.compile(r"test.*/(?P\w+)\/.*::test_(?P\w+)") + regex_name = re.compile(r"(?P\w+)\/.*::test_(?P\w+)") filename = "./support/tests/report.json" with open(filename, "r") as f: data = json.loads(f.read()) - for test in data["tests"]: - match = regex_name.search(test["nodeid"]) + for test in data["report"]["tests"]: + match = regex_name.search(test["name"]) if match: driver = match.group("driver") drivers.add(driver) diff --git a/docs/development/testing_framework.rst b/docs/development/testing_framework.rst index ef5a7ed7f..2b61cc9da 100644 --- a/docs/development/testing_framework.rst +++ b/docs/development/testing_framework.rst @@ -1,7 +1,7 @@ Testing Framework ----------------- -As NAPALM consists of multiple drivers and all of them have to provide similar functionality, we have developed a testing framework to provide a consistent test suite for all the drivers. +As napalm consists of multiple drivers and all of them have to provide similar functionality, we have developed a testing framework to provide a consistent test suite for all the drivers. Features ________ @@ -42,7 +42,7 @@ By default, the tests are going to be run against mocked data but you can change * ``NAPALM_USERNAME`` * ``NAPALM_PASSWORD`` * ``NAPALM_OPTIONAL_ARGS`` - + Mocking the ``open`` method ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,29 +56,29 @@ Multiple test cases:: (napalm) ➜ napalm-eos git:(test_framework) ✗ ls test/unit/mocked_data/test_get_bgp_neighbors lots_of_peers no_peers normal (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors - ... + ... test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[lots_of_peers] <- ../napalm/napalm.base/test/getters.py PASSED test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[no_peers] <- ../napalm/napalm.base/test/getters.py PASSED test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[normal] <- ../napalm/napalm.base/test/getters.py PASSED - + Missing test cases:: (napalm) ➜ napalm-eos git:(test_framework) ✗ ls test/unit/mocked_data/test_get_bgp_neighbors ls: test/unit/mocked_data/test_get_bgp_neighbors: No such file or directory (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors - ... + ... test/unit/test_getters.py::TestGetter::test_get_bgp_neighbors[no_test_case_found] <- ../napalm/napalm.base/test/getters.py FAILED - + ========================================================= FAILURES ========================================================== ___________________________________ TestGetter.test_get_bgp_neighbors[no_test_case_found] ___________________________________ - + cls = , test_case = 'no_test_case_found' - + @functools.wraps(func) def wrapper(cls, test_case): cls.device.device.current_test = func.__name__ cls.device.device.current_test_case = test_case - + try: # This is an ugly, ugly, ugly hack because some python objects don't load # as expected. For example, dicts where integers are strings @@ -87,7 +87,7 @@ Missing test cases:: if test_case == "no_test_case_found": > pytest.fail("No test case for '{}' found".format(func.__name__)) E Failed: No test case for 'test_get_bgp_neighbors' found - + ../napalm/napalm.base/test/getters.py:64: Failed ================================================= 1 failed in 0.12 seconds ================================================== @@ -96,41 +96,8 @@ Method not implemented:: (napalm) ➜ napalm-eos git:(test_framework) ✗ py.test test/unit/test_getters.py::TestGetter::test_get_probes_config ... test/unit/test_getters.py::TestGetter::test_get_probes_config[no_test_case_found] <- ../napalm/napalm.base/test/getters.py SKIPPED - + ================================================= 1 skipped in 0.09 seconds ================================================= -Testing Matrix --------------- - -NAPALM leverages [Github Actions](https://docs.github.com/en/actions) to test and lint code on commits and pull requests. -If you want to test prior to opening a pull request, you can use [nektos/act](https://github.com/nektos/act) and Docker to locally run the tests - -.. code-block:: console - - $ act -j std_tests - [build/std_tests-4] 🚀 Start image=catthehacker/ubuntu:act-latest - [build/std_tests-3] 🚀 Start image=catthehacker/ubuntu:act-latest - [build/std_tests-1] 🚀 Start image=catthehacker/ubuntu:act-latest - [build/std_tests-2] 🚀 Start image=catthehacker/ubuntu:act-latest - [build/std_tests-5] 🚀 Start image=catthehacker/ubuntu:act-latest - [build/std_tests-4] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true - [build/std_tests-1] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true - [build/std_tests-3] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true - [build/std_tests-5] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true - [build/std_tests-2] 🐳 docker pull image=catthehacker/ubuntu:act-latest platform= username= forcePull=true - - ... - - | --------------------------------------------------------------------- - | TOTAL 9258 1836 80% - | - | ================= 619 passed, 80 skipped, 3 warnings in 19.97s ================= - [build/std_tests-5] ✅ Success - Main Run Tests - [build/std_tests-5] ⭐ Run Post Setup Python 3.11 - [build/std_tests-5] 🐳 docker exec cmd=[node /var/run/act/actions/actions-setup-python@v2/dist/cache-save/index.js] user= workdir= - [build/std_tests-5] ✅ Success - Post Setup Python 3.11 - [build/std_tests-5] 🏁 Job succeeded - - .. _`test_getters.py`: https://github.com/napalm-automation/napalm-eos/blob/a2fc2cf6a98b0851efe4cba907086191b8f1df02/test/unit/test_getters.py .. _`conftest.py`: https://github.com/napalm-automation/napalm-eos/blob/a2fc2cf6a98b0851efe4cba907086191b8f1df02/test/unit/conftest.py diff --git a/docs/requirements.txt b/docs/requirements.txt index 24e3fa96b..f822bffdb 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,9 +1,4 @@ -urllib3==1.26.15 # https://github.com/readthedocs/readthedocs.org/issues/10290 -sphinx==1.8.6 -sphinx-rtd-theme==1.2.0 -sphinxcontrib-napoleon==0.7 -invoke==2.0.0 -jinja2==2.11.3 -MarkupSafe==2.0.1 -pytest==7.2.2 -ansible==4.10.0 +sphinx +sphinx-rtd-theme +sphinxcontrib-napoleon +invoke diff --git a/docs/support/index.rst b/docs/support/index.rst index 78ad1191a..f869f592c 100644 --- a/docs/support/index.rst +++ b/docs/support/index.rst @@ -13,7 +13,7 @@ General support matrix ===================== ========== ============= ==================== ================== ============ ============ ============ **Driver Name** eos junos iosxr_netconf iosxr nxos nxos_ssh ios **Structured data** Yes Yes Yes No Yes No No - **Minimum version** 4.15.0F 12.1 7.0 5.1.0 6.1 [#g1]_ 6.3.2 12.4(20)T + **Minimum version** 4.15.0F 12.1 7.0 5.1.0 6.1 [#g1]_ 12.4(20)T 6.3.2 **Backend library** `pyeapi`_ `junos-eznc`_ `ncclient`_ `pyIOSXR`_ `pynxos`_ `netmiko`_ `netmiko`_ **Caveats** :doc:`eos` :doc:`iosxr_netconf` :doc:`nxos` :doc:`nxos` :doc:`ios` ===================== ========== ============= ==================== ================== ============ ============ ============ @@ -141,7 +141,6 @@ ____________________________________ * :code:`eos_fn0039_config` (eos) - Transform old style configuration to the new style, available beginning with EOS release 4.23.0, as per FN 0039. Beware that enabling this option will change the configuration you're loading through NAPALM. Default: ``False`` (won't change your configuration commands). .. versionadded:: 3.0.1 -* :code:`force_cfg_session_invalid` (eos) - Force the config_session to be cleared in case of issues, like `discard_config` failure. (default: ``False``) The transport argument ______________________ diff --git a/docs/support/ios.rst b/docs/support/ios.rst index 1bbc5116e..b46a92a54 100644 --- a/docs/support/ios.rst +++ b/docs/support/ios.rst @@ -116,7 +116,7 @@ File Operation Prompts ______________________ By default IOS will prompt for confirmation on file operations. These prompts need to be disabled before the NAPALM-ios driver performs any such operation on the device. -This can be controlled using the `auto_file_prompt` optional argument: +This can be controlled using the `auto_file_prompt` optional arguement: * `auto_file_prompt=True` (default): NAPALM will automatically add `file prompt quiet` to the device configuration before performing file operations, and un-configure it again afterwards. If the device already had the command in its configuration then it will be silently removed as a result, and diff --git a/docs/support/nxos.rst b/docs/support/nxos.rst index 9f9e5ee8b..0dfff92be 100644 --- a/docs/support/nxos.rst +++ b/docs/support/nxos.rst @@ -71,7 +71,7 @@ One caveat of using netutils diff of configurations is that the diff is performe Example assuming that the device config contains: -.. code-block:: bash +.. code-block:: interface loopback0 ip address 10.1.4.4/32 diff --git a/docs/test.sh b/docs/test.sh index 3d102c74a..78a572fac 100755 --- a/docs/test.sh +++ b/docs/test.sh @@ -1,12 +1,14 @@ #!/bin/bash CWD=`pwd` TEST_RESULTS_PATH="$CWD/support/tests" -REPOBASE=$CWD/.. -if [ ! -f ".report.json" ]; then +if [ ! -f "report.json" ]; then set -e - pytest --rootdir $REPOBASE -c /dev/null --json-report --cov=./ -vs $REPOBASE/test*/*/test_getters.py + pip install -r ../requirements.txt -r ../requirements-dev.txt + set +e + py.test -c /dev/null --cov=./ -vs --json=report.json ../test*/*/test_getters.py set -e - cp .report.json $TEST_RESULTS_PATH/report.json + + cp report.json $TEST_RESULTS_PATH/report.json fi diff --git a/napalm/base/base.py b/napalm/base/base.py index 7410bf6a8..1259f6966 100644 --- a/napalm/base/base.py +++ b/napalm/base/base.py @@ -19,7 +19,6 @@ from typing_extensions import Literal from netmiko import ConnectHandler, NetMikoTimeoutException -from netutils.interface import canonical_interface_name # local modules import napalm.base.exceptions @@ -648,8 +647,7 @@ def get_bgp_config( :param neighbor: Returns the configuration of a specific BGP neighbor. Main dictionary keys represent the group name and the values represent a dictionary having - the keys below. A default group named "_" will contain information regarding global - settings and any neighbors that are not members of a group. + the keys below. Neighbors which aren't members of a group will be stored in a key named "_": * type (string) * description (string) @@ -1806,6 +1804,8 @@ def compliance_report( def _canonical_int(self, interface: str) -> str: """Expose the helper function within this class.""" if self.use_canonical_interface is True: - return canonical_interface_name(interface, addl_name_map=None) + return napalm.base.helpers.canonical_interface_name( + interface, addl_name_map=None + ) else: return interface diff --git a/napalm/base/canonical_map.py b/napalm/base/canonical_map.py index fb9658213..29b50e714 100644 --- a/napalm/base/canonical_map.py +++ b/napalm/base/canonical_map.py @@ -1,4 +1,153 @@ -# Do not remove the below imports, functions were moved to netutils, but to not -# break backwards compatibility, these should remain -from netutils.constants import BASE_INTERFACES as base_interfaces # noqa -from netutils.constants import REVERSE_MAPPING as reverse_mapping # noqa +base_interfaces = { + "ATM": "ATM", + "AT": "ATM", + "B": "Bdi", + "Bd": "Bdi", + "Bdi": "Bdi", + "EOBC": "EOBC", + "EO": "EOBC", + "Ethernet": "Ethernet", + "Eth": "Ethernet", + "eth": "Ethernet", + "Et": "Ethernet", + "et": "Ethernet", + "FastEthernet": "FastEthernet", + "FastEth": "FastEthernet", + "FastE": "FastEthernet", + "Fast": "FastEthernet", + "Fas": "FastEthernet", + "FE": "FastEthernet", + "Fa": "FastEthernet", + "fa": "FastEthernet", + "Fddi": "Fddi", + "FD": "Fddi", + "FortyGigabitEthernet": "FortyGigabitEthernet", + "FortyGigEthernet": "FortyGigabitEthernet", + "FortyGigEth": "FortyGigabitEthernet", + "FortyGigE": "FortyGigabitEthernet", + "FortyGig": "FortyGigabitEthernet", + "FGE": "FortyGigabitEthernet", + "FO": "FortyGigabitEthernet", + "Fo": "FortyGigabitEthernet", + "FiftyGigabitEthernet": "FiftyGigabitEthernet", + "FiftyGigEthernet": "FiftyGigabitEthernet", + "FiftyGigEth": "FiftyGigabitEthernet", + "FiftyGigE": "FiftyGigabitEthernet", + "FI": "FiftyGigabitEthernet", + "Fi": "FiftyGigabitEthernet", + "fi": "FiftyGigabitEthernet", + "GigabitEthernet": "GigabitEthernet", + "GigEthernet": "GigabitEthernet", + "GigEth": "GigabitEthernet", + "GigE": "GigabitEthernet", + "Gig": "GigabitEthernet", + "GE": "GigabitEthernet", + "Ge": "GigabitEthernet", + "ge": "GigabitEthernet", + "Gi": "GigabitEthernet", + "gi": "GigabitEthernet", + "HundredGigabitEthernet": "HundredGigabitEthernet", + "HundredGigEthernet": "HundredGigabitEthernet", + "HundredGigEth": "HundredGigabitEthernet", + "HundredGigE": "HundredGigabitEthernet", + "HundredGig": "HundredGigabitEthernet", + "Hu": "HundredGigabitEthernet", + "TwentyFiveGigabitEthernet": "TwentyFiveGigabitEthernet", + "TwentyFiveGigEthernet": "TwentyFiveGigabitEthernet", + "TwentyFiveGigEth": "TwentyFiveGigabitEthernet", + "TwentyFiveGigE": "TwentyFiveGigabitEthernet", + "TwentyFiveGig": "TwentyFiveGigabitEthernet", + "TF": "TwentyFiveGigabitEthernet", + "Tf": "TwentyFiveGigabitEthernet", + "tf": "TwentyFiveGigabitEthernet", + "TwoHundredGigabitEthernet": "TwoHundredGigabitEthernet", + "TwoHundredGigEthernet": "TwoHundredGigabitEthernet", + "TwoHundredGigEth": "TwoHundredGigabitEthernet", + "TwoHundredGigE": "TwoHundredGigabitEthernet", + "TwoHundredGig": "TwoHundredGigabitEthernet", + "TH": "TwoHundredGigabitEthernet", + "Th": "TwoHundredGigabitEthernet", + "th": "TwoHundredGigabitEthernet", + "FourHundredGigabitEthernet": "FourHundredGigabitEthernet", + "FourHundredGigEthernet": "FourHundredGigabitEthernet", + "FourHundredGigEth": "FourHundredGigabitEthernet", + "FourHundredGigE": "FourHundredGigabitEthernet", + "FourHundredGig": "FourHundredGigabitEthernet", + "F": "FourHundredGigabitEthernet", + "f": "FourHundredGigabitEthernet", + "Loopback": "Loopback", + "loopback": "Loopback", + "Lo": "Loopback", + "lo": "Loopback", + "Management": "Management", + "Mgmt": "Management", + "mgmt": "Management", + "Ma": "Management", + "Management_short": "Ma", + "MFR": "MFR", + "Multilink": "Multilink", + "Mu": "Multilink", + "n": "nve", + "nv": "nve", + "nve": "nve", + "PortChannel": "Port-channel", + "Port-channel": "Port-channel", + "Port-Channel": "Port-channel", + "port-channel": "Port-channel", + "po": "Port-channel", + "Po": "Port-channel", + "POS": "POS", + "PO": "POS", + "Serial": "Serial", + "Se": "Serial", + "S": "Serial", + "TenGigabitEthernet": "TenGigabitEthernet", + "TenGigEthernet": "TenGigabitEthernet", + "TenGigEth": "TenGigabitEthernet", + "TenGig": "TenGigabitEthernet", + "TeGig": "TenGigabitEthernet", + "Ten": "TenGigabitEthernet", + "T": "TenGigabitEthernet", + "Te": "TenGigabitEthernet", + "te": "TenGigabitEthernet", + "Tunnel": "Tunnel", + "Tun": "Tunnel", + "Tu": "Tunnel", + "Twe": "TwentyFiveGigE", + "Tw": "TwoGigabitEthernet", + "Two": "TwoGigabitEthernet", + "Virtual-Access": "Virtual-Access", + "Vi": "Virtual-Access", + "Virtual-Template": "Virtual-Template", + "Vt": "Virtual-Template", + "VLAN": "VLAN", + "V": "VLAN", + "Vl": "VLAN", + "Wlan-GigabitEthernet": "Wlan-GigabitEthernet", +} + +reverse_mapping = { + "ATM": "At", + "EOBC": "EO", + "Ethernet": "Et", + "FastEthernet": "Fa", + "Fddi": "FD", + "FortyGigabitEthernet": "Fo", + "GigabitEthernet": "Gi", + "HundredGigabitEthernet": "Hu", + "Loopback": "Lo", + "Management": "Ma", + "MFR": "MFR", + "Multilink": "Mu", + "Port-channel": "Po", + "POS": "PO", + "Serial": "Se", + "TenGigabitEthernet": "Te", + "Tunnel": "Tu", + "TwoGigabitEthernet": "Two", + "TwentyFiveGigE": "Twe", + "Virtual-Access": "Vi", + "Virtual-Template": "Vt", + "VLAN": "Vl", + "Wlan-GigabitEthernet": "Wl-Gi", +} diff --git a/napalm/base/helpers.py b/napalm/base/helpers.py index dd58ddc7a..935dfd58d 100644 --- a/napalm/base/helpers.py +++ b/napalm/base/helpers.py @@ -1,5 +1,4 @@ """Helper functions for the NAPALM base.""" -import ipaddress import itertools import logging @@ -15,17 +14,10 @@ import textfsm from lxml import etree from netaddr import EUI +from netaddr import IPAddress from netaddr import mac_unix from netutils.config.parser import IOSConfigParser -# Do not remove the below imports, functions were moved to netutils, but to not -# break backwards compatibility, these should remain -from netutils.interface import abbreviated_interface_name # noqa -from netutils.interface import canonical_interface_name # noqa -from netutils.constants import BASE_INTERFACES as base_interfaces # noqa -from netutils.constants import REVERSE_MAPPING as reverse_mapping # noqa -from netutils.interface import split_interface as _split_interface - try: from ttp import quick_parse as ttp_quick_parse @@ -38,6 +30,7 @@ from napalm.base import constants from napalm.base.models import ConfigDict from napalm.base.utils.jinja_filters import CustomJinjaFilters +from napalm.base.canonical_map import base_interfaces, reverse_mapping T = TypeVar("T") R = TypeVar("R") @@ -544,19 +537,10 @@ def ip(addr: str, version: Optional[int] = None) -> str: >>> ip('2001:0dB8:85a3:0000:0000:8A2e:0370:7334') u'2001:db8:85a3::8a2e:370:7334' """ - scope = "" - if "%" in addr: - addr, scope = addr.split("%", 1) - addr_obj = ipaddress.ip_address(addr) + addr_obj = IPAddress(addr) if version and addr_obj.version != version: raise ValueError("{} is not an ipv{} address".format(addr, version)) - if addr_obj.version == 6 and addr_obj.ipv4_mapped is not None: - return_addr = "%s:%s" % ("::ffff", addr_obj.ipv4_mapped) - else: - return_addr = str(addr_obj) - if scope: - return_addr = "%s%%%s" % (return_addr, scope) - return return_addr + return str(addr_obj) def as_number(as_number_val: str) -> int: @@ -571,7 +555,92 @@ def as_number(as_number_val: str) -> int: def split_interface(intf_name: str) -> Tuple[str, str]: """Split an interface name based on first digit, slash, or space match.""" - return _split_interface(interface=intf_name) + head = intf_name.rstrip(r"/\0123456789. ") + tail = intf_name[len(head) :].lstrip() + return (head, tail) + + +def canonical_interface_name( + interface: str, addl_name_map: Optional[Dict[str, str]] = None +) -> str: + """Function to return an interface's canonical name (fully expanded name). + + Use of explicit matches used to indicate a clear understanding on any potential + match. Regex and other looser matching methods were not implmented to avoid false + positive matches. As an example, it would make sense to do "[P|p][O|o]" which would + incorrectly match PO = POS and Po = Port-channel, leading to a false positive, not + easily troubleshot, found, or known. + + :param interface: The interface you are attempting to expand. + :param addl_name_map: A dict containing key/value pairs that updates + the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs + {"Po": "Port-Channel"} + :type addl_name_map: optional + """ + + name_map = {} + name_map.update(base_interfaces) + interface_type, interface_number = split_interface(interface) + + if isinstance(addl_name_map, dict): + name_map.update(addl_name_map) + # check in dict for mapping + if name_map.get(interface_type): + long_int = name_map.get(interface_type) + assert isinstance(long_int, str) + return long_int + str(interface_number) + # if nothing matched, return the original name + else: + return interface + + +def abbreviated_interface_name( + interface: str, + addl_name_map: Optional[Dict[str, str]] = None, + addl_reverse_map: Optional[Dict[str, str]] = None, +) -> str: + """Function to return an abbreviated representation of the interface name. + + :param interface: The interface you are attempting to abbreviate. + :param addl_name_map: A dict containing key/value pairs that updates + the base mapping. Used if an OS has specific differences. e.g. {"Po": "PortChannel"} vs + {"Po": "Port-Channel"} + :type addl_name_map: optional + :param addl_reverse_map: A dict containing key/value pairs that updates + the reverse mapping. Used if an OS has specific differences. e.g. {"PortChannel": "Po"} vs + {"PortChannel": "po"} + :type addl_reverse_map: optional + """ + + name_map = {} + name_map.update(base_interfaces) + interface_type, interface_number = split_interface(interface) + + if isinstance(addl_name_map, dict): + name_map.update(addl_name_map) + + rev_name_map = {} + rev_name_map.update(reverse_mapping) + + if isinstance(addl_reverse_map, dict): + rev_name_map.update(addl_reverse_map) + + # Try to ensure canonical type. + if name_map.get(interface_type): + canonical_type = name_map.get(interface_type) + else: + canonical_type = interface_type + + assert isinstance(canonical_type, str) + + try: + abbreviated_name = rev_name_map[canonical_type] + str(interface_number) + return abbreviated_name + except KeyError: + pass + + # If abbreviated name lookup fails, return original name + return interface def transform_lldp_capab(capabilities: Union[str, Any]) -> List[str]: diff --git a/napalm/base/test/getters.py b/napalm/base/test/getters.py index 0a2e47a66..cc64f551e 100644 --- a/napalm/base/test/getters.py +++ b/napalm/base/test/getters.py @@ -244,7 +244,7 @@ def test_get_lldp_neighbors_detail(self, test_case): def test_get_bgp_config(self, test_case): """Test get_bgp_config.""" get_bgp_config = self.device.get_bgp_config() - assert get_bgp_config == {} or len(get_bgp_config) > 0 + assert len(get_bgp_config) > 0 for bgp_group in get_bgp_config.values(): assert helpers.test_model(models.BPGConfigGroupDict, bgp_group) diff --git a/napalm/base/utils/string_parsers.py b/napalm/base/utils/string_parsers.py index f14f10e8b..c7dd8f376 100644 --- a/napalm/base/utils/string_parsers.py +++ b/napalm/base/utils/string_parsers.py @@ -1,7 +1,6 @@ """ Common methods to normalize a string """ import re -import struct -from typing import Union, List, Iterable, Dict, Optional, Tuple +from typing import Union, List, Iterable, Dict, Optional def convert(text: str) -> Union[str, int]: @@ -51,7 +50,7 @@ def colon_separated_string_to_dict( dictionary[line_data[0].strip()] = None else: raise Exception( - f"Something went wrong parsing the colon separated string:\n\n{line}" + "Something went wrong parsing the colo separated string {}".format(line) ) return dictionary @@ -134,14 +133,3 @@ def convert_uptime_string_seconds(uptime: str) -> int: raise Exception("Unrecognized uptime string:{}".format(uptime)) return uptime_seconds - - -def parse_fixed_width(text: str, *fields: int) -> List[Tuple[str, ...]]: - len = sum(fields) - fmtstring = " ".join(f"{fw}s" for fw in fields) - unpack = struct.Struct(fmtstring).unpack_from - - def parse(line: str) -> Tuple[str, ...]: - return tuple([str(s.decode()) for s in unpack(line.ljust(len).encode())]) - - return [parse(s) for s in text.splitlines()] diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index d5554f434..b38ae4e7d 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -23,12 +23,15 @@ import time import importlib import inspect -import ipaddress import json import socket from datetime import datetime from collections import defaultdict +from netaddr import IPAddress +from netaddr import IPNetwork + +from netaddr.core import AddrFormatError # third party libs import pyeapi @@ -37,7 +40,6 @@ # NAPALM base import napalm.base.helpers -from napalm.base.netmiko_helpers import netmiko_args from napalm.base.base import NetworkDriver from napalm.base.utils import string_parsers from napalm.base.exceptions import ( @@ -96,12 +98,9 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) Optional args: * lock_disable (True/False): force configuration lock to be disabled (for external lock management). - * force_cfg_session_invalid (True/False): force invalidation of the config session - in case of failure. * enable_password (True/False): Enable password for privilege elevation * eos_autoComplete (True/False): Allow for shortening of cli commands - * transport (string): transport, eos_transport is a fallback for compatibility. - - ssh (uses Netmiko) + * transport (string): pyeapi transport, defaults to eos_transport if set - socket - http_local - http @@ -127,47 +126,45 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.platform = "eos" self.profile = [self.platform] - self.optional_args = optional_args or {} - self.enablepwd = self.optional_args.pop("enable_password", "") - self.eos_autoComplete = self.optional_args.pop("eos_autoComplete", None) - self.fn0039_config = self.optional_args.pop("eos_fn0039_config", False) + self._process_optional_args(optional_args or {}) + def _process_optional_args(self, optional_args): # Define locking method - self.lock_disable = self.optional_args.pop("lock_disable", False) - - self.force_cfg_session_invalid = self.optional_args.pop( - "force_cfg_session_invalid", False - ) + self.lock_disable = optional_args.get("lock_disable", False) + self.enablepwd = optional_args.pop("enable_password", "") + self.eos_autoComplete = optional_args.pop("eos_autoComplete", None) # eos_transport is there for backwards compatibility, transport is the preferred method - transport = self.optional_args.get( - "transport", self.optional_args.get("eos_transport", "https") + transport = optional_args.get( + "transport", optional_args.get("eos_transport", "https") ) + self.fn0039_config = optional_args.pop("eos_fn0039_config", False) self.transport = transport + if transport == "ssh": + self.transport_class = "ssh" + init_args = ["port"] + else: + # Parse pyeapi transport class + self.transport_class = self._parse_transport(transport) + # ([1:]) to omit self + init_args = inspect.getfullargspec(self.transport_class.__init__)[0][1:] + + filter_args = ["host", "username", "password", "timeout", "lock_disable"] if transport == "ssh": - self._process_optional_args_ssh(self.optional_args) + self.netmiko_optional_args = { + k: v + for k, v in optional_args.items() + if k in init_args and k not in filter_args + } else: - self._process_optional_args_eapi(self.optional_args) - - def _process_optional_args_ssh(self, optional_args): - self.transport_class = None - self.netmiko_optional_args = netmiko_args(optional_args) - - def _process_optional_args_eapi(self, optional_args): - # Parse pyeapi transport class - self.transport_class = self._parse_transport(self.transport) - - # ([1:]) to omit self - init_args = inspect.getfullargspec(self.transport_class.__init__)[0][1:] - filter_args = ["host", "username", "password", "timeout"] - init_args.append("enforce_verification") # Not an arg for unknown reason - self.eapi_kwargs = { - k: v - for k, v in optional_args.items() - if k in init_args and k not in filter_args - } + init_args.append("enforce_verification") # Not an arg for unknown reason + self.eapi_kwargs = { + k: v + for k, v in optional_args.items() + if k in init_args and k not in filter_args + } def _parse_transport(self, transport): if inspect.isclass(transport) and issubclass(transport, EapiConnection): @@ -198,8 +195,7 @@ def open(self): """Implementation of NAPALM method open.""" if self.transport == "ssh": self.device = self._netmiko_open( - device_type="arista_eos", - netmiko_optional_args=self.netmiko_optional_args, + "arista_eos", netmiko_optional_args=self.netmiko_optional_args ) # let's try to determine if we need to use new EOS cli syntax sh_ver = self._run_commands(["show version"]) @@ -212,7 +208,7 @@ def open(self): username=self.username, password=self.password, timeout=self.timeout, - **self.eapi_kwargs, + **self.eapi_kwargs ) if self.device is None: @@ -235,9 +231,7 @@ def open(self): def close(self): """Implementation of NAPALM method close.""" self.discard_config() - if self.transport == "ssh": - self._netmiko_close() - elif hasattr(self.device.connection, "close") and callable( + if hasattr(self.device.connection, "close") and callable( self.device.connection.close ): self.device.connection.close() @@ -288,27 +282,6 @@ def _run_commands(self, commands, **kwargs): else: return self.device.run_commands(commands, **kwargs) - def _obtain_lock(self, wait_time=None): - """ - EOS internally creates config sessions when using commit-confirm. - - This can cause issues obtaining the configuration lock: - - cfg-2034--574620864-0 completed - cfg-2034--574620864-1 pending - """ - if wait_time: - start_time = time.time() - while time.time() - start_time < wait_time: - try: - self._lock() - return - except SessionLockedException: - time.sleep(1) - - # One last try - return self._lock() - def _lock(self): sess = self._run_commands(["show configuration sessions"])[0]["sessions"] if [ @@ -412,7 +385,7 @@ def _load_config(self, filename=None, config=None, replace=True): self.config_session = "napalm_{}".format(datetime.now().microsecond) if not self.lock_disable: - self._obtain_lock(wait_time=10) + self._lock() commands = [] commands.append("configure session {}".format(self.config_session)) @@ -457,7 +430,7 @@ def _load_config(self, filename=None, config=None, replace=True): return None try: - if not any(cmd == "end" for cmd in commands): + if not any(l == "end" for l in commands): commands.append("end") # exit config mode if self.eos_autoComplete is not None: self._run_commands( @@ -548,15 +521,13 @@ def confirm_commit(self): def discard_config(self): """Implementation of NAPALM method discard_config.""" if self.config_session is not None: - try: - commands = [f"configure session {self.config_session} abort"] - self._run_commands(commands, encoding="text") - except Exception: - # If discard fails, you might want to invalidate the config_session (esp. Salt) - # The config_session in EOS is used as the config lock. - if self.force_cfg_session_invalid: - self.config_session = None - raise + commands = ["configure session {}".format(self.config_session), "abort"] + if self.transport == "ssh": + # For some reason when testing with vEOS 4.26.1F this + # doesn't work with the normal wrapper. + self._run_commands(["", commands[0]]) + else: + self.device.run_commands(commands) self.config_session = None def rollback(self): @@ -685,13 +656,13 @@ def get_interfaces_counters(self): def get_bgp_neighbors(self): def get_re_group(res, key, default=None): - """Small helper to retrieve data from re match groups""" + """Small helper to retrive data from re match groups""" try: return res.group(key) except KeyError: return default - NEIGHBOR_FILTER = "bgp neighbors vrf all | include IPv[46] (Unicast|6PE):.*[0-9]+ | grep -v ' IPv[46] Unicast:/.' | remote AS |^Local AS|Desc|BGP state |remote router ID" # noqa + NEIGHBOR_FILTER = "bgp neighbors vrf all | include remote AS | remote router ID |IPv[46] (Unicast|6PE):.*[0-9]+|^Local AS|Desc|BGP state" # noqa output_summary_cmds = self._run_commands( ["show ipv6 bgp summary vrf all", "show ip bgp summary vrf all"], encoding="json", @@ -1006,7 +977,6 @@ def get_bgp_config(self, group="", neighbor=""): "local-v4-addr": "local_address", "local-v6-addr": "local_address", "local-as": "local_as", - "next-hop-self": "nhs", "description": "description", "import-policy": "import_policy", "export-policy": "export_policy", @@ -1064,7 +1034,7 @@ def default_group_dict(local_as): ) # few more default values return group_dict - def default_neighbor_dict(local_as, group_dict): + def default_neighbor_dict(local_as): neighbor_dict = {} neighbor_dict.update( { @@ -1075,13 +1045,6 @@ def default_neighbor_dict(local_as, group_dict): neighbor_dict.update( {"prefix_limit": {}, "local_as": local_as, "authentication_key": ""} ) # few more default values - neighbor_dict.update( - { - key: group_dict.get(key) - for key in _GROUP_FIELD_MAP_.values() - if key in group_dict and key in _PEER_FIELD_MAP_.values() - } - ) # copy in values from group dict if present return neighbor_dict def parse_options(options, default_value=False): @@ -1169,23 +1132,17 @@ def parse_options(options, default_value=False): # will try to parse the neighbor name # which sometimes is the IP Address of the neigbor # or the name of the BGP group - ipaddress.ip_address(group_or_neighbor) + IPAddress(group_or_neighbor) # if passes the test => it is an IP Address, thus a Neighbor! peer_address = group_or_neighbor - group_name = None + if peer_address not in bgp_neighbors: + bgp_neighbors[peer_address] = default_neighbor_dict(local_as) if options[0] == "peer-group": - group_name = options[1] + bgp_neighbors[peer_address]["__group"] = options[1] # EOS > 4.23.0 only supports the new syntax # https://www.arista.com/en/support/advisories-notices/fieldnotices/7097-field-notice-39 elif options[0] == "peer" and options[1] == "group": - group_name = options[2] - if peer_address not in bgp_neighbors: - bgp_neighbors[peer_address] = default_neighbor_dict( - local_as, bgp_config.get(group_name, {}) - ) - - if group_name: - bgp_neighbors[peer_address]["__group"] = group_name + bgp_neighbors[peer_address]["__group"] = options[2] # in the config, neighbor details are lister after # the group is specified for the neighbor: @@ -1203,7 +1160,7 @@ def parse_options(options, default_value=False): bgp_neighbors[peer_address].update( parse_options(options, default_value) ) - except ValueError: + except AddrFormatError: # exception trying to parse group name # group_or_neighbor represents the name of the group group_name = group_or_neighbor @@ -1213,8 +1170,6 @@ def parse_options(options, default_value=False): bgp_config[group_name] = default_group_dict(local_as) bgp_config[group_name].update(parse_options(options, default_value)) - bgp_config["_"] = default_group_dict(local_as) - for peer, peer_details in bgp_neighbors.items(): peer_group = peer_details.pop("__group", None) if not peer_group: @@ -1223,14 +1178,6 @@ def parse_options(options, default_value=False): bgp_config[peer_group] = default_group_dict(local_as) bgp_config[peer_group]["neighbors"][peer] = peer_details - [ - v.pop("nhs", None) for v in bgp_config.values() - ] # remove NHS from group-level dictionary - - if local_as == 0: - # BGP not running - return {} - return bgp_config def get_arp_table(self, vrf=""): @@ -1476,7 +1423,7 @@ def get_route_to(self, destination="", protocol="", longer=False): protocol = "connected" ipv = "" - if ipaddress.ip_network(destination).version == 6: + if IPNetwork(destination).version == 6: ipv = "v6" commands = [] @@ -1583,7 +1530,7 @@ def get_route_to(self, destination="", protocol="", longer=False): .get("peerEntry", {}) .get("peerAddr", "") ) - except ValueError: + except AddrFormatError: remote_address = napalm.base.helpers.ip( bgp_route_details.get("peerEntry", {}).get( "peerAddr", "" @@ -1962,7 +1909,7 @@ def _append(bgp_dict, peer_info): summary_commands.append("show ipv6 bgp summary vrf all") else: try: - peer_ver = ipaddress.ip_address(neighbor_address).version + peer_ver = IPAddress(neighbor_address).version except Exception as e: raise e @@ -2130,59 +2077,15 @@ def get_config(self, retrieve="all", full=False, sanitized=False): else: raise Exception("Wrong retrieve filter: {}".format(retrieve)) - def _show_vrf_json(self): - commands = ["show vrf"] - - vrfs = self._run_commands(commands)[0]["vrfs"] - return [ - { - "name": k, - "interfaces": [i for i in v["interfaces"]], - "route_distinguisher": v["routeDistinguisher"], - } - for k, v in vrfs.items() - ] - - def _show_vrf_text(self): + def _show_vrf(self): commands = ["show vrf"] - # This command has no JSON in EOS < 4.23 + # This command has no JSON yet raw_output = self._run_commands(commands, encoding="text")[0].get("output", "") - width_line = raw_output.splitlines()[2] # Line with dashes - fields = width_line.split(" ") - widths = [len(f) + 1 for f in fields] - widths[-1] -= 1 - - parsed_lines = string_parsers.parse_fixed_width(raw_output, *widths) - - vrfs = [] - vrf = {} - current_vrf = None - for line in parsed_lines[3:]: - line = [t.strip() for t in line] - if line[0]: - if current_vrf: - vrfs.append(vrf) - current_vrf = line[0] - vrf = { - "name": current_vrf, - "interfaces": list(), - } - if line[1]: - vrf["route_distinguisher"] = line[1] - if line[4]: - vrf["interfaces"].extend([t.strip() for t in line[4].split(",") if t]) - if current_vrf: - vrfs.append(vrf) - - return vrfs + output = napalm.base.helpers.textfsm_extractor(self, "vrf", raw_output) - def _show_vrf(self): - if self.cli_version == 2: - return self._show_vrf_json() - else: - return self._show_vrf_text() + return output def _get_vrfs(self): output = self._show_vrf() @@ -2215,26 +2118,23 @@ def get_network_instances(self, name=""): interfaces[str(line.strip())] = {} all_vrf_interfaces[str(line.strip())] = {} - vrfs[vrf["name"]] = { - "name": vrf["name"], - "type": "DEFAULT_INSTANCE" if vrf["name"] == "default" else "L3VRF", + vrfs[str(vrf["name"])] = { + "name": str(vrf["name"]), + "type": "L3VRF", "state": {"route_distinguisher": vrf["route_distinguisher"]}, "interfaces": {"interface": interfaces}, } - if "default" not in vrfs: - all_interfaces = self.get_interfaces_ip().keys() - vrfs["default"] = { - "name": "default", - "type": "DEFAULT_INSTANCE", - "state": {"route_distinguisher": ""}, - "interfaces": { - "interface": { - k: {} - for k in all_interfaces - if k not in all_vrf_interfaces.keys() - } - }, - } + all_interfaces = self.get_interfaces_ip().keys() + vrfs["default"] = { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": {"route_distinguisher": ""}, + "interfaces": { + "interface": { + k: {} for k in all_interfaces if k not in all_vrf_interfaces.keys() + } + }, + } if name: if name in vrfs: diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 5e31c49f8..59284a362 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -14,7 +14,6 @@ # the License. import copy import functools -import ipaddress import os import re import socket @@ -23,6 +22,8 @@ import uuid from collections import defaultdict +from netaddr import IPNetwork +from netaddr.core import AddrFormatError from netmiko import FileTransfer, InLineTransfer import napalm.base.constants as C @@ -36,17 +37,14 @@ CommitConfirmException, ) from napalm.base.helpers import ( + canonical_interface_name, transform_lldp_capab, textfsm_extractor, + split_interface, + abbreviated_interface_name, generate_regex_or, sanitize_configs, ) -from netaddr.core import AddrFormatError -from netutils.interface import ( - abbreviated_interface_name, - canonical_interface_name, - split_interface, -) from napalm.base.netmiko_helpers import netmiko_args # Easier to store these as constants @@ -483,10 +481,10 @@ def _commit_handler(self, cmd): # Handle special username removal pattern pattern2 = r".*all username.*confirm" patterns = rf"(?:{pattern1}|{pattern2})" - output = self.device.send_command(cmd, expect_string=patterns, read_timeout=90) + output = self.device.send_command(cmd, expect_string=patterns) loop_count = 50 new_output = output - for _ in range(loop_count): + for i in range(loop_count): if re.search(pattern2, new_output): # Send confirmation if username removal new_output = self.device.send_command_timing( @@ -987,26 +985,10 @@ def get_lldp_neighbors(self): hostname = lldp_entry["remote_system_name"] port = lldp_entry["remote_port"] # Match IOS behaviour of taking remote chassis ID - # when lacking a system name (in show lldp neighbors) - - # We can't assume remote_chassis_id or remote_port are MAC Addresses - # See IEEE 802.1AB-2005 and rfc2922, specifically PtopoChassisId + # When lacking a system name (in show lldp neighbors) if not hostname: - try: - hostname = napalm.base.helpers.mac( - lldp_entry["remote_chassis_id"] - ) - except AddrFormatError: - hostname = lldp_entry["remote_chassis_id"] - - # If port is a mac-address, normalize it. - # The MAC helper library will normalize "15" to "00:00:00:00:00:0F" - if port.count(":") == 5 or port.count("-") == 5 or port.count(".") == 2: - try: - port = napalm.base.helpers.mac(port) - except AddrFormatError: - pass - + hostname = napalm.base.helpers.mac(lldp_entry["remote_chassis_id"]) + port = napalm.base.helpers.mac(port) lldp_dict = {"port": port, "hostname": hostname} lldp[intf_name].append(lldp_dict) @@ -1463,11 +1445,6 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): bgp_config_list = napalm.base.helpers.netutils_parse_objects( "router bgp", cfg["running"] ) - - # No BGP configuration - if not bgp_config_list: - return {} - bgp_asn = napalm.base.helpers.regex_find_txt( r"router bgp (\d+)", bgp_config_list, default=0 ) @@ -1538,9 +1515,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): r" update-source (\w+)", neighbor_config ) local_as = napalm.base.helpers.regex_find_txt( - r"local-as (\d+)", - neighbor_config, - default=bgp_asn, + r"local-as (\d+)", neighbor_config, default=0 ) password = napalm.base.helpers.regex_find_txt( r"password (?:[0-9] )?([^\']+\')", neighbor_config @@ -1574,32 +1549,29 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): "route_reflector_client": route_reflector_client, } - # Do not include the no-group ("_") if a group argument is passed in - # unless group argument is "_" - if not group or group == "_": - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": bgp_asn, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("_", {}), - } - # Get the peer-group level config for each group for group_name in bgp_group_neighbors.keys(): # If a group is passed in params, only continue on that group if group: if group_name != group: continue + # Default no group if group_name == "_": + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": 0, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("_", {}), + } continue neighbor_config = napalm.base.helpers.netutils_parse_objects( group_name, bgp_config_list @@ -1621,7 +1593,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): r" description ([^\']+)\'", neighbor_config ) local_as = napalm.base.helpers.regex_find_txt( - r"local-as (\d+)", neighbor_config, default=bgp_asn + r"local-as (\d+)", neighbor_config, default=0 ) import_policy = napalm.base.helpers.regex_find_txt( r"route-map ([^\s]+) in", neighbor_config @@ -3033,7 +3005,7 @@ def _get_bgp_route_attr(self, destination, vrf, next_hop, ip_version=4): # next-hop is not known in this vrf, route leaked from # other vrf or from vpnv4 table? # get remote AS nr. from as-path if it is ebgp neighbor - # locally sourced prefix is not in routing table as a bgp route (i hope...) + # localy sourced prefix is not in routing table as a bgp route (i hope...) if search_re_dict["bgpie"]["result"] == "external": bgpras = ( search_re_dict["aspath"]["result"] @@ -3102,8 +3074,8 @@ def get_route_to(self, destination="", protocol="", longer=False): vrf = "" ip_version = None try: - ip_version = ipaddress.ip_network(destination).version - except ValueError: + ip_version = IPNetwork(destination).version + except AddrFormatError: return "Please specify a valid destination!" if ip_version == 4: # process IPv4 routing table if vrf == "": @@ -3111,8 +3083,8 @@ def get_route_to(self, destination="", protocol="", longer=False): else: vrfs = [vrf] # VRFs where IPv4 is enabled vrfs.append("default") # global VRF - ipnet_dest = ipaddress.ip_network(destination) - prefix = str(ipnet_dest.network_address) + ipnet_dest = IPNetwork(destination) + prefix = str(ipnet_dest.network) netmask = "" routes = {} if "/" in destination: diff --git a/napalm/iosxr/iosxr.py b/napalm/iosxr/iosxr.py index 383e8ae00..e8e4e5921 100644 --- a/napalm/iosxr/iosxr.py +++ b/napalm/iosxr/iosxr.py @@ -16,13 +16,15 @@ # import stdlib import re import copy -import ipaddress from collections import defaultdict import logging # import third party lib from lxml import etree as ETREE +from netaddr import IPAddress # needed for traceroute, to check IP version +from netaddr.core import AddrFormatError + from napalm.pyIOSXR import IOSXR from napalm.pyIOSXR.exceptions import ConnectError from napalm.pyIOSXR.exceptions import TimeoutError @@ -987,22 +989,6 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): default" result_tree = ETREE.fromstring(self.device.make_rpc_call(rpc_command)) - # Check if BGP is not configured. - get_tag = result_tree.find("./Get") - if get_tag is not None: - bgp_not_found = get_tag.attrib.get("ItemNotFound") - if bgp_not_found: - return {} - - bgp_asn = napalm.base.helpers.convert( - int, - napalm.base.helpers.find_txt( - result_tree, - "Get/Configuration/BGP/Instance[1]/InstanceAS/FourByteAS/Naming/AS", - ), - 0, - ) - if not group: neighbor = "" @@ -1026,9 +1012,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): int, napalm.base.helpers.find_txt(bgp_neighbor, "RemoteAS/AS_YY"), 0 ) local_as = napalm.base.helpers.convert( - int, - napalm.base.helpers.find_txt(bgp_neighbor, "LocalAS/AS_YY"), - bgp_asn, + int, napalm.base.helpers.find_txt(bgp_neighbor, "LocalAS/AS_YY"), 0 ) af_table = napalm.base.helpers.find_txt( bgp_neighbor, "NeighborAFTable/NeighborAF/Naming/AFName" @@ -1120,7 +1104,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): int, napalm.base.helpers.find_txt(bgp_group, "RemoteAS/AS_YY"), 0 ) local_as = napalm.base.helpers.convert( - int, napalm.base.helpers.find_txt(bgp_group, "LocalAS/AS_YY"), bgp_asn + int, napalm.base.helpers.find_txt(bgp_group, "LocalAS/AS_YY"), 0 ) multihop_ttl = napalm.base.helpers.convert( int, @@ -1182,22 +1166,22 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): } if group and group == group_name: break - - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": bgp_asn, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("", {}), - } + if "" in bgp_group_neighbors.keys(): + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": 0, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("", {}), + } return bgp_config @@ -1749,8 +1733,8 @@ def get_route_to(self, destination="", protocol="", longer=False): ipv = 4 try: - ipv = ipaddress.ip_address(network).version - except ValueError: + ipv = IPAddress(network).version + except AddrFormatError: logger.error("Wrong destination IP Address format supplied to get_route_to") raise TypeError("Wrong destination IP Address!") @@ -2203,8 +2187,8 @@ def traceroute( ipv = 4 try: - ipv = ipaddress.ip_address(destination).version - except ValueError: + ipv = IPAddress(destination).version + except AddrFormatError: logger.error( "Incorrect format of IP Address in traceroute \ with value provided:%s" diff --git a/napalm/iosxr_netconf/iosxr_netconf.py b/napalm/iosxr_netconf/iosxr_netconf.py index ff7a06ef8..656078880 100644 --- a/napalm/iosxr_netconf/iosxr_netconf.py +++ b/napalm/iosxr_netconf/iosxr_netconf.py @@ -22,7 +22,6 @@ import re import copy import difflib -import ipaddress import logging # import third party lib @@ -32,6 +31,8 @@ from ncclient.operations.errors import TimeoutExpiredError from lxml import etree as ETREE from lxml.etree import XMLSyntaxError +from netaddr import IPAddress # needed for traceroute, to check IP version +from netaddr.core import AddrFormatError # import NAPALM base from napalm.iosxr_netconf import constants as C @@ -1366,25 +1367,9 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): # Converts string to etree result_tree = ETREE.fromstring(rpc_reply) - data_ele = result_tree.find("./{*}data") - # If there are no children in "", then there is no BGP configured - bgp_configured = bool(len(data_ele.getchildren())) - if not bgp_configured: - return {} - if not group: neighbor = "" - bgp_asn = napalm.base.helpers.convert( - int, - self._find_txt( - result_tree, - ".//bgpc:bgp/bgpc:instance/bgpc:instance-as/bgpc:four-byte-as/bgpc:as", - default=0, - namespaces=C.NS, - ), - ) - bgp_group_neighbors = {} bgp_neighbor_xpath = ".//bgpc:bgp/bgpc:instance/bgpc:instance-as/\ bgpc:four-byte-as/bgpc:default-vrf/bgpc:bgp-entity/bgpc:neighbors/bgpc:neighbor" @@ -1446,7 +1431,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): ), 0, ) - local_as = (local_as_x * 65536 + local_as_y) or bgp_asn + local_as = local_as_x * 65536 + local_as_y af_table = self._find_txt( bgp_neighbor, "./bgpc:neighbor-afs/bgpc:neighbor-af/bgpc:af-name", @@ -1613,7 +1598,7 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): ), 0, ) - local_as = (local_as_x * 65536 + local_as_y) or bgp_asn + local_as = local_as_x * 65536 + local_as_y multihop_ttl = napalm.base.helpers.convert( int, self._find_txt( @@ -1695,22 +1680,22 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): } if group and group == group_name: break - - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": bgp_asn, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": bgp_group_neighbors.get("", {}), - } + if "" in bgp_group_neighbors.keys(): + bgp_config["_"] = { + "apply_groups": [], + "description": "", + "local_as": 0, + "type": "", + "import_policy": "", + "export_policy": "", + "local_address": "", + "multipath": False, + "multihop_ttl": 0, + "remote_as": 0, + "remove_private_as": False, + "prefix_limit": {}, + "neighbors": bgp_group_neighbors.get("", {}), + } return bgp_config @@ -2496,8 +2481,8 @@ def get_route_to(self, destination="", protocol="", longer=False): ipv = 4 try: - ipv = ipaddress.ip_address(network).version - except ValueError: + ipv = IPAddress(network).version + except AddrFormatError: logger.error("Wrong destination IP Address format supplied to get_route_to") raise TypeError("Wrong destination IP Address!") @@ -2967,8 +2952,8 @@ def traceroute( ipv = 4 try: - ipv = ipaddress.ip_address(destination).version - except ValueError: + ipv = IPAddress(destination).version + except AddrFormatError: logger.error( "Incorrect format of IP Address in traceroute \ with value provided:%s" @@ -3154,7 +3139,7 @@ def get_config(self, retrieve="all", full=False, sanitized=False): if config[datastore] != "": if encoding == "cli": cli_tree = ETREE.XML(config[datastore], parser=parser)[0] - if len(cli_tree): + if cli_tree: config[datastore] = cli_tree[0].text.strip() else: config[datastore] = "" diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index 74b6e5efe..d274dac91 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -176,10 +176,10 @@ def _unlock(self): def _rpc(self, get, child=None, **kwargs): """ - This allows you to construct an arbitrary RPC call to retrieve common stuff. For example: + This allows you to construct an arbitrary RPC call to retreive common stuff. For example: Configuration: get: "" Interface information: get: "" - A particular interface information: + A particular interfacece information: get: "" child: "ge-0/0/0" """ @@ -1169,7 +1169,7 @@ def update_dict(d, u): # for deep dictionary update def build_prefix_limit(**args): """ - Transform the elements of a dictionary into nested dictionaries. + Transform the lements of a dictionary into nested dictionaries. Example: { @@ -1250,40 +1250,13 @@ def build_prefix_limit(**args): bgp_config = {} - routing_options = junos_views.junos_routing_config_table(self.device) - routing_options.get(options=self.junos_config_options) - - bgp_asn_obj = routing_options.xml.find( - "./routing-options/autonomous-system/as-number" - ) - system_bgp_asn = int(bgp_asn_obj.text) if bgp_asn_obj is not None else 0 - - # No BGP peer-group i.e. "_" key is a special case. - if group and group != "_": + if group: bgp = junos_views.junos_bgp_config_group_table(self.device) bgp.get(group=group, options=self.junos_config_options) else: bgp = junos_views.junos_bgp_config_table(self.device) bgp.get(options=self.junos_config_options) neighbor = "" # if no group is set, no neighbor should be set either - - # Only set no peer-group if BGP is actually configured. - if bgp.items() or system_bgp_asn: - bgp_config["_"] = { - "apply_groups": [], - "description": "", - "local_as": system_bgp_asn, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": False, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": False, - "prefix_limit": {}, - "neighbors": {}, - } bgp_items = bgp.items() if neighbor: @@ -1310,17 +1283,13 @@ def build_prefix_limit(**args): for field, datatype in _GROUP_FIELDS_DATATYPE_MAP_.items() if "_prefix_limit" not in field } - - # Always overwrite with the system local_as (this will either be - # valid or will be zero i.e. the same as the default value). - bgp_config[bgp_group_name]["local_as"] = system_bgp_asn - - for key, value in bgp_group_details: - if "_prefix_limit" in key or value is None: + for elem in bgp_group_details: + if not ("_prefix_limit" not in elem[0] and elem[1] is not None): continue - datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(key) + datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0]) default = _DATATYPE_DEFAULT_.get(datatype) - + key = elem[0] + value = elem[1] if key in ["export_policy", "import_policy"]: if isinstance(value, list): value = " ".join(value) @@ -1328,10 +1297,6 @@ def build_prefix_limit(**args): value = napalm.base.helpers.convert( napalm.base.helpers.ip, value, value ) - if key == "apply_groups": - # Ensure apply_groups value is wrapped in a list - if isinstance(value, str): - value = [value] if key == "neighbors": bgp_group_peers = value continue @@ -1339,15 +1304,15 @@ def build_prefix_limit(**args): {key: napalm.base.helpers.convert(datatype, value, default)} ) prefix_limit_fields = {} - for key, value in bgp_group_details: - if "_prefix_limit" in key and value is not None: - datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(key) + for elem in bgp_group_details: + if "_prefix_limit" in elem[0] and elem[1] is not None: + datatype = _GROUP_FIELDS_DATATYPE_MAP_.get(elem[0]) default = _DATATYPE_DEFAULT_.get(datatype) prefix_limit_fields.update( { - key.replace( + elem[0].replace( "_prefix_limit", "" - ): napalm.base.helpers.convert(datatype, value, default) + ): napalm.base.helpers.convert(datatype, elem[1], default) } ) bgp_config[bgp_group_name]["prefix_limit"] = build_prefix_limit( @@ -1361,31 +1326,23 @@ def build_prefix_limit(**args): bgp_config[bgp_group_name]["multihop_ttl"] = 64 bgp_config[bgp_group_name]["neighbors"] = {} - bgp_group_remote_as = bgp_config[bgp_group_name]["remote_as"] for bgp_group_neighbor in bgp_group_peers.items(): bgp_peer_address = napalm.base.helpers.ip(bgp_group_neighbor[0]) if neighbor and bgp_peer_address != neighbor: continue # if filters applied, jump over all other neighbors bgp_group_details = bgp_group_neighbor[1] - - # Set defaults for this BGP peer bgp_peer_details = { field: _DATATYPE_DEFAULT_.get(datatype) for field, datatype in _PEER_FIELDS_DATATYPE_MAP_.items() if "_prefix_limit" not in field } - - # Always overwrite with the system local_as (this will either be - # valid or will be zero i.e. the same as the default value). - bgp_peer_details["local_as"] = system_bgp_asn - # Always set the default remote-as as the Peer-Group remote-as - bgp_peer_details["remote_as"] = bgp_group_remote_as - - for key, value in bgp_group_details: - if "_prefix_limit" in key or value is None: + for elem in bgp_group_details: + if not ("_prefix_limit" not in elem[0] and elem[1] is not None): continue - datatype = _PEER_FIELDS_DATATYPE_MAP_.get(key) + datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0]) default = _DATATYPE_DEFAULT_.get(datatype) + key = elem[0] + value = elem[1] if key in ["export_policy"]: # next-hop self is applied on export IBGP sessions bgp_peer_details["nhs"] = _check_nhs(value, nhs_policies) @@ -1413,15 +1370,17 @@ def build_prefix_limit(**args): if "cluster" in bgp_config[bgp_group_name].keys(): bgp_peer_details["route_reflector_client"] = True prefix_limit_fields = {} - for key, value in bgp_group_details: - if "_prefix_limit" in key and value is not None: - datatype = _PEER_FIELDS_DATATYPE_MAP_.get(key) + for elem in bgp_group_details: + if "_prefix_limit" in elem[0] and elem[1] is not None: + datatype = _PEER_FIELDS_DATATYPE_MAP_.get(elem[0]) default = _DATATYPE_DEFAULT_.get(datatype) prefix_limit_fields.update( { - key.replace( + elem[0].replace( "_prefix_limit", "" - ): napalm.base.helpers.convert(datatype, value, default) + ): napalm.base.helpers.convert( + datatype, elem[1], default + ) } ) bgp_peer_details["prefix_limit"] = build_prefix_limit( @@ -1865,7 +1824,7 @@ def get_route_to(self, destination="", protocol="", longer=False): try: routes_table.get(**rt_kargs) except RpcTimeoutError: - # on devices with millions of routes + # on devices with milions of routes # in case the destination is too generic (e.g.: 10/8) # will take very very long to determine all routes and # moreover will return a huge list diff --git a/napalm/junos/utils/junos_views.yml b/napalm/junos/utils/junos_views.yml index 3fd60b1f4..5d81ae2fc 100644 --- a/napalm/junos/utils/junos_views.yml +++ b/napalm/junos/utils/junos_views.yml @@ -402,15 +402,6 @@ junos_bgp_config_peers_view: inet6_flow_teardown_timeout_prefix_limit: {family/inet6/flow/prefix-limit/teardown/idle-timeout/timeout: int} inet6_flow_novalidate_prefix_limit: {family/inet6/flow/prefix-limit/no-validate: unicode} -junos_routing_config_table: - get: "routing-options/autonomous-system" - view: junos_routing_config_view - -junos_routing_config_view: - fields: - local_system_as: autonomous-system - - #### #### BGP Neighbors and Routing Tables Stats #### diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index 9668569ff..d857832e4 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -13,7 +13,6 @@ # License for the specific language governing permissions and limitations under # the License. -import ipaddress import json import os import re @@ -43,10 +42,11 @@ DefaultDict, ) +from netaddr import IPAddress +from netaddr.core import AddrFormatError from netmiko import file_transfer from requests.exceptions import ConnectionError from netutils.config.compliance import diff_network_config -from netutils.interface import canonical_interface_name import napalm.base.constants as c @@ -233,7 +233,7 @@ def _get_merge_diff(self) -> str: interface loopback0 ip address 10.1.4.5/32 """ - running_config = self.get_config(retrieve="running", full=True)["running"] + running_config = self.get_config(retrieve="running")["running"] return diff_network_config(self.merge_candidate, running_config, "cisco_nxos") def _get_diff(self) -> str: @@ -356,8 +356,8 @@ def ping( version = "" try: - version = "6" if ipaddress.ip_address(destination).version == 6 else "" - except ValueError: + version = "6" if IPAddress(destination).version == 6 else "" + except AddrFormatError: # Allow use of DNS names pass @@ -470,8 +470,8 @@ def traceroute( version = "" try: - version = "6" if ipaddress.ip_address(destination).version == 6 else "" - except ValueError: + version = "6" if IPAddress(destination).version == 6 else "" + except AddrFormatError: # Allow use of DNS names pass @@ -683,7 +683,7 @@ def get_lldp_neighbors_detail( lldp_entry["remote_system_enable_capab"] ) # Turn the interfaces into their long version - local_intf = canonical_interface_name(local_intf) + local_intf = napalm.base.helpers.canonical_interface_name(local_intf) lldp.setdefault(local_intf, []) lldp[local_intf].append(lldp_entry) # type: ignore @@ -739,9 +739,13 @@ def _parse_vlan_ports(self, vlan_s: Union[str, List]) -> List: find = re.findall(find_regexp, vls.strip()) if find: for i in range(int(find[0][1]), int(find[0][2]) + 1): - vlans.append(canonical_interface_name(find[0][0] + str(i))) + vlans.append( + napalm.base.helpers.canonical_interface_name( + find[0][0] + str(i) + ) + ) else: - vlans.append(canonical_interface_name(vls.strip())) + vlans.append(napalm.base.helpers.canonical_interface_name(vls.strip())) return vlans @abstractmethod diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index bdb01f5a9..01147d0e6 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -15,13 +15,12 @@ # import stdlib from builtins import super -import ipaddress import re import socket -from collections import defaultdict -# import external lib -from netutils.interface import canonical_interface_name +# import third party lib +from netaddr import IPAddress, IPNetwork +from netaddr.core import AddrFormatError # import NAPALM Base from napalm.base import helpers @@ -119,7 +118,7 @@ def parse_intf_section(interface): else: # More standard is up, next line admin state is lines match = re.search(re_intf_name_state, interface) - intf_name = canonical_interface_name(match.group("intf_name")) + intf_name = helpers.canonical_interface_name(match.group("intf_name")) intf_state = match.group("intf_state").strip() is_up = True if intf_state == "up" else False @@ -457,15 +456,21 @@ def _send_command(self, command, raw_text=False, cmd_verify=True): """ return self.device.send_command(command, cmd_verify=cmd_verify) - def _send_command_list(self, commands, expect_string=None, **kwargs): - """Send a list of commands using Netmiko""" - return self.device.send_multiline( - commands, expect_string=expect_string, **kwargs - ) + def _send_command_list(self, commands, expect_string=None): + """Wrapper for Netmiko's send_command method (for list of commands.""" + output = "" + for command in commands: + output += self.device.send_command( + command, + strip_prompt=False, + strip_command=False, + expect_string=expect_string, + ) + return output def _send_config(self, commands): if isinstance(commands, str): - commands = [command for command in commands.splitlines() if command] + commands = (command for command in commands.splitlines() if command) return self.device.send_config_set(commands) @staticmethod @@ -519,6 +524,7 @@ def is_alive(self): return {"is_alive": self.device.remote_conn.transport.is_active()} def _copy_run_start(self): + output = self.device.save_config() if "complete" in output.lower(): return True @@ -527,6 +533,7 @@ def _copy_run_start(self): raise CommandErrorException(msg) def _load_cfg_from_checkpoint(self): + commands = [ "terminal dont-ask", "rollback running-config file {}".format(self.candidate_cfg), @@ -534,9 +541,7 @@ def _load_cfg_from_checkpoint(self): ] try: - rollback_result = self._send_command_list( - commands, expect_string=r"[#>]", read_timeout=90 - ) + rollback_result = self._send_command_list(commands, expect_string=r"[#>]") finally: self.changed = True msg = rollback_result @@ -550,9 +555,7 @@ def rollback(self): "rollback running-config file {}".format(self.rollback_cfg), "no terminal dont-ask", ] - result = self._send_command_list( - commands, expect_string=r"[#>]", read_timeout=90 - ) + result = self._send_command_list(commands, expect_string=r"[#>]") if "completed" not in result.lower(): raise ReplaceConfigException(result) # If hostname changes ensure Netmiko state is updated properly @@ -656,7 +659,7 @@ def get_facts(self): continue interface = line.split()[0] # Return canonical interface name - interface_list.append(canonical_interface_name(interface)) + interface_list.append(helpers.canonical_interface_name(interface)) return { "uptime": float(uptime), @@ -796,61 +799,6 @@ def cli(self, commands, encoding="text"): cli_output[str(command)] = output return cli_output - def get_network_instances(self, name=""): - """ - get_network_instances implementation for NX-OS - """ - - # command 'show vrf detail | json' returns all VRFs with detailed information in JSON format - # format: list of dictionaries with keys such as 'vrf_name' and 'rd' - vrf_table_raw = self._get_command_table( - "show vrf detail | json", "TABLE_vrf", "ROW_vrf" - ) - - # command 'show vrf interface' returns all interfaces including their assigned VRF - # format: list of dictionaries with keys 'if_name', 'vrf_name', 'vrf_id' and 'soo' - intf_table_raw = self._get_command_table( - "show vrf interface | json", "TABLE_if", "ROW_if" - ) - - # create a dictionary with key = 'vrf_name' and value = list of interfaces - vrf_intfs = defaultdict(list) - for intf in intf_table_raw: - vrf_intfs[intf["vrf_name"]].append(str(intf["if_name"])) - - vrfs = {} - for vrf in vrf_table_raw: - vrf_name = str(vrf.get("vrf_name")) - vrfs[vrf_name] = {} - vrfs[vrf_name]["name"] = vrf_name - - # differentiate between VRF type 'DEFAULT_INSTANCE' and 'L3VRF' - if vrf_name == "default": - vrfs[vrf_name]["type"] = "DEFAULT_INSTANCE" - else: - vrfs[vrf_name]["type"] = "L3VRF" - - vrfs[vrf_name]["state"] = {"route_distinguisher": str(vrf.get("rd"))} - - # convert list of interfaces (vrf_intfs[vrf_name]) to expected format - # format = dict with key = interface name and empty values - vrfs[vrf_name]["interfaces"] = {} - vrfs[vrf_name]["interfaces"]["interface"] = dict.fromkeys( - vrf_intfs[vrf_name], {} - ) - - # if name of a specific VRF was passed as an argument - # only return results for this particular VRF - - if name: - if name in vrfs.keys(): - return {str(name): vrfs[name]} - else: - return {} - # else return results for all VRFs - else: - return vrfs - def get_environment(self): """ Get environment facts. @@ -1005,7 +953,7 @@ def _get_ntp_entity(self, peer_type): # Skip first two lines and last line of command output if line == "" or "-----" in line or "Peer IP Address" in line: continue - elif not ipaddress.ip_address(len(line.split()[0])).is_multicast: + elif IPAddress(len(line.split()[0])).is_unicast: peer_addr = line.split()[0] ntp_entities[peer_addr] = {} else: @@ -1191,7 +1139,7 @@ def process_mac_fields(vlan, mac, mac_type, interface): active = False return { "mac": helpers.mac(mac), - "interface": canonical_interface_name(interface), + "interface": helpers.canonical_interface_name(interface), "vlan": int(vlan), "static": static, "active": active, @@ -1210,6 +1158,7 @@ def process_mac_fields(vlan, mac, mac_type, interface): output = re.sub(r"vPC Peer-Link", "vPC-Peer-Link", output, flags=re.M) for line in output.splitlines(): + # Every 500 Mac's Legend is reprinted, regardless of terminal length if re.search(r"^Legend", line): continue @@ -1391,8 +1340,8 @@ def get_route_to(self, destination="", protocol="", longer=False): ip_version = None try: - ip_version = ipaddress.ip_network(destination).version - except ValueError: + ip_version = IPNetwork(destination).version + except AddrFormatError: return "Please specify a valid destination!" if ip_version == 4: # process IPv4 routing table routes = {} @@ -1460,7 +1409,7 @@ def get_route_to(self, destination="", protocol="", longer=False): # routing protocol process number, for future use # nh_source_proc_nr = viastr.group('procnr) if nh_int: - nh_int_canon = canonical_interface_name(nh_int) + nh_int_canon = helpers.canonical_interface_name(nh_int) else: nh_int_canon = "" route_entry = { diff --git a/napalm/pyIOSXR/iosxr.py b/napalm/pyIOSXR/iosxr.py index a1ddc2215..694a73227 100644 --- a/napalm/pyIOSXR/iosxr.py +++ b/napalm/pyIOSXR/iosxr.py @@ -690,7 +690,7 @@ def commit_replace_config(self, label=None, comment=None, confirmed=None): def discard_config(self): """ - Clear uncommitted changes in the current session. + Clear uncommited changes in the current session. Clear previously loaded configuration on the device without committing it. """ diff --git a/requirements-dev.txt b/requirements-dev.txt index 62923790b..b1197ced2 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,17 +1,17 @@ black==22.6.0 coveralls==3.3.1 -ddt==1.6.0 -flake8-import-order==0.18.2 -pytest==7.3.1 -pytest-cov==4.0.0 -pytest-json-report==1.5.0 -pyflakes==3.0.1 -pylama==8.4.1 -mock==5.0.2 -mypy==0.982 -types-PyYAML==6.0.12.10 -types-requests==2.28.11.17 -types-six==1.16.21.8 -types-setuptools==67.8.0.0 -ttp==0.9.4 -ttp_templates==0.3.5 +ddt==1.5.0 +flake8-import-order==0.18.1 +pytest==7.1.2 +pytest-cov==3.0.0 +pytest-json==0.4.0 +pylama==8.2.1 +mock==4.0.3 +tox==3.25.1 +mypy==0.961 +types-requests==2.28.0 +types-six==1.16.17 +types-setuptools==57.4.18 +types-PyYAML==6.0.9 +ttp==0.9.0 +ttp_templates==0.3.0 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 57ecd72eb..18530cdd5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,12 +3,12 @@ cffi>=1.11.3 paramiko>=2.6.0 requests>=2.7.0 future -textfsm +textfsm<=1.1.2 jinja2 netaddr pyYAML pyeapi>=0.8.2 -netmiko>=4.1.0 +netmiko>=4.0.0 junos-eznc>=2.6.3 scp lxml>=4.3.0 diff --git a/setup.cfg b/setup.cfg index 871c4c939..272f56d7f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,11 +5,11 @@ universal = 1 license_file = LICENSE [pylama] -linters = mccabe,pycodestyle,pyflakes +linters = mccabe,pep8,pyflakes ignore = D203,C901,E203 skip = .tox/*,.env/*,.venv/* -[pylama:pycodestyle] +[pylama:pep8] max_line_length = 100 [tool:pytest] diff --git a/setup.py b/setup.py index 0a3bbe374..9eb0865d0 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="napalm", - version="4.1.0", + version="4.0.0", packages=find_packages(exclude=("test*",)), test_suite="test_base", author="David Barroso, Kirk Byers, Mircea Ulinic", diff --git a/test/base/test_helpers.py b/test/base/test_helpers.py index cd2226877..f6ca9717b 100644 --- a/test/base/test_helpers.py +++ b/test/base/test_helpers.py @@ -57,10 +57,7 @@ from napalm.base.netmiko_helpers import netmiko_args import napalm.base.exceptions from napalm.base.base import NetworkDriver -from napalm.base.utils.string_parsers import ( - convert_uptime_string_seconds, - parse_fixed_width, -) +from napalm.base.utils.string_parsers import convert_uptime_string_seconds class TestBaseHelpers(unittest.TestCase): @@ -84,7 +81,7 @@ def test_load_template(self): custom path * check if can load correct template from custom path * check if template passed as string can be loaded - * check that the search path setup by MRO is correct when loading an incorrect template + * check that the search path setup by MRO is correct when loading an incorrecet template """ self.assertTrue(HAS_JINJA) # firstly check if jinja2 is installed @@ -378,8 +375,10 @@ def test_ip(self): * check if IPv6 address returned as expected """ - # test that raises ValueError when wrong format - self.assertRaises(ValueError, napalm.base.helpers.ip, "fake") + self.assertTrue(HAS_NETADDR) + + # test that raises AddrFormatError when wrong format + self.assertRaises(AddrFormatError, napalm.base.helpers.ip, "fake") self.assertRaises( ValueError, napalm.base.helpers.ip, @@ -496,6 +495,87 @@ def test_convert_uptime_string_seconds(self): self.assertEqual(convert_uptime_string_seconds("95w2d10h58m"), 57668280) self.assertEqual(convert_uptime_string_seconds("1h5m"), 3900) + def test_canonical_interface_name(self): + """Test the canonical_interface_name helper function.""" + self.assertEqual( + napalm.base.helpers.canonical_interface_name("Fa0/1"), "FastEthernet0/1" + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name("FastEthernet0/1"), + "FastEthernet0/1", + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name("TenGig1/1/1.5"), + "TenGigabitEthernet1/1/1.5", + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name("Gi1/2"), "GigabitEthernet1/2" + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name("HundredGigE105/1/1"), + "HundredGigabitEthernet105/1/1", + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name("Lo0"), "Loopback0" + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name("lo0"), "Loopback0" + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name("no_match0/1"), "no_match0/1" + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name( + "lo10", addl_name_map={"lo": "something_custom"} + ), + "something_custom10", + ) + self.assertEqual( + napalm.base.helpers.canonical_interface_name( + "uniq0/1/1", addl_name_map={"uniq": "something_custom"} + ), + "something_custom0/1/1", + ) + + def test_abbreviated_interface_name(self): + """Test the abbreviated_interface_name helper function.""" + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name("Fa0/1"), "Fa0/1" + ) + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name("FastEthernet0/1"), "Fa0/1" + ) + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name("TenGig1/1/1.5"), "Te1/1/1.5" + ) + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name("Gi1/2"), "Gi1/2" + ) + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name("HundredGigE105/1/1"), + "Hu105/1/1", + ) + self.assertEqual(napalm.base.helpers.abbreviated_interface_name("Lo0"), "Lo0") + self.assertEqual(napalm.base.helpers.abbreviated_interface_name("lo0"), "Lo0") + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name("something_custom0/1"), + "something_custom0/1", + ) + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name( + "loop10", addl_name_map={"loop": "Loopback"} + ), + "Lo10", + ) + self.assertEqual( + napalm.base.helpers.abbreviated_interface_name( + "loop10", + addl_name_map={"loop": "Loopback"}, + addl_reverse_map={"Loopback": "lo"}, + ), + "lo10", + ) + def test_netmiko_arguments(self): """Test the netmiko argument processing.""" self.assertEqual(netmiko_args(optional_args={}), {}) @@ -675,37 +755,6 @@ def test_ttp_parse(self): ) self.assertEqual(result, _EXPECTED_RESULT) - def test_parse_fixed_width(self): - _TEST_STRING = """ VRF RD Protocols State Interfaces ----------------- --------------- --------------- ------------------- --------------------------- -123456789012345671234567890123456123456789012345612345678901234567890123456789012345678901234567 -""" # noqa: E501 - _EXPECTED_RESULT = [ - ( - " VRF ", - " RD ", - " Protocols ", - " State ", - "Interfaces ", - ), - ( - "---------------- ", - "--------------- ", - "--------------- ", - "------------------- ", - "---------------------------", - ), - ( - "12345678901234567", - "1234567890123456", - "1234567890123456", - "12345678901234567890", - "123456789012345678901234567", - ), - ] - result = parse_fixed_width(_TEST_STRING, 17, 16, 16, 20, 27) - self.assertEqual(result, _EXPECTED_RESULT) - class FakeNetworkDriver(NetworkDriver): def __init__(self): diff --git a/test/eos/conftest.py b/test/eos/conftest.py index aff8e78a1..7cf515f31 100644 --- a/test/eos/conftest.py +++ b/test/eos/conftest.py @@ -37,19 +37,6 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.patched_attrs = ["device"] self.device = FakeEOSDevice() - self._cli_version = 1 - - @property - def cli_version(self): - try: - full_path = self.device.find_file("cli_version.txt") - except IOError: - return self._cli_version - return int(self.device.read_txt_file(full_path)) - - @cli_version.setter - def cli_version(self, value): - self._cli_version = value class FakeEOSDevice(BaseTestDouble): diff --git a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json index 1dbf0d43b..8354f24ba 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue1504_alt_peer_group_syntax/expected_result.json @@ -1,19 +1,4 @@ { - "_": { - "type": "", - "multipath": false, - "apply_groups": [], - "remove_private_as": false, - "multihop_ttl": 0, - "remote_as": 0, - "local_address": "", - "local_as": 64496, - "description": "", - "import_policy": "", - "export_policy": "", - "prefix_limit": {}, - "neighbors": {} - }, "IPv6-PEERS-GROUP-NAME": { "type": "", "multipath": false, @@ -35,8 +20,8 @@ "local_as": 64496, "nhs": false, "route_reflector_client": false, - "import_policy": "reject-all", - "export_policy": "reject-all", + "import_policy": "", + "export_policy": "", "authentication_key": "", "prefix_limit": {} }, @@ -47,8 +32,8 @@ "local_as": 64496, "nhs": false, "route_reflector_client": false, - "import_policy": "reject-all", - "export_policy": "reject-all", + "import_policy": "", + "export_policy": "", "authentication_key": "", "prefix_limit": {} } diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json index 1f885538c..84f8c3bd8 100644 --- a/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/issue_1113_dot_asn/expected_result.json @@ -1,19 +1,4 @@ { - "_": { - "type": "", - "multipath": false, - "apply_groups": [], - "remove_private_as": false, - "multihop_ttl": 0, - "remote_as": 0, - "local_address": "", - "local_as": 4266524237, - "description": "", - "import_policy": "", - "export_policy": "", - "prefix_limit": {}, - "neighbors": {} - }, "IPv4-PEERS-GROUP-NAME": { "type": "", "multipath": false, @@ -35,8 +20,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "reject-all", - "export_policy": "4-public-peer-anycast-out", + "import_policy": "", + "export_policy": "", "authentication_key": "", "prefix_limit": {} }, @@ -47,8 +32,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "reject-all", - "export_policy": "4-public-peer-anycast-out", + "import_policy": "", + "export_policy": "", "authentication_key": "", "prefix_limit": {} } @@ -75,8 +60,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "reject-all", - "export_policy": "reject-all", + "import_policy": "", + "export_policy": "", "authentication_key": "", "prefix_limit": {} }, @@ -87,8 +72,8 @@ "local_as": 4266524237, "nhs": false, "route_reflector_client": false, - "import_policy": "reject-all", - "export_policy": "reject-all", + "import_policy": "", + "export_policy": "", "authentication_key": "", "prefix_limit": {} } diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json deleted file mode 100644 index 4f2f36e4e..000000000 --- a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/expected_result.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "_": { - "type": "", - "multipath": false, - "apply_groups": [], - "remove_private_as": false, - "multihop_ttl": 0, - "remote_as": 0, - "local_address": "", - "local_as": 65534, - "description": "", - "import_policy": "", - "export_policy": "", - "prefix_limit": {}, - "neighbors": {} - }, - "FOO-GROUP": { - "local_address": "", - "description": "FOO", - "type": "", - "local_as": 65534, - "apply_groups": [], - "multihop_ttl": 0, - "remove_private_as": false, - "remote_as": 65534, - "import_policy": "", - "export_policy": "", - "neighbors": { - "192.0.2.2": { - "local_address": "", - "authentication_key": "", - "description": "FOO", - "nhs": false, - "local_as": 65534, - "route_reflector_client": false, - "remote_as": 65534, - "import_policy": "", - "export_policy": "", - "prefix_limit": {} - }, - "192.0.2.3": { - "local_address": "", - "authentication_key": "", - "description": "SECOND-PEER", - "nhs": true, - "local_as": 65534, - "route_reflector_client": false, - "remote_as": 65534, - "import_policy": "", - "export_policy": "", - "prefix_limit": {} - } - }, - "prefix_limit": {}, - "multipath": false - } -} diff --git a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text b/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text deleted file mode 100644 index 0db6d0c27..000000000 --- a/test/eos/mocked_data/test_get_bgp_config/issue_905_group_copydown/show_running_config___section_router_bgp.text +++ /dev/null @@ -1,11 +0,0 @@ -router bgp 65534 - router-id 192.0.2.1 - neighbor FOO-GROUP peer group - neighbor FOO-GROUP next-hop-self - neighbor FOO-GROUP description FOO - neighbor FOO-GROUP remote-as 65534 - neighbor 192.0.2.2 peer group FOO-GROUP - no neighbor 192.0.2.2 next-hop-self - neighbor 192.0.2.3 peer group FOO-GROUP - neighbor 192.0.2.3 description SECOND-PEER -! diff --git a/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json deleted file mode 100644 index 0967ef424..000000000 --- a/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json index bdf8f2657..de52578fe 100644 --- a/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/eos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,97 +1 @@ -{ - "_": { - "type": "", - "multipath": false, - "apply_groups": [], - "remove_private_as": false, - "multihop_ttl": 0, - "remote_as": 0, - "local_address": "", - "local_as": 13335, - "description": "", - "import_policy": "", - "export_policy": "", - "prefix_limit": {}, - "neighbors": {} - }, - "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": "reject-all", - "export_policy": "4-public-peer-anycast-out", - "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": "reject-all", - "export_policy": "4-public-peer-anycast-out", - "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": "reject-all", - "export_policy": "reject-all", - "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": "reject-all", - "export_policy": "reject-all", - "prefix_limit": {} - } - }, - "prefix_limit": {}, - "multipath": false - } -} +{"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/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/eos/mocked_data/test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_config/no_bgp_config/show_running_config___section_router_bgp.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json deleted file mode 100644 index ee7922393..000000000 --- a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/expected_result.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "global": { - "peers": { - "fe80::a8c1:abff:fe0b:7b5f%Et5": { - "is_up": true, - "is_enabled": true, - "uptime": "...", - "description": "", - "remote_as": 4259840008, - "remote_id": "172.18.0.8", - "local_as": 4259906562, - "address_family": { - "ipv4": { - "sent_prefixes": 9, - "received_prefixes": 2, - "accepted_prefixes": -1 - }, - "ipv6": { - "sent_prefixes": 9, - "received_prefixes": 2, - "accepted_prefixes": -1 - } - } - }, - "fe80::a8c1:abff:fe27:69e9%Et2": { - "is_up": true, - "is_enabled": true, - "uptime": "...", - "description": "", - "remote_as": 4259973121, - "remote_id": "172.18.8.1", - "local_as": 4259906562, - "address_family": { - "ipv4": { - "sent_prefixes": 9, - "received_prefixes": 5, - "accepted_prefixes": -1 - }, - "ipv6": { - "sent_prefixes": 9, - "received_prefixes": 5, - "accepted_prefixes": -1 - } - } - }, - "fe80::a8c1:abff:fe35:51d9%Et1": { - "is_up": true, - "is_enabled": true, - "uptime": "...", - "description": "", - "remote_as": 4259973120, - "remote_id": "172.18.8.0", - "local_as": 4259906562, - "address_family": { - "ipv4": { - "sent_prefixes": 6, - "received_prefixes": 5, - "accepted_prefixes": -1 - }, - "ipv6": { - "sent_prefixes": 6, - "received_prefixes": 5, - "accepted_prefixes": -1 - } - } - }, - "fe80::a8c1:abff:fe5d:9706%Et4": { - "is_up": true, - "is_enabled": true, - "uptime": "...", - "description": "", - "remote_as": 4259840007, - "remote_id": "172.18.0.7", - "local_as": 4259906562, - "address_family": { - "ipv4": { - "sent_prefixes": 9, - "received_prefixes": 2, - "accepted_prefixes": -1 - }, - "ipv6": { - "sent_prefixes": 9, - "received_prefixes": 2, - "accepted_prefixes": -1 - } - } - }, - "fe80::a8c1:abff:fe95:fa49%Et3": { - "is_up": true, - "is_enabled": true, - "uptime": "...", - "description": "", - "remote_as": 4259840005, - "remote_id": "172.18.0.5", - "local_as": 4259906562, - "address_family": { - "ipv4": { - "sent_prefixes": 9, - "received_prefixes": 2, - "accepted_prefixes": -1 - }, - "ipv6": { - "sent_prefixes": 9, - "received_prefixes": 2, - "accepted_prefixes": -1 - } - } - } - }, - "router_id": "172.18.4.2" - } -} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json deleted file mode 100644 index 0155ea42a..000000000 --- a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ip_bgp_summary_vrf_all.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "vrfs": { - "default": { - "routerId": "172.18.4.2", - "peers": { - "fe80::a8c1:abff:fe0b:7b5f%Et5": { - "msgSent": 239229, - "inMsgQueue": 0, - "prefixReceived": 2, - "upDownTime": 1664912777.128896, - "version": 4, - "prefixAccepted": 2, - "msgReceived": 203694, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65000.8" - }, - "fe80::a8c1:abff:fe27:69e9%Et2": { - "msgSent": 11997, - "inMsgQueue": 0, - "prefixReceived": 5, - "upDownTime": 1664912780.356704, - "version": 4, - "prefixAccepted": 5, - "msgReceived": 11972, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65002.2049" - }, - "fe80::a8c1:abff:fe35:51d9%Et1": { - "msgSent": 11984, - "inMsgQueue": 0, - "prefixReceived": 5, - "upDownTime": 1664912783.670673, - "version": 4, - "prefixAccepted": 5, - "msgReceived": 11979, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65002.2048" - }, - "fe80::a8c1:abff:fe5d:9706%Et4": { - "msgSent": 239170, - "inMsgQueue": 0, - "prefixReceived": 2, - "upDownTime": 1664912777.50903, - "version": 4, - "prefixAccepted": 2, - "msgReceived": 203718, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65000.7" - }, - "fe80::a8c1:abff:fe95:fa49%Et3": { - "msgSent": 239116, - "inMsgQueue": 0, - "prefixReceived": 2, - "upDownTime": 1664912777.604791, - "version": 4, - "prefixAccepted": 2, - "msgReceived": 203718, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65000.5" - } - }, - "vrf": "default", - "asn": "65001.1026" - } - } -} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text deleted file mode 100644 index f1d5ed371..000000000 --- a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text +++ /dev/null @@ -1,30 +0,0 @@ -BGP neighbor is fe80::a8c1:abff:fe0b:7b5f%Et5, remote AS 65000.8, external link - BGP version 4, remote router ID 172.18.0.8, VRF default - BGP state is Established, up for 7d01h - IPv4 Unicast: 9 2 1 0 - IPv6 Unicast: 9 2 1 0 -Local AS is 65001.1026, local router ID 172.18.4.2 -BGP neighbor is fe80::a8c1:abff:fe27:69e9%Et2, remote AS 65002.2049, external link - BGP version 4, remote router ID 172.18.8.1, VRF default - BGP state is Established, up for 7d01h - IPv4 Unicast: 9 5 1 0 - IPv6 Unicast: 9 5 1 0 -Local AS is 65001.1026, local router ID 172.18.4.2 -BGP neighbor is fe80::a8c1:abff:fe35:51d9%Et1, remote AS 65002.2048, external link - BGP version 4, remote router ID 172.18.8.0, VRF default - BGP state is Established, up for 7d01h - IPv4 Unicast: 6 5 4 0 - IPv6 Unicast: 6 5 4 0 -Local AS is 65001.1026, local router ID 172.18.4.2 -BGP neighbor is fe80::a8c1:abff:fe5d:9706%Et4, remote AS 65000.7, external link - BGP version 4, remote router ID 172.18.0.7, VRF default - BGP state is Established, up for 7d01h - IPv4 Unicast: 9 2 1 0 - IPv6 Unicast: 9 2 1 0 -Local AS is 65001.1026, local router ID 172.18.4.2 -BGP neighbor is fe80::a8c1:abff:fe95:fa49%Et3, remote AS 65000.5, external link - BGP version 4, remote router ID 172.18.0.5, VRF default - BGP state is Established, up for 7d01h - IPv4 Unicast: 9 2 1 0 - IPv6 Unicast: 9 2 1 0 -Local AS is 65001.1026, local router ID 172.18.4.2 diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json deleted file mode 100644 index aa96e6d48..000000000 --- a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_summary_vrf_all.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "vrfs": { - "default": { - "routerId": "172.18.4.2", - "peers": { - "fe80::a8c1:abff:fe0b:7b5f%Et5": { - "msgSent": 239193, - "inMsgQueue": 0, - "prefixReceived": 2, - "upDownTime": 1664912777.128896, - "version": 4, - "prefixAccepted": 2, - "msgReceived": 203664, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65000.8" - }, - "fe80::a8c1:abff:fe27:69e9%Et2": { - "msgSent": 11995, - "inMsgQueue": 0, - "prefixReceived": 5, - "upDownTime": 1664912780.356703, - "version": 4, - "prefixAccepted": 5, - "msgReceived": 11970, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65002.2049" - }, - "fe80::a8c1:abff:fe35:51d9%Et1": { - "msgSent": 11982, - "inMsgQueue": 0, - "prefixReceived": 5, - "upDownTime": 1664912783.670674, - "version": 4, - "prefixAccepted": 5, - "msgReceived": 11977, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65002.2048" - }, - "fe80::a8c1:abff:fe5d:9706%Et4": { - "msgSent": 239135, - "inMsgQueue": 0, - "prefixReceived": 2, - "upDownTime": 1664912777.50903, - "version": 4, - "prefixAccepted": 2, - "msgReceived": 203688, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65000.7" - }, - "fe80::a8c1:abff:fe95:fa49%Et3": { - "msgSent": 239080, - "inMsgQueue": 0, - "prefixReceived": 2, - "upDownTime": 1664912777.604791, - "version": 4, - "prefixAccepted": 2, - "msgReceived": 203688, - "peerState": "Established", - "outMsgQueue": 0, - "underMaintenance": false, - "asn": "65000.5" - } - }, - "vrf": "default", - "asn": "65001.1026" - } - } -} diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text b/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_r.text rename to test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ip_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_remote_AS___remote_router_ID__IPv_46___Unicast_6PE_____0_9____Local_AS_Desc_BGP_state.text diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json b/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json deleted file mode 100644 index 413d219c4..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "management": { - "name": "management", - "type": "L3VRF", - "state": { "route_distinguisher": "" }, - "interfaces": { "interface": { "Management1": {} } } - }, - "default": { - "interfaces": { - "interface": { - "Ethernet1": {}, - "Ethernet2": {}, - "Ethernet3": {}, - "Ethernet4": {}, - "Ethernet49/1": {}, - "Ethernet5": {}, - "Ethernet50/1": {}, - "Ethernet52/1": {}, - "Ethernet53/1": {}, - "Ethernet54/1": {}, - "Ethernet55/1": {}, - "Ethernet56/1": {}, - "Loopback0": {} - } - }, - "state": { "route_distinguisher": "" }, - "type": "DEFAULT_INSTANCE", - "name": "default" - } -} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text deleted file mode 100644 index cd1dbbba4..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text +++ /dev/null @@ -1,12 +0,0 @@ -Maximum number of vrfs allowed: 1023 - VRF RD Protocols State Interfaces ----------------- --------------- --------------- ------------------- --------------------------- - default ipv4,ipv6 v4:routing, Ethernet1, Ethernet2, - v6:no routing Ethernet3, Ethernet4, - Ethernet49/1, Ethernet5, - Ethernet50/1, Ethernet52/1, - Ethernet53/1, Ethernet54/1, - Ethernet55/1, Ethernet56/1, - Loopback0 - management ipv4,ipv6 v4:routing, Management1 - v6:no routing diff --git a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text index 65fdb6529..e81cd6e11 100644 --- a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text +++ b/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text @@ -1,11 +1,11 @@ Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- --------- ------------ ------------------------ ------------------- - VRFA0 201:201 ipv4 v4:routing; multicast, Vlan2, Vlan102 - v6:no routing + Vrf RD Protocols State Interfaces +------- ------------ ------------ ------------------- ------------------- +VRFA0 201:201 ipv4 v4:routing; multicast, Vlan2, Vlan102 + v6:no routing - VRFA1 203:203 ipv4 v4:routing; multicast, Vlan3, Vlan103 - v6:no routing +VRFA1 203:203 ipv4 v4:routing; multicast, Vlan3, Vlan103 + v6:no routing - VRFA2 205:205 ipv4 v4:routing; multicast, Ethernet1, Vlan100 - v6:no routing +VRFA2 205:205 ipv4 v4:routing; multicast, Ethernet1, Vlan100 + v6:no routing diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt b/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt deleted file mode 100644 index 0cfbf0888..000000000 --- a/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json b/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json deleted file mode 100644 index dc3f3d294..000000000 --- a/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "default": { - "name": "default", - "type": "DEFAULT_INSTANCE", - "state": { "route_distinguisher": "" }, - "interfaces": { - "interface": { - "Ethernet1": {}, - "Ethernet2": {}, - "Loopback0": {}, - "Management0": {} - } - } - }, - "foo": { - "name": "foo", - "type": "L3VRF", - "state": { "route_distinguisher": "0:1" }, - "interfaces": { - "interface": {} - } - }, - "bar": { - "name": "bar", - "type": "L3VRF", - "state": { "route_distinguisher": "" }, - "interfaces": { - "interface": {} - } - } -} diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json b/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json deleted file mode 100644 index bbc04245a..000000000 --- a/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "vrfs": { - "foo": { - "routeDistinguisher": "0:1", - "protocols": { - "ipv4": { - "supported": true, - "protocolState": "up", - "routingState": "up" - }, - "ipv6": { - "supported": true, - "protocolState": "up", - "routingState": "down" - } - }, - "vrfState": "up", - "interfacesV4": [], - "interfacesV6": [], - "interfaces": [] - }, - "bar": { - "routeDistinguisher": "", - "protocols": { - "ipv4": { - "supported": true, - "protocolState": "up", - "routingState": "down" - }, - "ipv6": { - "supported": true, - "protocolState": "up", - "routingState": "down" - } - }, - "vrfState": "up", - "interfacesV4": [], - "interfacesV6": [], - "interfaces": [] - }, - "default": { - "routeDistinguisher": "", - "protocols": { - "ipv4": { - "supported": true, - "protocolState": "up", - "routingState": "up" - }, - "ipv6": { - "supported": true, - "protocolState": "up", - "routingState": "down" - } - }, - "vrfState": "up", - "interfacesV4": ["Ethernet1", "Ethernet2", "Loopback0", "Management0"], - "interfacesV6": ["Management0"], - "interfaces": ["Ethernet1", "Ethernet2", "Loopback0", "Management0"] - } - } -} diff --git a/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json index d6a2343ac..f74d5a593 100644 --- a/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json @@ -5,7 +5,7 @@ "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 65001, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +15,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65001, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { @@ -37,7 +37,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65001, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { @@ -75,7 +75,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65001, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { diff --git a/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json index b75943177..6c5a9cbaa 100644 --- a/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/no_afi/expected_result.json @@ -2,7 +2,7 @@ "_": { "apply_groups": [], "description": "", - "local_as": 42, + "local_as": 0, "type": "", "import_policy": "", "export_policy": "", @@ -20,7 +20,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 42, + "local_as": 0, "authentication_key": "", "nhs": false, "route_reflector_client": false diff --git a/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json deleted file mode 100644 index 0967ef424..000000000 --- a/test/ios/mocked_data/test_get_bgp_config/no_bgp/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt b/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt deleted file mode 100644 index 50e08a544..000000000 --- a/test/ios/mocked_data/test_get_bgp_config/no_bgp/show_running_config.txt +++ /dev/null @@ -1,150 +0,0 @@ -! -! Last configuration change at 18:41:02 UTC Thu Nov 24 2016 -! -version 15.5 -service timestamps debug datetime msec -service timestamps log datetime msec -no platform punt-keepalive disable-kernel-core -platform console auto -! -hostname CSR1 -! -boot-start-marker -boot-end-marker -! -! -enable password cisco -! -aaa new-model -! -! -aaa authentication login default local -aaa authorization exec default local -! -! -! -! -! -aaa session-id common -! -ip vrf MGMT -! -! -! -! -! -! -! -! -! - - -ip domain name example.local - -! -! -! -! -! -! -! -! -! -! -subscriber templating -! -multilink bundle-name authenticated -! -! -! -! -! -! -! -! -! -! -! -! -! -license udi pid CSR1000V sn 9OSEGKJXRHE -spanning-tree extend system-id -! -username cisco privilege 15 password 0 cisco -! -redundancy -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -! -interface Loopback0 - ip address 1.1.1.1 255.255.255.255 -! -interface GigabitEthernet1 - ip vrf forwarding MGMT - ip address 192.168.35.121 255.255.255.0 - negotiation auto -! -interface GigabitEthernet2 - ip address 10.1.1.1 255.255.255.0 - negotiation auto -! -interface GigabitEthernet3 - no ip address - shutdown - negotiation auto -! -router ospf 1 - redistribute connected subnets - network 10.1.1.0 0.0.0.255 area 0 -! -! -! -! -virtual-service csr_mgmt -! -ip forward-protocol nd -! -no ip http server -no ip http secure-server -! -! -! -! -! -! -control-plane -! - ! - ! - ! - ! -! -! -! -! -! -line con 0 -line vty 0 4 -! -! -end diff --git a/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json index f58f5e0c5..3f4742397 100644 --- a/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,26 +1,11 @@ { - "_": { - "apply_groups": [], - "description": "", - "local_as": 65001, - "type": "", - "import_policy": "", - "export_policy": "", - "local_address": "", - "multipath": false, - "multihop_ttl": 0, - "remote_as": 0, - "remove_private_as": false, - "prefix_limit": {}, - "neighbors": {} - }, "RR-CLIENTS": { "apply_groups": [], "description": "[ibgp - rr clients]", "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 65001, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -30,7 +15,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65001, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { @@ -52,7 +37,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65001, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { diff --git a/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json b/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json index 1f53b03ff..d2dfbaf32 100644 --- a/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json +++ b/test/ios/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json @@ -5,7 +5,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65001, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -15,7 +15,7 @@ "export_policy": "PASS-OUT", "import_policy": "PASS-IN", "local_address": "GigabitEthernet1", - "local_as": 65001, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { @@ -37,4 +37,4 @@ "remove_private_as": false, "type": "" } -} +} \ No newline at end of file diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json deleted file mode 100644 index 49bc80227..000000000 --- a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/expected_result.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "GigabitEthernet9/48": [ - { - "port": "Gi0", - "hostname": "COMPUTER.company.example.com" - } - ] - , - "GigabitEthernet9/8": [ - { - "port": "A1:8B:95:B5:E4:6F", - "hostname": "NICEHOSTNAME" - } - ] -} diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt deleted file mode 100644 index f7074e0d7..000000000 --- a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors.txt +++ /dev/null @@ -1,8 +0,0 @@ - -Capability codes: - (R) Router, (B) Bridge, (T) Telephone, (C) DOCSIS Cable Device - (W) WLAN Access Point, (P) Repeater, (S) Station, (O) Other - -Device ID Local Intf Hold-time Capability Port ID -ACOMPUTER.company.exGi9/48 120 B Gi0 -NICEHOSTNAME Gi9/8 3601 a18b.95b5.e46f diff --git a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt b/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt deleted file mode 100644 index 5908277d6..000000000 --- a/test/ios/mocked_data/test_get_lldp_neighbors/no_mac_support/show_lldp_neighbors_detail.txt +++ /dev/null @@ -1,68 +0,0 @@ ------------------------------------------------- -Local Intf: Gi9/48 -Chassis id: 4a07.d0f3.fbb6 -Port id: Gi0 -Port Description: GigabitEthernet0 -System Name: COMPUTER.company.example.com - -System Description: -Cisco IOS Software, C3600 Software (AP3G2-K9W8-M), Version 15.3(3)JC15, RELEASE SOFTWARE (fc1) -Technical Support: http://www.cisco.com/techsupport -Copyright (c) 1986-2018 by Cisco Systems, Inc. -Compiled Thu 07-Jun-18 16:43 by prod_rel_team - -Time remaining: 95 seconds -System Capabilities: B -Enabled Capabilities: B -Management Addresses: - IP: 10.31.18.65 -Auto Negotiation - supported, enabled -Physical media capabilities: - 1000baseT(FD) - 1000baseT(HD) - 100base-TX(FD) - 100base-TX(HD) - 10base-T(FD) - 10base-T(HD) -Media Attachment Unit type: 30 -Vlan ID: - not advertised -PoE+ Power-via-MDI TLV: - Power Pair: Signal - Power Class: Class 4 - Power Device Type: Type 1 PD - Power Source: PSE - Power Priority: high - Power Requested: 13000 mW - Power Allocated: 13000 mW - ------------------------------------------------- -Local Intf: Gi9/8 -Chassis id: NICEHOSTNAME -Port id: a18b.95b5.e46f -Port Description - not advertised -System Name - not advertised -System Description - not advertised - -Time remaining: 2690 seconds -System Capabilities - not advertised -Enabled Capabilities - not advertised -Management Addresses - not advertised -Auto Negotiation - supported, enabled -Physical media capabilities: - 1000baseT(FD) -Media Attachment Unit type - not advertised -Vlan ID: - not advertised - -MED Information: - - MED Codes: - (NP) Network Policy, (LI) Location Identification - (PS) Power Source Entity, (PD) Power Device - (IN) Inventory - - Inventory information - not advertised - Capabilities: - Device type: Endpoint Class I - Network Policies - not advertised - Power requirements - not advertised - Location - not advertised diff --git a/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json index 60e669b26..e39f06c91 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/mixed_with_without_groups/expected_result.json @@ -8,7 +8,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 65900, + "local_as": 0, "import_policy": "pass-all", "local_address": "", "prefix_limit": { @@ -30,7 +30,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 65900, + "local_as": 0, "import_policy": "pass-all", "local_address": "", "prefix_limit": { @@ -54,7 +54,7 @@ "remove_private_as": false, "description": "", "export_policy": "", - "local_as": 65900, + "local_as": 0, "apply_groups": [], "multipath": false, "prefix_limit": {} @@ -68,7 +68,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 65900, + "local_as": 0, "import_policy": "RP-SPECIAL-SNOWFLAKE-IN", "local_address": "", "prefix_limit": { @@ -90,7 +90,7 @@ "description": "", "route_reflector_client": false, "nhs": false, - "local_as": 65900, + "local_as": 0, "import_policy": "", "local_address": "", "prefix_limit": {}, @@ -104,7 +104,7 @@ "remove_private_as": true, "description": "", "export_policy": "", - "local_as": 65900, + "local_as": 0, "apply_groups": [], "multipath": false, "prefix_limit": {} diff --git a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt deleted file mode 100644 index 1bcd305b2..000000000 --- a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/_Get__Configuration__BGP__Instance__Naming__________InstanceName_default__InstanceName___Naming___Instance___BGP___Configuration___Get_.txt +++ /dev/null @@ -1,2 +0,0 @@ - -default diff --git a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json deleted file mode 100644 index 0967ef424..000000000 --- a/test/iosxr/mocked_data/test_get_bgp_config/no_bgp/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json index c850fe601..20971ddf8 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,28 +1,13 @@ { - "_": { - "local_as": 13335, - "remove_private_as": false, - "import_policy": "", - "multihop_ttl": 0, - "neighbors": {}, - "multipath": false, - "export_policy": "", - "type": "", - "apply_groups": [], - "remote_as": 0, - "prefix_limit": {}, - "description": "", - "local_address": "" - }, "4-public-anycast-peers": { - "local_as": 13335, + "local_as": 0, "remove_private_as": true, "import_policy": "4-public-anycast-peers-in", "multihop_ttl": 0, "neighbors": { "192.168.20.3": { "export_policy": "", - "local_as": 13335, + "local_as": 0, "prefix_limit": { "inet": { "unicast": { @@ -44,7 +29,7 @@ }, "172.17.17.50": { "export_policy": "", - "local_as": 13335, + "local_as": 0, "prefix_limit": { "inet": { "unicast": { @@ -66,7 +51,7 @@ }, "192.168.50.5": { "export_policy": "", - "local_as": 13335, + "local_as": 0, "prefix_limit": { "inet": { "unicast": { diff --git a/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json b/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json index 30a30dd4c..bc0239416 100644 --- a/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json +++ b/test/iosxr/mocked_data/test_get_bgp_config/peers_without_groups/expected_result.json @@ -10,7 +10,7 @@ "remove_private_as": false, "remote_as": 0, "multihop_ttl": 0, - "local_as": 65900, + "local_as": 0, "apply_groups": [], "neighbors": { "10.255.255.2": { @@ -26,7 +26,7 @@ } } }, - "local_as": 65900, + "local_as": 0, "description": "", "local_address": "", "import_policy": "pass-all", @@ -48,7 +48,7 @@ } } }, - "local_as": 65900, + "local_as": 0, "description": "", "local_address": "", "import_policy": "pass-all", diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json deleted file mode 100644 index 0967ef424..000000000 --- a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml b/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml deleted file mode 100644 index 7a3a0b218..000000000 --- a/test/iosxr_netconf/mocked_data/test_get_bgp_config/no_bgp/ipv4-bgp-cfg_bgp__running.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - diff --git a/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json index 4ed653140..1d60e8893 100644 --- a/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/iosxr_netconf/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,26 +1,11 @@ { - "_": { - "apply_groups": [], - "description": "", - "export_policy": "", - "import_policy": "", - "local_address": "", - "local_as": 65172, - "multihop_ttl": 0, - "multipath": false, - "neighbors": {}, - "prefix_limit": {}, - "remote_as": 0, - "remove_private_as": false, - "type": "" - }, "EBGP": { "apply_groups": [], "description": "", "export_policy": "EBGP-OUT-POLICY", "import_policy": "EBGP-IN-POLICY", "local_address": "", - "local_as": 65172, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -30,7 +15,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { @@ -52,7 +37,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { @@ -80,7 +65,7 @@ "export_policy": "EBGP-VRF-OUT-POLICY", "import_policy": "EBGP-VRF-IN-POLICY", "local_address": "", - "local_as": 65172, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": {}, @@ -95,7 +80,7 @@ "export_policy": "IBGPv6-OUT-POLICY", "import_policy": "IBGPv6-IN-POLICY", "local_address": "", - "local_as": 65172, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -105,7 +90,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "nhs": false, "prefix_limit": { "inet6": { @@ -127,7 +112,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "nhs": false, "prefix_limit": { "inet6": { @@ -155,7 +140,7 @@ "export_policy": "EBGPv6-VRF-OUT-POLICY", "import_policy": "EBGPv6-VRF-IN-POLICY", "local_address": "", - "local_as": 65172, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": {}, @@ -170,7 +155,7 @@ "export_policy": "IBGP-OUT-POLICY", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -180,7 +165,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "nhs": false, "prefix_limit": { "inet": { @@ -208,7 +193,7 @@ "export_policy": "IBGP-OUT-POLICY", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "multihop_ttl": 0, "multipath": false, "neighbors": { @@ -218,7 +203,7 @@ "export_policy": "", "import_policy": "", "local_address": "", - "local_as": 65172, + "local_as": 0, "nhs": false, "prefix_limit": { "inet6": { diff --git a/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml deleted file mode 100644 index bd581bc2c..000000000 --- a/test/junos/mocked_data/test_get_bgp_config/nhs/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - 65001 - - - diff --git a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json index a375a75a0..93c77a2ec 100644 --- a/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/nhs/expected_result.json @@ -1,73 +1 @@ -{ - "_": { - "export_policy": "", - "multipath": false, - "prefix_limit": {}, - "description": "", - "local_as": 65001, - "multihop_ttl": 0, - "apply_groups": [], - "remote_as": 0, - "remove_private_as": false, - "local_address": "", - "type": "", - "import_policy": "", - "neighbors": {} - }, - "internal": { - "apply_groups": [], - "description": "", - "export_policy": "", - "import_policy": "", - "local_address": "", - "local_as": 65001, - "multihop_ttl": 0, - "multipath": false, - "neighbors": { - "10.10.10.1": { - "authentication_key": "", - "description": "", - "export_policy": "nhs", - "import_policy": "", - "local_address": "", - "local_as": 65001, - "nhs": true, - "prefix_limit": {}, - "remote_as": 0, - "route_reflector_client": false - } - }, - "prefix_limit": {}, - "remote_as": 0, - "remove_private_as": false, - "type": "internal" - }, - "internal-2": { - "apply_groups": [], - "description": "", - "export_policy": "", - "import_policy": "", - "local_address": "", - "local_as": 65001, - "multihop_ttl": 0, - "multipath": false, - "neighbors": { - "10.10.10.2": { - "authentication_key": "", - "description": "", - "export_policy": "static", - "import_policy": "", - "local_address": "", - "local_as": 65001, - "nhs": false, - "prefix_limit": {}, - "remote_as": 0, - "route_reflector_client": false - } - }, - "prefix_limit": {}, - "remote_as": 0, - "remove_private_as": false, - "type": "internal" - } -} +{"internal":{"apply_groups":[],"description":"","export_policy":"","import_policy":"","local_address":"","local_as":0,"multihop_ttl":0,"multipath":false,"neighbors":{"10.10.10.1":{"authentication_key":"","description":"","export_policy":"nhs","import_policy":"","local_address":"","local_as":0,"nhs":true,"prefix_limit":{},"remote_as":0,"route_reflector_client":false}},"prefix_limit":{},"remote_as":0,"remove_private_as":false,"type":"internal"},"internal-2":{"apply_groups":[],"description":"","export_policy":"","import_policy":"","local_address":"","local_as":0,"multihop_ttl":0,"multipath":false,"neighbors":{"10.10.10.2":{"authentication_key":"","description":"","export_policy":"static","import_policy":"","local_address":"","local_as":0,"nhs":false,"prefix_limit":{},"remote_as":0,"route_reflector_client":false}},"prefix_limit":{},"remote_as":0,"remove_private_as":false,"type":"internal"}} diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml deleted file mode 100644 index 83138436e..000000000 --- a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__policy_options__policy_statement____policy_options___configuration_.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml deleted file mode 100644 index 83138436e..000000000 --- a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__protocols__bgp__group____bgp___protocols___configuration_.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml deleted file mode 100644 index 83138436e..000000000 --- a/test/junos/mocked_data/test_get_bgp_config/no_bgp/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json deleted file mode 100644 index 0967ef424..000000000 --- a/test/junos/mocked_data/test_get_bgp_config/no_bgp/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml b/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml deleted file mode 100644 index 6ad44d234..000000000 --- a/test/junos/mocked_data/test_get_bgp_config/normal/_configuration__routing_options__autonomous_system____routing_options___configuration_.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - 13335 - - - diff --git a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json index 6c44290dd..868ef99cc 100644 --- a/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json +++ b/test/junos/mocked_data/test_get_bgp_config/normal/expected_result.json @@ -1,69 +1 @@ -{ - "_": { - "export_policy": "", - "multipath": false, - "prefix_limit": {}, - "description": "", - "local_as": 13335, - "multihop_ttl": 0, - "apply_groups": [], - "remote_as": 0, - "remove_private_as": false, - "local_address": "", - "type": "", - "import_policy": "", - "neighbors": {} - }, - "PEERS-GROUP-NAME": { - "neighbors": { - "192.168.0.1": { - "export_policy": "", - "prefix_limit": { - "inet": { - "unicast": { - "limit": 100 - } - } - }, - "route_reflector_client": false, - "description": "Facebook [CDN]", - "local_as": 13335, - "nhs": false, - "local_address": "", - "remote_as": 32934, - "authentication_key": "", - "import_policy": "" - }, - "172.17.17.1": { - "export_policy": "", - "prefix_limit": { - "inet": { - "unicast": { - "limit": 500 - } - } - }, - "route_reflector_client": false, - "description": "Twitter [CDN]", - "local_as": 13335, - "nhs": false, - "local_address": "", - "remote_as": 13414, - "authentication_key": "", - "import_policy": "" - } - }, - "export_policy": "PUBLIC-PEER-OUT", - "multipath": true, - "prefix_limit": {}, - "description": "", - "local_as": 13335, - "multihop_ttl": 0, - "apply_groups": ["BGP-PREFIX-LIMIT"], - "remote_as": 0, - "remove_private_as": true, - "local_address": "", - "type": "external", - "import_policy": "PUBLIC-PEER-IN" - } -} +{"PEERS-GROUP-NAME": {"neighbors": {"192.168.0.1": {"export_policy": "", "prefix_limit": {"inet": {"unicast": {"limit": 100}}}, "route_reflector_client": false, "description": "Facebook [CDN]", "local_as": 0, "nhs": false, "local_address": "", "remote_as": 32934, "authentication_key": "", "import_policy": ""}, "172.17.17.1": {"export_policy": "", "prefix_limit": {"inet": {"unicast": {"limit": 500}}}, "route_reflector_client": false, "description": "Twitter [CDN]", "local_as": 0, "nhs": false, "local_address": "", "remote_as": 13414, "authentication_key": "", "import_policy": ""}}, "export_policy": "PUBLIC-PEER-OUT", "multipath": true, "prefix_limit": {}, "description": "", "local_as": 13335, "multihop_ttl": 0, "apply_groups": ["B", "G", "P", "-", "P", "R", "E", "F", "I", "X", "-", "L", "I", "M", "I", "T"], "remote_as": 0, "remove_private_as": true, "local_address": "", "type": "external", "import_policy": "PUBLIC-PEER-IN"}} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json deleted file mode 100644 index ca3d2f110..000000000 --- a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/expected_result.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "management": { - "name": "management", - "type": "L3VRF", - "state": { - "route_distinguisher": "0:0" - }, - "interfaces": { - "interface": { - "mgmt0": {} - } - } - }, - "default": { - "name": "default", - "type": "DEFAULT_INSTANCE", - "state": { - "route_distinguisher": "0:0" - }, - "interfaces": { - "interface": { - "Vlan1": {}, - "Vlan100": {}, - "Vlan101": {}, - "Vlan102": {}, - "Vlan103": {}, - "Vlan104": {}, - "Vlan105": {}, - "loopback1": {}, - "Null0": {}, - "Ethernet1/5": {}, - "Ethernet1/5.1": {} - } - } - } -} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt deleted file mode 100644 index 637f62365..000000000 --- a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_detail___json.txt +++ /dev/null @@ -1,58 +0,0 @@ -{ - "TABLE_vrf": { - "ROW_vrf": [ - { - "vrf_name": "default", - "vrf_id": 1, - "vrf_state": "Up", - "vpnid": "unknown", - "rd": "0:0", - "vni": 0, - "max_routes": 0, - "mid_threshold": 0, - "TABLE_tib": { - "ROW_tib": [ - { - "tib_id": 80000001, - "tib_af": "IPv6", - "tib_nonce": 80000001, - "tib_state": "Up" - }, - { - "tib_id": 1, - "tib_af": "IPv4", - "tib_nonce": 1, - "tib_state": "Up" - } - ] - } - }, - { - "vrf_name": "management", - "vrf_id": 2, - "vrf_state": "Up", - "vpnid": "unknown", - "rd": "0:0", - "vni": 0, - "max_routes": 0, - "mid_threshold": 0, - "TABLE_tib": { - "ROW_tib": [ - { - "tib_id": 80000002, - "tib_af": "IPv6", - "tib_nonce": 80000002, - "tib_state": "Up" - }, - { - "tib_id": 2, - "tib_af": "IPv4", - "tib_nonce": 2, - "tib_state": "Up" - } - ] - } - } - ] - } -} diff --git a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt b/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt deleted file mode 100644 index 72a325a0d..000000000 --- a/test/nxos_ssh/mocked_data/test_get_network_instances/normal/show_vrf_interface___json.txt +++ /dev/null @@ -1,78 +0,0 @@ -{ - "TABLE_if": { - "ROW_if": [ - { - "if_name": "Vlan1", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Vlan100", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Vlan101", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Vlan102", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Vlan103", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Vlan104", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Vlan105", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "loopback1", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Null0", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Ethernet1/5", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "Ethernet1/5.1", - "vrf_name": "default", - "vrf_id": 1, - "soo": "--" - }, - { - "if_name": "mgmt0", - "vrf_name": "management", - "vrf_id": 2, - "soo": "--" - } - ] - } -} diff --git a/test/pyiosxr/test_iosxr.py b/test/pyiosxr/test_iosxr.py index b8485659d..9c8128c45 100755 --- a/test/pyiosxr/test_iosxr.py +++ b/test/pyiosxr/test_iosxr.py @@ -257,7 +257,7 @@ def test__getattr_show_config(self): def test__getattr__no_show(self): - """Test special attribute __getattr__ against a no-show command""" + """Test special attribute __getattr__ agains a no-show command""" raised = False diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..a6f11697f --- /dev/null +++ b/tox.ini @@ -0,0 +1,39 @@ +[tox] +envlist = py3{6,7,8},black,pylama +skip_missing_interpreters = true + +[testenv] +deps = + -rrequirements.txt + -rrequirements-dev.txt +passenv = * + +commands = + py.test --cov=napalm --cov-report term-missing -vs --pylama {posargs} + +[testenv:black] +deps = black==20.8b1 + +basepython = python3.6 +commands = + black --check . + +[testenv:pylama] +deps = + -rrequirements-dev.txt + +basepython = python3.6 +commands = + pylama . + +[testenv:sphinx] +deps = + -rdocs/requirements.txt + +basepython = python3.6 + +commands = + make doctest + +whitelist_externals = + make From 50ab9f73a2afd8c84c430e5d844e570f28adc917 Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Tue, 23 May 2023 11:17:53 -0700 Subject: [PATCH 51/76] Update black to a newer version (#1940) --- napalm/base/base.py | 10 ----- napalm/base/clitools/cl_napalm_configure.py | 1 - napalm/base/test/base.py | 4 -- napalm/base/test/getters.py | 4 +- napalm/eos/eos.py | 10 ----- napalm/ios/ios.py | 6 +-- napalm/iosxr/iosxr.py | 18 --------- napalm/iosxr_netconf/iosxr_netconf.py | 4 +- napalm/junos/junos.py | 2 - napalm/nxapi_plumbing/api_client.py | 1 - napalm/nxos/nxos.py | 3 -- napalm/pyIOSXR/exceptions.py | 1 - napalm/pyIOSXR/iosxr.py | 6 --- requirements-dev.txt | 2 +- test/base/test_helpers.py | 2 - test/eos/test_heredoc.py | 2 - test/ios/conftest.py | 1 - test/iosxr/conftest.py | 1 - test/iosxr_netconf/conftest.py | 1 - test/junos/TestJunOSDriver.py | 1 - test/junos/conftest.py | 1 - test/pyiosxr/test_iosxr.py | 44 --------------------- 22 files changed, 5 insertions(+), 120 deletions(-) diff --git a/napalm/base/base.py b/napalm/base/base.py index 7410bf6a8..b1b56040d 100644 --- a/napalm/base/base.py +++ b/napalm/base/base.py @@ -742,7 +742,6 @@ def get_bgp_config( def cli( self, commands: List[str], encoding: str = "text" ) -> Dict[str, Union[str, Dict[str, Any]]]: - """ Will execute a list of commands and return the output in a dictionary format. @@ -772,7 +771,6 @@ def cli( def get_bgp_neighbors_detail( self, neighbor_address: str = "" ) -> Dict[str, models.PeerDetailsDict]: - """ Returns a detailed view of the BGP neighbors as a dictionary of lists. @@ -867,7 +865,6 @@ def get_bgp_neighbors_detail( raise NotImplementedError def get_arp_table(self, vrf: str = "") -> List[models.ARPTableDict]: - """ Returns a list of dictionaries having the following set of keys: * interface (string) @@ -902,7 +899,6 @@ def get_arp_table(self, vrf: str = "") -> List[models.ARPTableDict]: raise NotImplementedError def get_ntp_peers(self) -> Dict[str, models.NTPPeerDict]: - """ Returns the NTP peers configuration as dictionary. The keys of the dictionary represent the IP Addresses of the peers. @@ -922,7 +918,6 @@ def get_ntp_peers(self) -> Dict[str, models.NTPPeerDict]: raise NotImplementedError def get_ntp_servers(self) -> Dict[str, models.NTPServerDict]: - """ Returns the NTP servers configuration as dictionary. The keys of the dictionary represent the IP Addresses of the servers. @@ -942,7 +937,6 @@ def get_ntp_servers(self) -> Dict[str, models.NTPServerDict]: raise NotImplementedError def get_ntp_stats(self) -> List[models.NTPStats]: - """ Returns a list of NTP synchronization statistics. @@ -979,7 +973,6 @@ def get_ntp_stats(self) -> List[models.NTPStats]: raise NotImplementedError def get_interfaces_ip(self) -> Dict[str, models.InterfacesIPDict]: - """ Returns all configured IP addresses on all interfaces as a dictionary of dictionaries. Keys of the main dictionary represent the name of the interface. @@ -1033,7 +1026,6 @@ def get_interfaces_ip(self) -> Dict[str, models.InterfacesIPDict]: raise NotImplementedError def get_mac_address_table(self) -> List[models.MACAdressTable]: - """ Returns a lists of dictionaries. Each dictionary represents an entry in the MAC Address Table, having the following keys: @@ -1086,7 +1078,6 @@ def get_mac_address_table(self) -> List[models.MACAdressTable]: def get_route_to( self, destination: str = "", protocol: str = "", longer: bool = False ) -> Dict[str, models.RouteDict]: - """ Returns a dictionary of dictionaries containing details of all available routes to a destination. @@ -1161,7 +1152,6 @@ def get_route_to( raise NotImplementedError def get_snmp_information(self) -> models.SNMPDict: - """ Returns a dict of dicts containing SNMP configuration. Each inner dictionary contains these fields diff --git a/napalm/base/clitools/cl_napalm_configure.py b/napalm/base/clitools/cl_napalm_configure.py index 85752359e..f259209c7 100644 --- a/napalm/base/clitools/cl_napalm_configure.py +++ b/napalm/base/clitools/cl_napalm_configure.py @@ -22,7 +22,6 @@ def run( vendor, hostname, user, password, strategy, optional_args, config_file, dry_run ): - logger.debug('Getting driver for OS "{driver}"'.format(driver=vendor)) driver = get_network_driver(vendor) diff --git a/napalm/base/test/base.py b/napalm/base/test/base.py index 4d59ec0db..d46f7ff47 100644 --- a/napalm/base/test/base.py +++ b/napalm/base/test/base.py @@ -529,7 +529,6 @@ def test_ping(self): self.assertTrue(result) def test_traceroute(self): - destination = "8.8.8.8" try: get_traceroute = self.device.traceroute(destination) @@ -547,7 +546,6 @@ def test_traceroute(self): self.assertTrue(result) def test_get_users(self): - try: get_users = self.device.get_users() except NotImplementedError: @@ -561,7 +559,6 @@ def test_get_users(self): self.assertTrue(result) def test_get_optics(self): - try: get_optics = self.device.get_optics() except NotImplementedError: @@ -575,7 +572,6 @@ def test_get_optics(self): assert len(channel) == 2 assert isinstance(channel["index"], int) for field in ["input_power", "output_power", "laser_bias_current"]: - assert len(channel["state"][field]) == 4 assert isinstance(channel["state"][field]["instant"], float) assert isinstance(channel["state"][field]["avg"], float) diff --git a/napalm/base/test/getters.py b/napalm/base/test/getters.py index 0a2e47a66..5c660ab21 100644 --- a/napalm/base/test/getters.py +++ b/napalm/base/test/getters.py @@ -112,7 +112,8 @@ def test_method_signatures(self): """ Test that all methods have the same signature. - The type hint annotations are ignored here because the import paths might differ.""" + The type hint annotations are ignored here because the import paths might differ. + """ errors = {} cls = self.driver # Create fictional driver instance (py3 needs bound methods) @@ -493,7 +494,6 @@ def test_get_optics(self, test_case): assert len(channel) == 2 assert isinstance(channel["index"], int) for field in ["input_power", "output_power", "laser_bias_current"]: - assert len(channel["state"][field]) == 4 assert isinstance(channel["state"][field]["instant"], float) assert isinstance(channel["state"][field]["avg"], float) diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index d5554f434..52db5463b 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -907,7 +907,6 @@ def _transform_lldp_capab(self, capabilities): return sorted([LLDP_CAPAB_TRANFORM_TABLE[c.lower()] for c in capabilities]) def get_lldp_neighbors_detail(self, interface=""): - lldp_neighbors_out = {} filters = [] @@ -1085,7 +1084,6 @@ def default_neighbor_dict(local_as, group_dict): return neighbor_dict def parse_options(options, default_value=False): - if not options: return {} @@ -1330,7 +1328,6 @@ def get_ntp_stats(self): return ntp_stats def get_interfaces_ip(self): - interfaces_ip = {} interfaces_ipv4_out = self._run_commands(["show ip interface"])[0]["interfaces"] @@ -1427,7 +1424,6 @@ def get_interfaces_ip(self): return interfaces_ip def get_mac_address_table(self): - mac_table = [] commands = ["show mac address-table"] @@ -1725,7 +1721,6 @@ def traceroute( timeout=c.TRACEROUTE_TIMEOUT, vrf=c.TRACEROUTE_VRF, ): - _HOP_ENTRY_PROBE = [ r"\s+", r"(", # beginning of host_name (ip_address) RTT group @@ -1882,7 +1877,6 @@ def _parse_per_peer_bgp_detail(peer_output): ) for item in peer_info: - # Determining a few other fields in the final peer_info item["up"] = True if item["up"] == "up" else False item["local_address_configured"] = ( @@ -1942,7 +1936,6 @@ def _parse_per_peer_bgp_detail(peer_output): return peer_details def _append(bgp_dict, peer_info): - remote_as = peer_info["remote_as"] vrf_name = peer_info["routing_table"] @@ -1995,7 +1988,6 @@ def _append(bgp_dict, peer_info): v6_peer_info = _parse_per_peer_bgp_detail(raw_output[1]["output"]) for peer_info in v4_peer_info: - vrf_name = peer_info["routing_table"] peer_remote_addr = peer_info["remote_address"] peer_info["accepted_prefix_count"] = ( @@ -2009,7 +2001,6 @@ def _append(bgp_dict, peer_info): _append(bgp_detail_info, peer_info) for peer_info in v6_peer_info: - vrf_name = peer_info["routing_table"] peer_remote_addr = peer_info["remote_address"] peer_info["accepted_prefix_count"] = ( @@ -2025,7 +2016,6 @@ def _append(bgp_dict, peer_info): return bgp_detail_info def get_optics(self): - command = ["show interfaces transceiver"] output = self._run_commands(command, encoding="json")[0]["interfaces"] diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 5e31c49f8..df7a78400 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -783,7 +783,6 @@ def _xfer_file( use_scp = False with TransferClass(**kwargs) as transfer: - # Check if file already exists and has correct MD5 if transfer.check_file_exists() and transfer.compare_md5(): msg = "File already exists and has correct MD5: no SCP needed" @@ -1220,7 +1219,6 @@ def get_interfaces(self): interface_dict = {} for line in output.splitlines(): - interface_regex_1 = r"^(\S+?)\s+is\s+(.+?),\s+line\s+protocol\s+is\s+(\S+)" interface_regex_2 = r"^(\S+)\s+is\s+(up|down)" interface_regex_3 = ( @@ -3135,7 +3133,7 @@ def get_route_to(self, destination="", protocol="", longer=False): for cmditem in commands: outvrf = self._send_command(cmditem) output.append(outvrf) - for (outitem, _vrf) in zip(output, vrfs): # for all VRFs + for outitem, _vrf in zip(output, vrfs): # for all VRFs route_proto_regex = RE_RP_FROM.search(outitem) if route_proto_regex: route_match = destination @@ -3550,7 +3548,6 @@ def traceroute( return traceroute_dict def get_network_instances(self, name=""): - instances = {} sh_vrf_detail = self._send_command("show vrf detail") show_ip_int_br = self._send_command("show ip interface brief") @@ -3583,7 +3580,6 @@ def get_network_instances(self, name=""): return instances for vrf in sh_vrf_detail.split("\n\n"): - first_part = vrf.split("Address family")[0] # retrieve the name of the VRF and the Route Distinguisher diff --git a/napalm/iosxr/iosxr.py b/napalm/iosxr/iosxr.py index 383e8ae00..475ad3484 100644 --- a/napalm/iosxr/iosxr.py +++ b/napalm/iosxr/iosxr.py @@ -152,7 +152,6 @@ def rollback(self): self.device.rollback() def get_facts(self): - facts = { "vendor": "Cisco", "os_version": "", @@ -256,7 +255,6 @@ def get_facts(self): return facts def get_interfaces(self): - interfaces = {} INTERFACE_DEFAULTS = { @@ -844,7 +842,6 @@ def get_module_xml_query(module, selection): return environment_status def get_lldp_neighbors(self): - # init result dict lldp = {} sh_lldp = self.device.show_lldp_neighbors().splitlines()[5:-3] @@ -864,7 +861,6 @@ def get_lldp_neighbors(self): return lldp def get_lldp_neighbors_detail(self, interface=""): - lldp_neighbors = {} rpc_command = ( @@ -953,7 +949,6 @@ def cli(self, commands, encoding="text"): return cli_output def get_bgp_config(self, group="", neighbor=""): - bgp_config = {} # a helper @@ -1202,7 +1197,6 @@ def build_prefix_limit(af_table, limit, prefix_percent, prefix_timeout): return bgp_config def get_bgp_neighbors_detail(self, neighbor_address=""): - bgp_neighbors_detail = {} active_vrfs = ["default"] @@ -1504,7 +1498,6 @@ def get_arp_table(self, vrf=""): return arp_table def get_ntp_peers(self): - ntp_peers = {} rpc_command = "" @@ -1529,7 +1522,6 @@ def get_ntp_peers(self): return ntp_peers def get_ntp_servers(self): - ntp_servers = {} rpc_command = "" @@ -1554,7 +1546,6 @@ def get_ntp_servers(self): return ntp_servers def get_ntp_stats(self): - ntp_stats = [] rpc_command = ( @@ -1607,7 +1598,6 @@ def get_ntp_stats(self): return ntp_stats def get_interfaces_ip(self): - interfaces_ip = {} rpc_command_ipv4_ipv6 = "\ @@ -1688,7 +1678,6 @@ def get_interfaces_ip(self): return interfaces_ip def get_mac_address_table(self): - mac_table = [] rpc_command = ( @@ -1725,7 +1714,6 @@ def get_mac_address_table(self): return mac_table def get_route_to(self, destination="", protocol="", longer=False): - routes = {} global IP_RIBRoute @@ -1936,7 +1924,6 @@ def get_route_to(self, destination="", protocol="", longer=False): return routes def get_snmp_information(self): - snmp_information = {} snmp_rpc_command = "" @@ -1966,7 +1953,6 @@ def get_snmp_information(self): return snmp_information def get_probes_config(self): - sla_config = {} _PROBE_TYPE_XML_TAG_MAP_ = { @@ -2014,7 +2000,6 @@ def get_probes_config(self): return sla_config def get_probes_results(self): - sla_results = {} _PROBE_TYPE_XML_TAG_MAP_ = { @@ -2198,7 +2183,6 @@ def traceroute( timeout=C.TRACEROUTE_TIMEOUT, vrf=C.TRACEROUTE_VRF, ): - traceroute_result = {} ipv = 4 @@ -2305,7 +2289,6 @@ def traceroute( return traceroute_result def get_users(self): - users = {} _CISCO_GROUP_TO_CISCO_PRIVILEGE_MAP = { @@ -2336,7 +2319,6 @@ def get_users(self): return users def get_config(self, retrieve="all", full=False, sanitized=False): - config = {"startup": "", "running": "", "candidate": ""} # default values # IOS-XR only supports "all" on "show run" diff --git a/napalm/iosxr_netconf/iosxr_netconf.py b/napalm/iosxr_netconf/iosxr_netconf.py index ff7a06ef8..6f224e46a 100644 --- a/napalm/iosxr_netconf/iosxr_netconf.py +++ b/napalm/iosxr_netconf/iosxr_netconf.py @@ -451,7 +451,7 @@ def get_interfaces(self): interfaces_rpc_reply_etree = ETREE.fromstring(interfaces_rpc_reply) # Retrieves interfaces details - for (interface_tree, description_tree) in zip( + for interface_tree, description_tree in zip( interfaces_rpc_reply_etree.xpath( ".//int:interfaces/int:interface-xr/int:interface", namespaces=C.NS ), @@ -459,7 +459,6 @@ def get_interfaces(self): ".//int:interfaces/int:interfaces/int:interface", namespaces=C.NS ), ): - interface_name = self._find_txt( interface_tree, "./int:interface-name", default="", namespaces=C.NS ) @@ -680,7 +679,6 @@ def get_vrf_neighbors(rpc_reply_etree, xpath): neighbors = {} for neighbor in rpc_reply_etree.xpath(xpath, namespaces=C.NS): - this_neighbor = {} this_neighbor["local_as"] = napalm.base.helpers.convert( int, diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index 74b6e5efe..b12d09774 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -2128,7 +2128,6 @@ def ping( vrf=C.PING_VRF, source_interface=C.PING_SOURCE_INTERFACE, ): - ping_dict = {} source_str = "" @@ -2458,7 +2457,6 @@ def get_config(self, retrieve="all", full=False, sanitized=False): return rv def get_network_instances(self, name=""): - network_instances = {} ri_table = junos_views.junos_nw_instances_table(self.device) diff --git a/napalm/nxapi_plumbing/api_client.py b/napalm/nxapi_plumbing/api_client.py index a813ec716..52e28357b 100644 --- a/napalm/nxapi_plumbing/api_client.py +++ b/napalm/nxapi_plumbing/api_client.py @@ -185,7 +185,6 @@ def _process_api_response( new_response = [] for response in response_list: - # Detect errors self._error_check(response) diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index 9668569ff..09170074d 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -133,7 +133,6 @@ def __init__( def load_replace_candidate( self, filename: Optional[str] = None, config: Optional[str] = None ) -> None: - if not filename and not config: raise ReplaceConfigException( "filename or config parameter must be provided." @@ -444,7 +443,6 @@ def traceroute( timeout: int = c.TRACEROUTE_TIMEOUT, vrf: str = c.TRACEROUTE_VRF, ) -> models.TracerouteResultDict: - _HOP_ENTRY_PROBE = [ r"\s+", r"(", # beginning of host_name (ip_address) RTT group @@ -587,7 +585,6 @@ def _disable_confirmation(self) -> None: def get_config( self, retrieve: str = "all", full: bool = False, sanitized: bool = False ) -> models.ConfigDict: - # NX-OS adds some extra, unneeded lines that should be filtered. filter_strings = [ r"!Command: show .*$", diff --git a/napalm/pyIOSXR/exceptions.py b/napalm/pyIOSXR/exceptions.py index 0a854c33d..96de83d3e 100644 --- a/napalm/pyIOSXR/exceptions.py +++ b/napalm/pyIOSXR/exceptions.py @@ -24,7 +24,6 @@ class IOSXRException(Exception): def __init__(self, msg=None, dev=None): - super(IOSXRException, self).__init__(msg) if dev: self._xr = dev diff --git a/napalm/pyIOSXR/iosxr.py b/napalm/pyIOSXR/iosxr.py index a1ddc2215..08e51c173 100644 --- a/napalm/pyIOSXR/iosxr.py +++ b/napalm/pyIOSXR/iosxr.py @@ -132,7 +132,6 @@ def __getattr__(self, item): """ def _getattr(*args, **kwargs): - cmd = item.replace("_", " ") for arg in args: cmd += " %s" % arg @@ -244,7 +243,6 @@ def _send_command_timing(self, command): ) def _in_cli_mode(self): - out = self._send_command_timing("\n") if not out: return False @@ -253,7 +251,6 @@ def _in_cli_mode(self): return False def _enter_xml_mode(self): - self._unlock_xml_agent() # release - other commands should not have anyway access to the XML agent # when not in XML mode @@ -283,7 +280,6 @@ def _send_command( read_output=None, receive=False, ): - if not expect_string: expect_string = self._XML_MODE_PROMPT @@ -405,7 +401,6 @@ def _send_command( # previous module function __execute_rpc__ def _execute_rpc(self, command_xml, delay_factor=0.1): - xml_rpc_command = ( '' + command_xml @@ -433,7 +428,6 @@ def _execute_rpc(self, command_xml, delay_factor=0.1): result_summary = root.find("ResultSummary") if result_summary is not None and int(result_summary.get("ErrorCount", 0)) > 0: - if "CLI" in childs: error_msg = root.find("CLI").get("ErrorMsg") or "" elif "Commit" in childs: diff --git a/requirements-dev.txt b/requirements-dev.txt index 62923790b..3b479bec5 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,4 +1,4 @@ -black==22.6.0 +black==23.3.0 coveralls==3.3.1 ddt==1.6.0 flake8-import-order==0.18.2 diff --git a/test/base/test_helpers.py b/test/base/test_helpers.py index cd2226877..3f1a86eee 100644 --- a/test/base/test_helpers.py +++ b/test/base/test_helpers.py @@ -265,7 +265,6 @@ def test_convert(self): # should return empty unicode def test_find_txt(self): - """ Tests helper function ```find_txt```: @@ -352,7 +351,6 @@ def test_find_txt(self): self.assertTrue(len(napalm.base.helpers.find_txt(_NOT_SPECIAL_CHILD2, ".")) > 0) def test_mac(self): - """ Tests the helper function ```mac```: diff --git a/test/eos/test_heredoc.py b/test/eos/test_heredoc.py index a7b46cbfd..9190ff67e 100644 --- a/test/eos/test_heredoc.py +++ b/test/eos/test_heredoc.py @@ -6,7 +6,6 @@ @pytest.mark.usefixtures("set_device_parameters") class TestConfigMangling(object): def test_heredoc(self): - raw_config = dedent( """\ hostname vEOS @@ -117,7 +116,6 @@ def test_mode_comment(self): ) def test_heredoc_with_bangs(self): - raw_config = dedent( """\ hostname vEOS diff --git a/test/ios/conftest.py b/test/ios/conftest.py index 7fa26bd21..948b986f3 100644 --- a/test/ios/conftest.py +++ b/test/ios/conftest.py @@ -32,7 +32,6 @@ class PatchedIOSDriver(ios.IOSDriver): """Patched IOS Driver.""" def __init__(self, hostname, username, password, timeout=60, optional_args=None): - super().__init__(hostname, username, password, timeout, optional_args) self.patched_attrs = ["device"] diff --git a/test/iosxr/conftest.py b/test/iosxr/conftest.py index a8b40d83b..7ef92f9d6 100644 --- a/test/iosxr/conftest.py +++ b/test/iosxr/conftest.py @@ -32,7 +32,6 @@ class PatchedIOSXRDriver(iosxr.IOSXRDriver): """Patched IOS Driver.""" def __init__(self, hostname, username, password, timeout=60, optional_args=None): - super().__init__(hostname, username, password, timeout, optional_args) self.patched_attrs = ["device"] diff --git a/test/iosxr_netconf/conftest.py b/test/iosxr_netconf/conftest.py index 20207985e..f623ee649 100644 --- a/test/iosxr_netconf/conftest.py +++ b/test/iosxr_netconf/conftest.py @@ -32,7 +32,6 @@ class PatchedIOSXRNETCONFDriver(iosxr_netconf.IOSXRNETCONFDriver): """Patched IOSXR NETCONF Driver.""" def __init__(self, hostname, username, password, timeout=60, optional_args=None): - super().__init__(hostname, username, password, timeout, optional_args) self.patched_attrs = ["device"] diff --git a/test/junos/TestJunOSDriver.py b/test/junos/TestJunOSDriver.py index c477bc541..fc1394803 100644 --- a/test/junos/TestJunOSDriver.py +++ b/test/junos/TestJunOSDriver.py @@ -116,7 +116,6 @@ def response(self, **rpc_args): return lxml.etree.fromstring(xml_string) def get_config(self, get_cmd=None, filter_xml=None, options={}): - # get_cmd is an XML tree that requests a specific part of the config # E.g.: diff --git a/test/junos/conftest.py b/test/junos/conftest.py index dc21dce60..31a7cad14 100644 --- a/test/junos/conftest.py +++ b/test/junos/conftest.py @@ -147,7 +147,6 @@ def response(self, **rpc_args): return lxml.etree.fromstring(xml_string) def get_config(self, get_cmd=None, filter_xml=None, options={}): - # get_cmd is an XML tree that requests a specific part of the config # E.g.: diff --git a/test/pyiosxr/test_iosxr.py b/test/pyiosxr/test_iosxr.py index b8485659d..1eedaeeec 100755 --- a/test/pyiosxr/test_iosxr.py +++ b/test/pyiosxr/test_iosxr.py @@ -142,7 +142,6 @@ def __repr__(self): @classmethod def setUpClass(cls): - """ Opens the connection with the IOS-XR device. """ @@ -165,7 +164,6 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - """ Closes the connection with the device. """ @@ -173,7 +171,6 @@ def tearDownClass(cls): cls.device.close() def test_mock_lock_connection_open(self): - if self.MOCK: self.device.lock_on_connect = True # because there's one single mock file @@ -184,7 +181,6 @@ def test_mock_lock_connection_open(self): # enough to see that will try to lock during connect def test_mock_close(self): - """Testing if unlocking when connection is closed""" if self.MOCK: @@ -193,7 +189,6 @@ def test_mock_close(self): self.assertFalse(self.device.locked, msg="Cannot unlock the DB.") def test_execute_rpc_method(self): - """Testing private method _execute_rpc""" self.assertIsInstance( @@ -205,7 +200,6 @@ def test_execute_rpc_method(self): ) def test__getttr__show_(self): - """Testing special attribute __getattr___ against valid show command""" self.assertIsInstance( @@ -215,13 +209,11 @@ def test__getttr__show_(self): ) def test__getttr__show_args(self): - """Testing special attribute __getattr___ against valid show command with arguments""" self.assertIsInstance(self.device.show_ntp("ass"), str) def test_acquire_xml_agent(self): - """Testing if able to acquire the XML agent.""" self.device._lock_xml_agent(time.time()) @@ -250,13 +242,11 @@ def test_in_cli_mode(self): self.assertTrue(self.device._in_cli_mode()) def test__getattr_show_config(self): - """Testing special attribute __getattr___ against valid show config command""" self.assertIsInstance(self.device.show_run_ntp(config=True), str) def test__getattr__no_show(self): - """Test special attribute __getattr__ against a no-show command""" raised = False @@ -269,7 +259,6 @@ def test__getattr__no_show(self): self.assertTrue(raised) def test_make_rpc_call_returns_XML(self): - """Test if public method make_rpc_call returns str""" self.assertIsInstance( @@ -298,7 +287,6 @@ def test_acquired_xml_agent(self): ) # Exception raised => xml agent released def test_try_to_read_till_timeout(self): - """Testing if will try to read from the device till time out""" if self.MOCK: @@ -309,7 +297,6 @@ def test_try_to_read_till_timeout(self): ) def test_multiple_read_attempts_till_timeout(self): - """Testing if will try to read non-empty replies from the device till time out""" if self.MOCK: @@ -320,7 +307,6 @@ def test_multiple_read_attempts_till_timeout(self): ) def test_iterator_id_raises_IteratorIDError(self): - """Testing if reply containing the IteratorID attribute raises IteratorIDError""" self.device.load_candidate_config(config="xml agent tty iteration on size 1") @@ -340,7 +326,6 @@ def test_iterator_id_raises_IteratorIDError(self): # going to prev state def test_channel_acquired_enter_xml_mode(self): - """Test if not raises ConnectError when the channel is busy with other requests""" self.device._lock_xml_agent() @@ -348,7 +333,6 @@ def test_channel_acquired_enter_xml_mode(self): self.assertIsNone(self.device._enter_xml_mode()) def test_truncated_response_raises_InvalidXMLResponse(self): - """Testing if truncated XML reply raises InvalidXMLResponse""" if self.MOCK: @@ -361,7 +345,6 @@ def test_truncated_response_raises_InvalidXMLResponse(self): ) def test_iosxr_bug_0x44318c06(self): - """Tests if IOS-XR bug returns error 0x44318c06 and raise XMLCLIError""" if self.MOCK: @@ -374,7 +357,6 @@ def test_iosxr_bug_0x44318c06(self): ) def test_empty_reply_raises_TimeoutError(self): - """Testing if empty reply raises TimeoutError""" if self.MOCK: @@ -383,7 +365,6 @@ def test_empty_reply_raises_TimeoutError(self): self.assertRaises(TimeoutError, self.device._execute_rpc, "") def test_multiple_requests_raise_0xa3679e00(self): - """Testing if simultaneuous requests trigger XMLCLIError""" if self.MOCK: @@ -397,25 +378,21 @@ def test_multiple_requests_raise_0xa3679e00(self): pass def test_execute_show(self): - """Testing private method _execute_show""" self.assertIsInstance(self.device._execute_show("show ntp ass"), str) def test_execute_invalid_show_raises_InvalidInputError(self): - """Testing if invalid show command raises InvalidInputError""" self.assertRaises(InvalidInputError, self.device._execute_show, "sh fake") def test_execute_config_show(self): - """Testing private method _execute_config_show""" self.assertIsInstance(self.device._execute_config_show("show run ntp"), str) def test_execute_invalid_config_show_raises_InvalidInputError(self): - """Testing if invalid config show command raises InvalidInputError""" self.assertRaises( @@ -423,7 +400,6 @@ def test_execute_invalid_config_show_raises_InvalidInputError(self): ) def test_lock_raises_LockError(self): - """Tests if DB already locked raises LockError""" if self.MOCK: @@ -455,7 +431,6 @@ def test_lock_raises_LockError(self): same_device.close() def test_unlock(self): - """Testing unlock feature""" if self.MOCK: @@ -475,7 +450,6 @@ def test_unlock(self): self.assertFalse(self.device.locked) def _load_dummy_config(self): - """Helper that loads some dummy data before committing.""" config = """ @@ -485,7 +459,6 @@ def _load_dummy_config(self): return self.device.load_candidate_config(config=config) def test_load_invalid_config_raises_InvalidInputError(self): - """Testing if loading config with mistakes raises InvalidInputError""" self.assertRaises( @@ -496,7 +469,6 @@ def test_load_invalid_config_raises_InvalidInputError(self): self.device.discard_config() def test_load_candidate_config_file(self): - """Testing loading candidate config from file""" self.assertIsNone( @@ -508,7 +480,6 @@ def test_load_candidate_config_file(self): ) def test_load_invalid_candidate_config_file_raises_InvalidInputError(self): - """Testing if loading invalid config from a file raises InvalidInputError""" self.assertRaises( @@ -520,7 +491,6 @@ def test_load_invalid_candidate_config_file_raises_InvalidInputError(self): ) def test_load_config(self): - """Testing if able to load candidate config, then check commit diff and discard changes""" self._load_dummy_config() @@ -563,7 +533,6 @@ def test_load_config(self): ) def test_commit_config(self): - """Testing commit config""" self._load_dummy_config() @@ -573,7 +542,6 @@ def test_commit_config(self): self.device.rollback() def test_commit_config_message(self): - """Testing commit config with comment message""" self._load_dummy_config() @@ -583,7 +551,6 @@ def test_commit_config_message(self): self.device.rollback() def test_commit_config_label(self): - """Testing commit config with label""" self._load_dummy_config() @@ -593,7 +560,6 @@ def test_commit_config_label(self): self.device.rollback() def test_commit_config_confirmed(self): - """Testing commit confirmed""" self._load_dummy_config() @@ -603,19 +569,16 @@ def test_commit_config_confirmed(self): self.device.rollback() def test_commit_config_confirmed_raise_InvalidInputError(self): - """Testing if incorrect value for confirm time raises InvalidInputError""" self.assertRaises(InvalidInputError, self.device.commit_config, confirmed=1) def test_commit_empty_buffer_raises(self): - """Testing if trying to commit empty changes raises CommitError""" self.assertRaises(CommitError, self.device.commit_config, comment="empty") def test_commit_after_other_session_commit(self): - """Testing if trying to commit after another process commited does not raise CommitError""" if self.MOCK: @@ -658,7 +621,6 @@ def test_commit_after_other_session_commit(self): self.device.open() def _prefetch_running_config_and_append(self): - """Helper method to be used in the config-replace tests below""" running_config = "".join(self.device.show_run().splitlines(1)[3:]) @@ -666,7 +628,6 @@ def _prefetch_running_config_and_append(self): self.device.load_candidate_config(config="ntp server 8.8.8.8") def test_compare_replace_config(self): - """Testing compare replace config""" self._prefetch_running_config_and_append() @@ -674,7 +635,6 @@ def test_compare_replace_config(self): self.assertIsInstance(self.device.compare_replace_config(), str) def test_commit_replace_config(self): - """Testing commit replace config""" self._prefetch_running_config_and_append() @@ -682,7 +642,6 @@ def test_commit_replace_config(self): self.assertIsNone(self.device.commit_replace_config()) def test_commit_replace_config_message(self): - """Testing commit replace config with comment message""" self._prefetch_running_config_and_append() @@ -690,7 +649,6 @@ def test_commit_replace_config_message(self): self.assertIsNone(self.device.commit_replace_config(comment="good")) def test_commit_replace_config_label(self): - """Testing commit replace config with label""" self._prefetch_running_config_and_append() @@ -698,7 +656,6 @@ def test_commit_replace_config_label(self): self.assertIsNone(self.device.commit_replace_config(label="test")) def test_commit_replace_config_confirmed(self): - """Testing commit replace confirmed""" self._prefetch_running_config_and_append() @@ -706,7 +663,6 @@ def test_commit_replace_config_confirmed(self): self.assertIsNone(self.device.commit_replace_config(confirmed=60)) def test_commit_replace_config_confirmed_raise_InvalidInputError(self): - """Testing if incorrect value for confirmed replace commit time raises InvalidInputError""" self.assertRaises( From b90f184177c773da4cb650e9394d80c5f620beed Mon Sep 17 00:00:00 2001 From: NoahFeinberg Date: Mon, 17 Jul 2023 19:25:37 -0500 Subject: [PATCH 52/76] Update nxos.py to expose file transfer errors (#1974) --- napalm/nxos/nxos.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index 09170074d..0b46da0dd 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -157,11 +157,11 @@ def load_replace_candidate( ) if not transfer_result["file_exists"]: raise ValueError() - except Exception: + except Exception as e: msg = ( "Could not transfer file. There was an error " "during transfer. Please make sure remote " - "permissions are set." + f"permissions are set. Caught Error:\n{repr(str(e))}" ) raise ReplaceConfigException(msg) From 94f96757b1c99f733ab89566f9f5bc67b6f134f0 Mon Sep 17 00:00:00 2001 From: Jonathan Senecal Date: Mon, 31 Jul 2023 15:20:12 -0400 Subject: [PATCH 53/76] Handle mac == "none" properly --- napalm/junos/junos.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index b12d09774..e92071011 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -1638,7 +1638,11 @@ def get_ipv6_neighbors_table(self): for ipv6_table_entry in ipv6_neighbors_table_items: ipv6_entry = {elem[0]: elem[1] for elem in ipv6_table_entry[1]} - ipv6_entry["mac"] = napalm.base.helpers.mac(ipv6_entry.get("mac")) + ipv6_entry["mac"] = ( + "" + if ipv6_entry.get("mac") == "none" + else napalm.base.helpers.mac(ipv6_entry.get("mac")) + ) ipv6_entry["ip"] = napalm.base.helpers.ip(ipv6_entry.get("ip")) ipv6_neighbors_table.append(ipv6_entry) From aba8cdffb1e69248b2914e0b4ea3898582efba23 Mon Sep 17 00:00:00 2001 From: Jonathan Senecal Date: Mon, 31 Jul 2023 16:21:37 -0400 Subject: [PATCH 54/76] Test for "none" in "mac" reply --- .../normal/expected_result.json | 31 ++++++++++++++++++- .../normal/get-ipv6-nd-information.xml | 11 ++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json index f8d983123..616e8c638 100644 --- a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json @@ -1 +1,30 @@ -[{"interface": "em0.0", "ip": "fd00:1111:1111::2", "mac": "FE:54:00:08:EE:00", "age": 884.0, "state": "stale"}, {"interface": "em0.0", "ip": "fd00:2222:2222::2", "mac": "FE:54:00:08:EE:00", "age": 8.0, "state": "reachable"}, {"interface": "em0.0", "ip": "fe80::24e6:6cff:fe85:9ecb", "mac": "FE:54:00:08:EE:00", "age": 850.0, "state": "stale"}] +[ + { + "interface": "em0.0", + "ip": "fd00:1111:1111::2", + "mac": "FE:54:00:08:EE:00", + "age": 884.0, + "state": "stale" + }, + { + "interface": "em0.0", + "ip": "fd00:2222:2222::2", + "mac": "FE:54:00:08:EE:00", + "age": 8.0, + "state": "reachable" + }, + { + "interface": "em0.0", + "ip": "fe80::24e6:6cff:fe85:9ecb", + "mac": "FE:54:00:08:EE:00", + "age": 850.0, + "state": "stale" + }, + { + "interface": "ae0.3", + "ip": "2001:db8::3", + "mac": "", + "age": 3.0, + "state": "unreachable" + } +] diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml index 0f26e0fac..9527a92a7 100644 --- a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml @@ -26,5 +26,14 @@ no em0.0 - 3 + + 2001:0DB8::3 + none + unreachable + 3 + no + no + ae0.3 + + 4 From f2df10585956c5049a64fb84fab442a2556b71f3 Mon Sep 17 00:00:00 2001 From: Jonathan Senecal Date: Tue, 1 Aug 2023 10:53:57 -0400 Subject: [PATCH 55/76] Use isinstance(list) instead of types comparison --- napalm/base/validate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napalm/base/validate.py b/napalm/base/validate.py index db5bbc257..21b4fc888 100644 --- a/napalm/base/validate.py +++ b/napalm/base/validate.py @@ -162,7 +162,7 @@ def compare( else: return src == dst - elif type(src) == type(dst) == list: + elif isinstance(src, list) and isinstance(dst, list): pairs = zip(src, dst) diff_lists = [ [(k, x[k], y[k]) for k in x if not re.search(x[k], y[k])] From af2600e2fe78e1d8f4c77d1d791c6ef8e840427f Mon Sep 17 00:00:00 2001 From: Jonathan Senecal Date: Tue, 1 Aug 2023 13:53:59 -0400 Subject: [PATCH 56/76] Revert "Test for "none" in "mac" reply" This reverts commit aba8cdffb1e69248b2914e0b4ea3898582efba23. --- .../normal/expected_result.json | 31 +------------------ .../normal/get-ipv6-nd-information.xml | 11 +------ 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json index 616e8c638..f8d983123 100644 --- a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/expected_result.json @@ -1,30 +1 @@ -[ - { - "interface": "em0.0", - "ip": "fd00:1111:1111::2", - "mac": "FE:54:00:08:EE:00", - "age": 884.0, - "state": "stale" - }, - { - "interface": "em0.0", - "ip": "fd00:2222:2222::2", - "mac": "FE:54:00:08:EE:00", - "age": 8.0, - "state": "reachable" - }, - { - "interface": "em0.0", - "ip": "fe80::24e6:6cff:fe85:9ecb", - "mac": "FE:54:00:08:EE:00", - "age": 850.0, - "state": "stale" - }, - { - "interface": "ae0.3", - "ip": "2001:db8::3", - "mac": "", - "age": 3.0, - "state": "unreachable" - } -] +[{"interface": "em0.0", "ip": "fd00:1111:1111::2", "mac": "FE:54:00:08:EE:00", "age": 884.0, "state": "stale"}, {"interface": "em0.0", "ip": "fd00:2222:2222::2", "mac": "FE:54:00:08:EE:00", "age": 8.0, "state": "reachable"}, {"interface": "em0.0", "ip": "fe80::24e6:6cff:fe85:9ecb", "mac": "FE:54:00:08:EE:00", "age": 850.0, "state": "stale"}] diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml index 9527a92a7..0f26e0fac 100644 --- a/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/normal/get-ipv6-nd-information.xml @@ -26,14 +26,5 @@ no em0.0 - - 2001:0DB8::3 - none - unreachable - 3 - no - no - ae0.3 - - 4 + 3 From 17900498f129f1155cc057db6709c6724365553d Mon Sep 17 00:00:00 2001 From: Jonathan Senecal Date: Tue, 1 Aug 2023 14:00:24 -0400 Subject: [PATCH 57/76] Test for "none" in "mac" reply --- .../mac_is_none/expected_result.json | 9 +++++++++ .../mac_is_none/get-ipv6-nd-information.xml | 12 ++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json create mode 100644 test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json new file mode 100644 index 000000000..7544d02e2 --- /dev/null +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json @@ -0,0 +1,9 @@ +[ + { + "interface": "ae0.3", + "ip": "2001:db8::3", + "mac": "", + "age": 3.0, + "state": "unreachable" + } +] \ No newline at end of file diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml new file mode 100644 index 000000000..edd1f35ff --- /dev/null +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml @@ -0,0 +1,12 @@ + + + 2001:0DB8::3 + none + unreachable + 3 + no + no + ae0.3 + + 1 + \ No newline at end of file From 832b411cb5c72e4f805c65393edea5b9cd833cb5 Mon Sep 17 00:00:00 2001 From: Jonathan Senecal Date: Tue, 1 Aug 2023 14:57:54 -0400 Subject: [PATCH 58/76] Missing newline --- .../mac_is_none/expected_result.json | 3 ++- .../mac_is_none/get-ipv6-nd-information.xml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json index 7544d02e2..b1b6648da 100644 --- a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/expected_result.json @@ -6,4 +6,5 @@ "age": 3.0, "state": "unreachable" } -] \ No newline at end of file +] + diff --git a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml index edd1f35ff..dca6b3db7 100644 --- a/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml +++ b/test/junos/mocked_data/test_get_ipv6_neighbors_table/mac_is_none/get-ipv6-nd-information.xml @@ -9,4 +9,5 @@ ae0.3 1 - \ No newline at end of file + + From cba44b7a534bc896572dbf6a9a3a7911cf34ed13 Mon Sep 17 00:00:00 2001 From: Chris Moore Date: Wed, 23 Aug 2023 12:46:43 -0500 Subject: [PATCH 59/76] fix call to lxml.etree._ElementTree.getparent (#1796) --- napalm/junos/junos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/napalm/junos/junos.py b/napalm/junos/junos.py index e92071011..631824ef6 100644 --- a/napalm/junos/junos.py +++ b/napalm/junos/junos.py @@ -1136,7 +1136,7 @@ def _process_pipe(cmd, txt): ) raw_txt = self.device.cli(safe_command, warning=False, format=encoding) if isinstance(raw_txt, etree._Element): - raw_txt = etree.tostring(raw_txt.get_parent()).decode() + raw_txt = etree.tostring(raw_txt.getparent()).decode() cli_output[str(command)] = raw_txt else: cli_output[str(command)] = str(_process_pipe(command, raw_txt)) From 480cc918aacbedc8cf21a47d9f0e5ed66069675b Mon Sep 17 00:00:00 2001 From: Ken Celenza Date: Fri, 1 Sep 2023 16:48:52 -0400 Subject: [PATCH 60/76] Update extend_driver.rst (#1998) --- docs/tutorials/extend_driver.rst | 44 +++++++++++++++++++------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/docs/tutorials/extend_driver.rst b/docs/tutorials/extend_driver.rst index ba4c8617c..9274ef6bb 100644 --- a/docs/tutorials/extend_driver.rst +++ b/docs/tutorials/extend_driver.rst @@ -44,22 +44,26 @@ Bulding on the previous example, we can create a a simple parse to return what o .. code-block:: python - def get_my_banner(self): - command = 'show banner motd' - output = self._send_command(command) - - return_vars = {} - for line in output.splitlines(): - split_line = line.split() - if "Site:" == split_line[0]: - return_vars["site"] = split_line[1] - elif "Device:" == split_line[0]: - return_vars["device"] = split_line[1] - elif "Floor:" == split_line[0]: - return_vars["floor"] = split_line[1] - elif "Room:" == split_line[0]: - return_vars["room"] = split_line[1] - return return_vars + from napalm.ios.ios import IOSDriver + class CustomIOSDriver(IOSDriver): + """Custom NAPALM Cisco IOS Handler.""" + + def get_my_banner(self): + command = 'show banner motd' + output = self._send_command(command) + + return_vars = {} + for line in output.splitlines(): + split_line = line.split() + if "Site:" == split_line[0]: + return_vars["site"] = split_line[1] + elif "Device:" == split_line[0]: + return_vars["device"] = split_line[1] + elif "Floor:" == split_line[0]: + return_vars["floor"] = split_line[1] + elif "Room:" == split_line[0]: + return_vars["room"] = split_line[1] + return return_vars Which can build. @@ -85,8 +89,12 @@ be able to support their own environment. .. code-block:: python - def get_my_banner(self): - raise NotImplementedError + from napalm.ios.ios import IOSDriver + class CustomIOSDriver(IOSDriver): + """Custom NAPALM Cisco IOS Handler.""" + + def get_my_banner(self): + raise NotImplementedError This feature is meant to allow for maximum amount of flexibility, but it is up to the user to ensure they do not run into namespace issues, and follow best practices. From d0ea70752054f81176bb333413501573e1605d9c Mon Sep 17 00:00:00 2001 From: Steve Kowalik Date: Thu, 7 Sep 2023 02:28:51 +1000 Subject: [PATCH 61/76] Remove future requirement (#2002) Now that we support Python >= 3.7, we can remove the requirement on the future module, which appears to be unused. --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 57ecd72eb..3359b30a6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,6 @@ setuptools>=38.4.0 cffi>=1.11.3 paramiko>=2.6.0 requests>=2.7.0 -future textfsm jinja2 netaddr From 3f166ce666b214bfd0db2b093d8783db17fee8d7 Mon Sep 17 00:00:00 2001 From: Sharky Date: Wed, 27 Sep 2023 14:55:15 +0200 Subject: [PATCH 62/76] Make get_vlans name whitespace aware , see #1789 --- napalm/ios/ios.py | 6 +++--- .../mocked_data/test_get_vlans/normal/expected_result.json | 7 ++++++- .../test_get_vlans/normal/show_vlan_all_ports.txt | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index df7a78400..048b3abdb 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -3722,7 +3722,7 @@ def get_vlans(self): return self._get_vlan_all_ports(output) def _get_vlan_all_ports(self, output): - find_regexp = re.compile(r"^(\d+)\s+(\S+)\s+\S+(\s+[A-Z][a-z].*)?$") + find_regexp = re.compile(r"^(\d+)\s+(.*?(?=active|act\/[isl]{1}shut|act\/unsup))\w+(?:\/\w+)?\S+(\s+[A-Z][a-z].*)?$") continuation_regexp = re.compile(r"^\s+([A-Z][a-z].*)$") output = output.splitlines() vlans = {} @@ -3736,7 +3736,7 @@ def _get_vlan_all_ports(self, output): if vlan_m: was_vlan_or_cont = True vlan_id = vlan_m.group(1) - vlan_name = vlan_m.group(2) + vlan_name = vlan_m.group(2).strip() interfaces = vlan_m.group(3) or "" vlans[vlan_id] = {"name": vlan_name, "interfaces": []} @@ -3763,7 +3763,7 @@ def _get_vlan_all_ports(self, output): def _get_vlan_from_id(self): command = "show vlan brief" output = self._send_command(command) - vlan_regexp = r"^(\d+)\s+(\S+)\s+\S+.*$" + vlan_regexp = r"^(\d+)\W+(.*?(?=active|act\/[isl]{1}shut|act\/unsup))" find_vlan = re.findall(vlan_regexp, output, re.MULTILINE) vlans = {} for vlan_id, vlan_name in find_vlan: diff --git a/test/ios/mocked_data/test_get_vlans/normal/expected_result.json b/test/ios/mocked_data/test_get_vlans/normal/expected_result.json index 9724b801b..96c41b948 100644 --- a/test/ios/mocked_data/test_get_vlans/normal/expected_result.json +++ b/test/ios/mocked_data/test_get_vlans/normal/expected_result.json @@ -1112,7 +1112,7 @@ ] }, "795": { - "name": "Vlan795", + "name": "Vlan 795", "interfaces": [ "Port-channel1", "Port-channel5", @@ -1194,5 +1194,10 @@ "1275": { "name": "Vlan1275", "interfaces": [] + }, + "1276": { + "name": "A1 - VIDEO", + "interfaces": ["Port-channel1"] } + } diff --git a/test/ios/mocked_data/test_get_vlans/normal/show_vlan_all_ports.txt b/test/ios/mocked_data/test_get_vlans/normal/show_vlan_all_ports.txt index 5f9850dd7..dd44f4549 100644 --- a/test/ios/mocked_data/test_get_vlans/normal/show_vlan_all_ports.txt +++ b/test/ios/mocked_data/test_get_vlans/normal/show_vlan_all_ports.txt @@ -64,12 +64,13 @@ VLAN Name Status Ports 790 Vlan790 active Po1, Po5, Po6, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 792 Vlan792 active Po1, Po2, Po5, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 794 Vlan794 active Po1, Po5, Po6, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 -795 Vlan795 active Po1, Po5, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 +795 Vlan 795 active Po1, Po5, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 1002 Vlan1002 act/unsup Po1, Po5, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 1003 Vlan1003 act/unsup Po1, Po5, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 1004 Vlan1004 act/unsup Po1, Po5, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 1005 Vlan1005 act/unsup Po1, Po5, Po21, Po22, Po23, Po24, Po25, Po26, Po27, Po28, Po30 1275 Vlan1275 active +1276 A1 - VIDEO active Po1 VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 ---- ----- ---------- ----- ------ ------ -------- ---- -------- ------ ------ @@ -141,6 +142,7 @@ VLAN Type SAID MTU Parent RingNo BridgeNo Stp BrdgMode Trans1 Trans2 1004 fdnet 101004 1500 - - - ieee - 0 0 1005 trnet 101005 1500 - - - ibm - 0 0 1275 enet 101275 1500 - - - - - 0 0 +1276 enet 101275 1500 - - - - - 0 0 Primary Secondary Type Ports ------- --------- ----------------- ------------------------------------------ From 638bbbeeedb805691bef25b7f9d8eeec5eb9338a Mon Sep 17 00:00:00 2001 From: Sharky Date: Wed, 27 Sep 2023 15:13:55 +0200 Subject: [PATCH 63/76] lets make black happy --- napalm/ios/ios.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 048b3abdb..22f17ff22 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -3722,7 +3722,9 @@ def get_vlans(self): return self._get_vlan_all_ports(output) def _get_vlan_all_ports(self, output): - find_regexp = re.compile(r"^(\d+)\s+(.*?(?=active|act\/[isl]{1}shut|act\/unsup))\w+(?:\/\w+)?\S+(\s+[A-Z][a-z].*)?$") + find_regexp = re.compile( + r"^(\d+)\s+(.*?(?=active|act\/[isl]{1}shut|act\/unsup))\w+(?:\/\w+)?\S+(\s+[A-Z][a-z].*)?$" + ) continuation_regexp = re.compile(r"^\s+([A-Z][a-z].*)$") output = output.splitlines() vlans = {} From a81ef592c0eb109d251474909fc15eecef72e5a3 Mon Sep 17 00:00:00 2001 From: Sharky Date: Wed, 27 Sep 2023 15:25:03 +0200 Subject: [PATCH 64/76] writing regex on multiple lines .... intersting , thanks liner --- napalm/ios/ios.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index 22f17ff22..d68cc82f4 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -3723,7 +3723,9 @@ def get_vlans(self): def _get_vlan_all_ports(self, output): find_regexp = re.compile( - r"^(\d+)\s+(.*?(?=active|act\/[isl]{1}shut|act\/unsup))\w+(?:\/\w+)?\S+(\s+[A-Z][a-z].*)?$" + r"^(\d+)\s+" # vlan id + "(.*?(?=active|act\/[isl]{1}shut|act\/unsup))" # vlan name + "\w+(?:\/\w+)?\S+(\s+[A-Z][a-z].*)?$" # ports ) continuation_regexp = re.compile(r"^\s+([A-Z][a-z].*)$") output = output.splitlines() From 56c1b80aa864401015c08968b04ed1f4bf6c4e64 Mon Sep 17 00:00:00 2001 From: Sharky Date: Wed, 27 Sep 2023 15:28:18 +0200 Subject: [PATCH 65/76] fix pylama w605 --- napalm/ios/ios.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index d68cc82f4..83ecf751a 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -3724,8 +3724,8 @@ def get_vlans(self): def _get_vlan_all_ports(self, output): find_regexp = re.compile( r"^(\d+)\s+" # vlan id - "(.*?(?=active|act\/[isl]{1}shut|act\/unsup))" # vlan name - "\w+(?:\/\w+)?\S+(\s+[A-Z][a-z].*)?$" # ports + r"(.*?(?=active|act\/[isl]{1}shut|act\/unsup))" # vlan name + r"\w+(?:\/\w+)?\S+(\s+[A-Z][a-z].*)?$" # ports ) continuation_regexp = re.compile(r"^\s+([A-Z][a-z].*)$") output = output.splitlines() From 392e5e8b9c5d893998f63e78ca757ac6b648b9c1 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Sat, 8 Jul 2023 14:52:24 -0500 Subject: [PATCH 66/76] eos: add explicit minimum version check Require 4.23.0F or later EOS image Require pyeapi >= 1.0.2 resolves #1958 Remove all references to FN0039 and any configuration alterations Remove text-based VRF parsing in favor of JSON version Update all tests to reflect --- napalm/base/exceptions.py | 4 + napalm/eos/eos.py | 57 +-- napalm/eos/pyeapi_syntax_wrapper.py | 42 -- napalm/eos/utils/cli_syntax.py | 359 ------------------ requirements.txt | 2 +- test/eos/conftest.py | 21 - test/eos/mocked_data/show_version.json | 32 +- .../issue-1922/expected_result.json | 30 -- .../issue-1922/show_vrf.text | 12 - .../issue-509/expected_result.json | 1 - .../issue-509/show_ip_interface.json | 279 -------------- .../issue-509/show_ipv6_interface.json | 6 - .../issue-509/show_vrf.text | 11 - .../issue-796/expected_result.json | 1 - .../issue-796/show_ip_interface.json | 66 ---- .../issue-796/show_ipv6_interface.json | 6 - .../issue-796/show_vrf.text | 9 - .../missing_v6/expected_result.json | 1 - .../missing_v6/show_ip_interface.json | 279 -------------- .../missing_v6/show_ipv6_interface.json | 6 - .../missing_v6/show_vrf.text | 14 - .../normal/expected_result.json | 32 +- .../normal/show_ip_interface.json | 279 -------------- .../normal/show_ipv6_interface.json | 6 - .../{vrf => normal}/show_vrf.json | 0 .../normal/show_vrf.text | 17 - .../vrf/cli_version.txt | 1 - .../vrf/expected_result.json | 31 -- .../iss_1069/expected_result.json | 27 +- .../test_get_route_to/iss_1069/show_vrf.json | 37 ++ .../test_get_route_to/iss_1069/show_vrf.text | 8 - .../iss_1347/expected_result.json | 269 ++++++++++++- .../test_get_route_to/iss_1347/show_vrf.json | 61 +++ .../test_get_route_to/iss_1347/show_vrf.text | 12 - .../iss_736/expected_result.json | 49 ++- .../test_get_route_to/iss_736/show_vrf.json | 24 ++ .../test_get_route_to/iss_736/show_vrf.text | 3 - .../normal/expected_result.json | 59 ++- ...te_vrf_default_1_0_4_0_24__bgp_detail.json | 2 +- .../test_get_route_to/normal/show_vrf.json | 44 +++ .../test_get_route_to/normal/show_vrf.text | 9 - .../normal/expected_result.json | 115 +++++- .../normal/show_vrf.json | 44 +++ .../normal/show_vrf.text | 6 - test/eos/test_cli_syntax.py | 51 --- test/eos/test_heredoc.py | 12 +- 46 files changed, 799 insertions(+), 1637 deletions(-) delete mode 100644 napalm/eos/pyeapi_syntax_wrapper.py delete mode 100644 napalm/eos/utils/cli_syntax.py delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-509/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-509/show_ip_interface.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-509/show_ipv6_interface.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-796/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-796/show_ip_interface.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-796/show_ipv6_interface.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/issue-796/show_vrf.text delete mode 100644 test/eos/mocked_data/test_get_network_instances/missing_v6/expected_result.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/missing_v6/show_vrf.text delete mode 100644 test/eos/mocked_data/test_get_network_instances/normal/show_ip_interface.json delete mode 100644 test/eos/mocked_data/test_get_network_instances/normal/show_ipv6_interface.json rename test/eos/mocked_data/test_get_network_instances/{vrf => normal}/show_vrf.json (100%) delete mode 100644 test/eos/mocked_data/test_get_network_instances/normal/show_vrf.text delete mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt delete mode 100644 test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json create mode 100644 test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.json delete mode 100644 test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.text create mode 100644 test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.json delete mode 100644 test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.text create mode 100644 test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.json delete mode 100644 test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.text create mode 100644 test/eos/mocked_data/test_get_route_to/normal/show_vrf.json delete mode 100644 test/eos/mocked_data/test_get_route_to/normal/show_vrf.text create mode 100644 test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.json delete mode 100644 test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.text delete mode 100644 test/eos/test_cli_syntax.py diff --git a/napalm/base/exceptions.py b/napalm/base/exceptions.py index c889ee006..4c39656f7 100644 --- a/napalm/base/exceptions.py +++ b/napalm/base/exceptions.py @@ -67,6 +67,10 @@ class ConnectionClosedException(ConnectionException): pass +class UnsupportedVersion(ConnectionException): + pass + + class ReplaceConfigException(NapalmException): pass diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 52db5463b..37db5a8d1 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -47,11 +47,10 @@ ReplaceConfigException, SessionLockedException, CommandErrorException, + UnsupportedVersion, ) from napalm.eos.constants import LLDP_CAPAB_TRANFORM_TABLE -from napalm.eos.pyeapi_syntax_wrapper import Node from napalm.eos.utils.versions import EOSVersion -from napalm.eos.utils.cli_syntax import cli_convert import napalm.base.constants as c # local modules @@ -123,7 +122,6 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.timeout = timeout self.config_session = None self.locked = False - self.cli_version = 1 self.platform = "eos" self.profile = [self.platform] @@ -131,7 +129,6 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.enablepwd = self.optional_args.pop("enable_password", "") self.eos_autoComplete = self.optional_args.pop("eos_autoComplete", None) - self.fn0039_config = self.optional_args.pop("eos_fn0039_config", False) # Define locking method self.lock_disable = self.optional_args.pop("lock_disable", False) @@ -201,10 +198,6 @@ def open(self): device_type="arista_eos", netmiko_optional_args=self.netmiko_optional_args, ) - # let's try to determine if we need to use new EOS cli syntax - sh_ver = self._run_commands(["show version"]) - if EOSVersion(sh_ver[0]["version"]) >= EOSVersion("4.23.0"): - self.cli_version = 2 else: try: connection = self.transport_class( @@ -216,22 +209,24 @@ def open(self): ) if self.device is None: - self.device = Node(connection, enablepwd=self.enablepwd) + self.device = pyeapi.client.Node( + connection, enablepwd=self.enablepwd + ) # does not raise an Exception if unusable - # let's try to determine if we need to use new EOS cli syntax - sh_ver = self.device.run_commands(["show version"]) - self.cli_version = ( - 2 if EOSVersion(sh_ver[0]["version"]) >= EOSVersion("4.23.0") else 1 - ) - - self.device.update_cli_version(self.cli_version) except ConnectionError as ce: # and this is raised either if device not avaiable # either if HTTP(S) agent is not enabled # show management api http-commands raise ConnectionException(str(ce)) + # endif self.transport + + sh_ver = self._run_commands(["show version"]) + self._eos_version = EOSVersion(sh_ver[0]["version"]) + if self._eos_version < EOSVersion("4.23.0"): + raise UnsupportedVersion(self._eos_version) + def close(self): """Implementation of NAPALM method close.""" self.discard_config() @@ -263,11 +258,6 @@ def is_alive(self): def _run_commands(self, commands, **kwargs): if self.transport == "ssh": - if self.fn0039_config: - if isinstance(commands, str): - commands = [cli_convert(commands, self.cli_version)] - else: - commands = [cli_convert(cmd, self.cli_version) for cmd in commands] ret = [] for command in commands: if kwargs.get("encoding") == "text": @@ -463,10 +453,9 @@ def _load_config(self, filename=None, config=None, replace=True): self._run_commands( commands, autoComplete=self.eos_autoComplete, - fn0039_transform=self.fn0039_config, ) else: - self._run_commands(commands, fn0039_transform=self.fn0039_config) + self._run_commands(commands) except pyeapi.eapilib.CommandError as e: self.discard_config() msg = str(e) @@ -1527,23 +1516,14 @@ def get_route_to(self, destination="", protocol="", longer=False): nexthop_interface_map[nexthop_ip] = next_hop.get("interface") metric = route_details.get("metric") if _vrf not in vrf_cache.keys(): - if self.cli_version == 1: - command = "show ip{ipv} bgp {dest} {longer} detail vrf {_vrf}".format( + command = ( + "show ip{ipv} bgp {dest} {longer} detail vrf {_vrf}".format( ipv=ipv, dest=destination, longer="longer-prefixes" if longer else "", _vrf=_vrf, ) - else: - # Newer EOS can't mix longer-prefix and detail - command = ( - "show ip{ipv} bgp {dest} {longer} vrf {_vrf}".format( - ipv=ipv, - dest=destination, - longer="longer-prefixes" if longer else "", - _vrf=_vrf, - ) - ) + ) vrf_cache.update( { _vrf: self._run_commands([command])[0] @@ -2169,18 +2149,13 @@ def _show_vrf_text(self): return vrfs def _show_vrf(self): - if self.cli_version == 2: - return self._show_vrf_json() - else: - return self._show_vrf_text() + return self._show_vrf_json() def _get_vrfs(self): output = self._show_vrf() vrfs = [str(vrf["name"]) for vrf in output] - vrfs.append("default") - return vrfs def get_network_instances(self, name=""): diff --git a/napalm/eos/pyeapi_syntax_wrapper.py b/napalm/eos/pyeapi_syntax_wrapper.py deleted file mode 100644 index c240df3d4..000000000 --- a/napalm/eos/pyeapi_syntax_wrapper.py +++ /dev/null @@ -1,42 +0,0 @@ -"""pyeapi wrapper to fix cli syntax change""" -import pyeapi -from napalm.eos.utils.cli_syntax import cli_convert - - -class Node(pyeapi.client.Node): - """ - pyeapi node wrapper to fix cli syntax change - """ - - def __init__(self, *args, **kwargs): - if "cli_version" in kwargs: - self.cli_version = kwargs["cli_version"] - del kwargs["cli_version"] - else: - self.cli_version = 1 - - super(Node, self).__init__(*args, **kwargs) - - def update_cli_version(self, version): - """ - Update CLI version number for this device - :param version: int: version number - :return: None - """ - self.cli_version = version - - def run_commands(self, commands, *args, **kwargs): - """ - Run commands wrapper - :param commands: list of commands - :param kwargs: other args - :return: list of outputs - """ - fn0039_transform = kwargs.pop("fn0039_transform", True) - if fn0039_transform: - if isinstance(commands, str): - commands = [cli_convert(commands, self.cli_version)] - else: - commands = [cli_convert(cmd, self.cli_version) for cmd in commands] - - return super(Node, self).run_commands(commands, *args, **kwargs) diff --git a/napalm/eos/utils/cli_syntax.py b/napalm/eos/utils/cli_syntax.py deleted file mode 100644 index d4445fb01..000000000 --- a/napalm/eos/utils/cli_syntax.py +++ /dev/null @@ -1,359 +0,0 @@ -""" -EOS CLI syntax changes -""" -CLI_SYNTAX = { - # Default CLI syntax version - # We do trandlation from 4.23.0 syntax to pre-4.23.0 syntax - 1: { - "aaa authorization serial-console": "aaa authorization console", - "area not-so-stubby lsa type-7 convert type-5": "area nssa translate type7 always", - "arp aging timeout": "arp timeout", - "bfd default": "bfd all-interfaces", - "dynamic peer max": "bgp listen limit", - "class-map type copp": "class-map type control-plane", - "clear arp": "clear ip arp", - "clear ip nat flow translation": "clear ip nat translation", - "clear ospfv3 ipv6 force-spf": "clear ipv6 ospf force-spf", - "system control-plane": "control-plane", - "metric default": "default-metric", - "dot1x reauthorization request limit ": "dot1x max-reauth-req", - "enable password": "enable secret", - "delete startup-config": "erase startup-config", - "errdisable detect cause link-change": "errdisable detect cause link-flap", - "ip community-list regexp": "ip community-list expanded", - "ip dhcp relay all-subnets": "ip dhcp smart-relay", - "ip dhcp relay all-subnets default": "ip dhcp smart-relay global", - "dns domain": "ip domain-name", - "ip extcommunity-list regexp": "ip extcommunity-list expanded", - "ip extcommunity-list": "ip extcommunity-list standard", - "ip http client local-interface": "ip http client source-interface", - "query-max-response-time": "ip igmp query-max-response-time", - "ip igmp snooping vlan fast-leave": "ip igmp snooping vlan immediate-leave", - "ip igmp snooping vlan multicast-router": "ip igmp snooping vlan mrouter", - "ip igmp snooping vlan member": "ip igmp snooping vlan static", - # disabled next command because of ambiguity - # 'default-peer': 'ip msdp default-peer', - # disabled next command because of ambiguity - # 'description': 'ip msdp description', - "sa-limit": "ip msdp group-limit", - # disabled next command because of ambiguity - # 'keepalive': 'ip msdp keepalive', - "mesh-group": "ip msdp mesh-group", - "originator-id local-interface": "ip msdp originator-id", - # disabled next command because of ambiguity - # 'peer': 'ip msdp peer', - "sa filter in": "ip msdp sa-filter in", - "sa filter out": "ip msdp sa-filter out", - "sa limit": "ip msdp sa-limit", - # disabled next command because of ambiguity - # 'disabled': 'ip msdp shutdown', - "connection retry interval": "ip msdp timer", - "ip ospf neighbor bfd": "ip ospf bfd", - "router-id output-format hostnames": "ip ospf name-lookup", - "ip ospf disabled": "ip ospf shutdown", - "anycast-rp": "ip pim anycast-rp", - # disabled next command because of ambiguity - # 'bfd': 'ip pim bfd', - "pim bfd": "ip pim bfd-instance", - "pim bsr border": "ip pim bsr-border", - "log neighbors": "ip pim log-neighbor-changes", - "pim neighbor filter": "ip pim neighbor-filter", - "pim hello interval": "ip pim query-interval", - "register local-interface": "ip pim register-source", - "spt threshold match list": "ip pim spt-threshold group-list", - "ssm address range": "ip pim ssm range", - "rip v2 multicast disable": "ip rip v2-broadcast", - "ipv6 nd ra disabled": "ipv6 nd ra suppress", - "ospfv3 ipv6 retransmit-interval": "ipv6 ospf retransmit-interval", - "isis lsp tx interval": "isis lsp-interval", - # disabled next command because of ambiguity - # 'passive': 'passive-interface', - "lacp timer": "lacp rate", - "link tracking group ": "link state track", - "lldp hold-time": "lldp holdtime", - "lldp timer reinitialization": "lldp reinit", - "lldp tlv transmit": "lldp tlv-select", - "neighbor bfd": "neighbor fall-over bfd", - "neighbor peer group": "neighbor peer-group", - "neighbor rib-in pre-policy retain": "neighbor soft-reconfiguration", - "neighbor passive": "neighbor transport connection-mode", - "ntp local-interface": "ntp source", - "policy-map type copp": "policy-map type control-plane", - "policy-map type quality-of-service": "policy-map type qos", - "priority-flow-control": "priority-flow-control mode", - "pvlan mapping": "private-vlan mapping", - "ptp sync-message interval": "ptp sync interval", - "redundancy manual switchover": "redundancy force-switchover", - "cli vrf ": "routing-context vrf", - "logging format sequence-numbers": "service sequence-numbers", - "show aaa methods": "show aaa method-lists", - "show users detail": "show aaa sessions", - "show bfd peers": "show bfd neighbors", - "show dot1x all brief": "show dot1x all summary", - "show system environment all": "show environment all", - "show system environment cooling": "show environment cooling", - "show system environment temperature": "show environment temperature", - "show interfaces hardware": "show interfaces capabilities", - "show interfaces flow-control": "show interfaces flowcontrol", - "show pvlan mapping interfaces": "show interfaces private-vlan mapping", - "show interfaces switchport backup-link": "show interfaces switchport backup", - "show igmp snooping querier": "show ip igmp snooping querier", - "show multicast fib ipv4": "show ip mfib", - "show msdp mesh-group": "show ip msdp mesh-group", - "show msdp rpf-peer": "show ip msdp rpf-peer", - "show ip ospf request queue": "show ip ospf request-list", - "show ip ospf retransmission queue": "show ip ospf retransmission-list", - "show ip route match tag": "show ip route tag", - "show ipv6 bgp match community": "show ipv6 bgp community", - "show ipv6 bgp peers": "show ipv6 bgp neighbors", - "show ipv6 route match tag": "show ipv6 route tag", - "show isis network topology": "show isis topology", - "show lacp peer": "show lacp neighbor", - "show link tracking group": "show link state group", - "show lldp counters": "show lldp traffic", - "show bridge mac-address-table aging timeout": "show mac-address-table aging-time", - "show policy-map type copp": "show policy-map control-plane", - "show policy-map copp": "show policy-map interface control-plane", - "show port-channel dense": "show port-channel summary", - "show port-channel load-balance": "show port-channel traffic", - "show port-security mac-address": "show port-security address", - "show ptp local-clock": "show ptp clock", - "show ptp masters": "show ptp parent", - "show ptp local-clock time properties": "show ptp time-property", - "show redundancy status": "show redundancy states", - "show users roles": "show role", - "show snmp v2-mib chassis": "show snmp chassis", - "show snmp v2-mib contact": "show snmp contact", - "show snmp notification host": "show snmp host", - "show snmp v2-mib location": "show snmp location", - "show snmp local-interface": "show snmp source-interface", - "show snmp notification": "show snmp trap", - "show spanning-tree instance": "show spanning-tree bridge", - "show users accounts": "show user-account", - "show vlan brief count": "show vlan summary", - "snmp trap link-change": "snmp trap link-status", - "snmp-server local-interface": "snmp-server source-interface", - "spanning-tree transmit active": "spanning-tree bridge assurance", - "spanning-tree guard loop default": "spanning-tree loopguard default", - "spanning-tree edge-port bpdufilter default": "spanning-tree portfast bpdufilter default", - "spanning-tree edge-port bpduguard default": "spanning-tree portfast bpduguard default", - "spanning-tree bpdu tx hold-count": "spanning-tree transmit hold-count", - "spanning-tree vlan-id": "spanning-tree vlan", - "counters per-entry": "statistics per-entry", - "switchport backup-link": "switchport backup interface", - "switchport port-security mac-address maximum": "switchport port-security maximum", - "switchport vlan translation": "switchport vlan mapping", - # disabled next command because of ambiguity - # 'timers': 'timers basic', - "timers lsa rx min interval": "timers lsa arrival", - "timers lsa tx delay initial": "timers throttle lsa all", - "timers spf delay initial": "timers throttle spf", - "username ssh-key": "username sshkey", - "vlan internal order": "vlan internal allocation policy", - "vrf instance": "vrf definition", - # disabled next command because of ambiguity - # 'vrf': 'vrf forwarding', - "vrrp peer authentication": "vrrp authentication", - "vrrp timers delay reload": "vrrp delay reload", - "vrrp session description": "vrrp description", - "vrrp ipv4": "vrrp ip", - "vrrp ipv4 secondary": "vrrp ip secondary", - "vrrp priority-level": "vrrp priority", - "vrrp disabled": "vrrp shutdown", - "vrrp advertisement interval": "vrrp timers advertise", - "vrrp tracked-object": "vrrp track", - }, - # CLI syntax version after EOS 4.23.0 - 2: { - "aaa authorization console": "aaa authorization serial-console", - "area nssa translate type7 always": "area not-so-stubby lsa type-7 convert type-5", - "arp timeout": "arp aging timeout", - "bfd all-interfaces": "bfd default", - "bgp listen limit": "dynamic peer max", - "class-map type control-plane": "class-map type copp", - "clear ip arp": "clear arp", - "clear ip nat translation": "clear ip nat flow translation", - "clear ipv6 ospf force-spf": "clear ospfv3 ipv6 force-spf", - "control-plane": "system control-plane", - "default-metric": "metric default", - "dot1x max-reauth-req": "dot1x reauthorization request limit ", - "enable secret": "enable password", - "erase startup-config": "delete startup-config", - "errdisable detect cause link-flap": "errdisable detect cause link-change", - "ip community-list expanded": "ip community-list regexp", - "ip dhcp smart-relay": "ip dhcp relay all-subnets", - "ip dhcp smart-relay global": "ip dhcp relay all-subnets default", - "ip domain-name": "dns domain", - "ip extcommunity-list expanded": "ip extcommunity-list regexp", - "ip extcommunity-list standard": "ip extcommunity-list", - "ip http client source-interface": "ip http client local-interface", - "ip igmp query-max-response-time": "query-max-response-time", - "ip igmp snooping vlan immediate-leave": "ip igmp snooping vlan fast-leave", - "ip igmp snooping vlan mrouter": "ip igmp snooping vlan multicast-router", - "ip igmp snooping vlan static": "ip igmp snooping vlan member", - "ip msdp default-peer": "default-peer", - "ip msdp description": "description", - "ip msdp group-limit": "sa-limit", - "ip msdp keepalive": "keepalive", - "ip msdp mesh-group": "mesh-group", - "ip msdp originator-id": "originator-id local-interface", - "ip msdp peer": "peer", - "ip msdp sa-filter in": "sa filter in", - "ip msdp sa-filter out": "sa filter out", - "ip msdp sa-limit": "sa limit", - "ip msdp shutdown": "disabled", - "ip msdp timer": "connection retry interval", - "ip ospf bfd": "ip ospf neighbor bfd", - "ip ospf name-lookup": "router-id output-format hostnames", - "ip ospf shutdown": "ip ospf disabled", - "ip pim anycast-rp": "anycast-rp", - "ip pim bfd": "bfd", - "ip pim bfd-instance": "pim bfd", - "ip pim bsr-border": "pim bsr border", - "ip pim log-neighbor-changes": "log neighbors", - "ip pim neighbor-filter": "pim neighbor filter", - "ip pim query-interval": "pim hello interval", - "ip pim register-source": "register local-interface", - "ip pim spt-threshold group-list": "spt threshold match list", - "ip pim ssm range": "ssm address range", - "ip rip v2-broadcast": "rip v2 multicast disable", - "ipv6 nd ra suppress": "ipv6 nd ra disabled", - "ipv6 ospf retransmit-interval": "ospfv3 ipv6 retransmit-interval", - "isis lsp-interval": "isis lsp tx interval", - "passive-interface": "passive", - "lacp rate": "lacp timer", - "link state track": "link tracking group ", - "lldp holdtime": "lldp hold-time", - "lldp reinit": "lldp timer reinitialization", - "lldp tlv-select": "lldp tlv transmit", - "neighbor fall-over bfd": "neighbor bfd", - "neighbor peer-group": "neighbor peer group", - "neighbor soft-reconfiguration": "neighbor rib-in pre-policy retain", - "neighbor transport connection-mode": "neighbor passive", - "ntp source": "ntp local-interface", - "policy-map type control-plane": "policy-map type copp", - "policy-map type qos": "policy-map type quality-of-service", - "priority-flow-control mode": "priority-flow-control", - "private-vlan mapping": "pvlan mapping", - "ptp sync interval": "ptp sync-message interval", - "redundancy force-switchover": "redundancy manual switchover", - "routing-context vrf": "cli vrf ", - "service sequence-numbers": "logging format sequence-numbers", - "show aaa method-lists": "show aaa methods", - "show aaa sessions": "show users detail", - "show bfd neighbors": "show bfd peers", - "show dot1x all summary": "show dot1x all brief", - "show environment all": "show system environment all", - "show environment cooling": "show system environment cooling", - "show environment temperature": "show system environment temperature", - "show interfaces capabilities": "show interfaces hardware", - "show interfaces flowcontrol": "show interfaces flow-control", - "show interfaces private-vlan mapping": "show pvlan mapping interfaces", - "show interfaces switchport backup": "show interfaces switchport backup-link", - "show ip igmp snooping querier": "show igmp snooping querier", - "show ip mfib": "show multicast fib ipv4", - "show ip msdp mesh-group": "show msdp mesh-group", - "show ip msdp rpf-peer": "show msdp rpf-peer", - "show ip ospf request-list": "show ip ospf request queue", - "show ip ospf retransmission-list": "show ip ospf retransmission queue", - "show ip route tag": "show ip route match tag", - "show ipv6 bgp community": "show ipv6 bgp match community", - "show ipv6 bgp neighbors": "show ipv6 bgp peers", - "show ipv6 route tag": "show ipv6 route match tag", - "show isis topology": "show isis network topology", - "show lacp neighbor": "show lacp peer", - "show link state group": "show link tracking group", - "show lldp traffic": "show lldp counters", - "show mac-address-table aging-time": "show bridge mac-address-table aging timeout", - "show policy-map control-plane": "show policy-map type copp", - "show policy-map interface control-plane": "show policy-map copp", - "show port-channel summary": "show port-channel dense", - "show port-channel traffic": "show port-channel load-balance", - "show port-security address": "show port-security mac-address", - "show ptp clock": "show ptp local-clock", - "show ptp parent": "show ptp masters", - "show ptp time-property": "show ptp local-clock time properties", - "show redundancy states": "show redundancy status", - "show role": "show users roles", - "show snmp chassis": "show snmp v2-mib chassis", - "show snmp contact": "show snmp v2-mib contact", - "show snmp host": "show snmp notification host", - "show snmp location": "show snmp v2-mib location", - "show snmp source-interface": "show snmp local-interface", - "show snmp trap": "show snmp notification", - "show spanning-tree bridge": "show spanning-tree instance", - "show user-account": "show users accounts", - "show vlan summary": "show vlan brief count", - "snmp trap link-status": "snmp trap link-change", - "snmp-server source-interface": "snmp-server local-interface", - "spanning-tree bridge assurance": "spanning-tree transmit active", - "spanning-tree loopguard default": "spanning-tree guard loop default", - "spanning-tree portfast bpdufilter default": "spanning-tree edge-port bpdufilter default", - "spanning-tree portfast bpduguard default": "spanning-tree edge-port bpduguard default", - "spanning-tree transmit hold-count": "spanning-tree bpdu tx hold-count", - "spanning-tree vlan": "spanning-tree vlan-id", - "statistics per-entry": "counters per-entry", - "switchport backup interface": "switchport backup-link", - "switchport port-security maximum": "switchport port-security mac-address maximum", - "switchport vlan mapping": "switchport vlan translation", - "timers basic": "timers", - "timers lsa arrival": "timers lsa rx min interval", - "timers throttle lsa all": "timers lsa tx delay initial", - "timers throttle spf": "timers spf delay initial", - "username sshkey": "username ssh-key", - "vlan internal allocation policy": "vlan internal order", - "vrf definition": "vrf instance", - "vrf forwarding": "vrf", - "vrrp authentication": "vrrp peer authentication", - "vrrp delay reload": "vrrp timers delay reload", - "vrrp description": "vrrp session description", - "vrrp ip": "vrrp ipv4", - "vrrp ip secondary": "vrrp ipv4 secondary", - "vrrp priority": "vrrp priority-level", - "vrrp shutdown": "vrrp disabled", - "vrrp timers advertise": "vrrp advertisement interval", - "vrrp track": "vrrp tracked-object", - }, -} - - -class CliConverter: - """ - ClI converter class - """ - - def __init__(self, syntax): - """ - Object creation - :param syntax: syntax dict - """ - self.syntax = syntax - - def convert(self, command, version): - """ - Convert command from version 1 to specified version - :param command: str: command - :param version: int: version number - :return: str: command - """ - if version not in self.syntax: - return command - - for c in self.syntax[version]: - if command.startswith(c): - return self.syntax[version][c] + command[len(c) :] - - return command - - -CONVERTER = CliConverter(CLI_SYNTAX) - - -def cli_convert(command, version): - """ - Convert command from CLI version 1 to one from CLI of specified version - :param command: str: CLI command - :param version: int: EOS CLI version number - :return: str: command - """ - return CONVERTER.convert(command, version) diff --git a/requirements.txt b/requirements.txt index 3359b30a6..b7a20077a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ textfsm jinja2 netaddr pyYAML -pyeapi>=0.8.2 +pyeapi>=1.0.2 netmiko>=4.1.0 junos-eznc>=2.6.3 scp diff --git a/test/eos/conftest.py b/test/eos/conftest.py index aff8e78a1..d35204fe9 100644 --- a/test/eos/conftest.py +++ b/test/eos/conftest.py @@ -37,19 +37,6 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None) self.patched_attrs = ["device"] self.device = FakeEOSDevice() - self._cli_version = 1 - - @property - def cli_version(self): - try: - full_path = self.device.find_file("cli_version.txt") - except IOError: - return self._cli_version - return int(self.device.read_txt_file(full_path)) - - @cli_version.setter - def cli_version(self, value): - self._cli_version = value class FakeEOSDevice(BaseTestDouble): @@ -73,11 +60,3 @@ def run_commands(self, command_list, encoding="json"): result.append({"output": self.read_txt_file(full_path)}) return result - - def update_cli_version(self, version): - """ - Update CLI version number for this device - :param version: int: version number - :return: None - """ - self.cli_version = version diff --git a/test/eos/mocked_data/show_version.json b/test/eos/mocked_data/show_version.json index 092d29bce..4a1957a37 100644 --- a/test/eos/mocked_data/show_version.json +++ b/test/eos/mocked_data/show_version.json @@ -1,16 +1,22 @@ { - "memTotal": 3954980, - "uptime": 200478.31, - "modelName": "DCS-7150S-64-CL-R", - "internalVersion": "4.21.8M-2GB-13902577.4218M", "mfgName": "Arista", - "serialNumber": "JPE00000000", - "systemMacAddress": "00:1c:73:00:00:00", - "bootupTimestamp": 1588135848.0, - "memFree": 2558364, - "version": "4.21.8M-2GB", - "architecture": "i386", - "isIntlVersion": false, - "internalBuildId": "5af75062-ded5-4c99-8f44-daa88aa4414d", - "hardwareRevision": "01.03" + "modelName": "cEOSLab", + "hardwareRevision": "", + "serialNumber": "DE5B7D98C24A207BE70876CC0AD5546F", + "systemMacAddress": "00:1c:73:78:8e:81", + "hwMacAddress": "00:00:00:00:00:00", + "configMacAddress": "00:00:00:00:00:00", + "version": "4.30.0F-31408673.4300F (engineering build)", + "architecture": "x86_64", + "internalVersion": "4.30.0F-31408673.4300F", + "internalBuildId": "a35f0dc7-2d65-4f2a-a010-279cf445fd8c", + "imageFormatVersion": "1.0", + "imageOptimization": "None", + "cEosToolsVersion": "(unknown)", + "kernelVersion": "5.15.0-56-generic", + "bootupTimestamp": 1688840924.7556078, + "uptime": 374.72549414634705, + "memTotal": 231066228, + "memFree": 222939448, + "isIntlVersion": false } diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json b/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json deleted file mode 100644 index 413d219c4..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-1922/expected_result.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "management": { - "name": "management", - "type": "L3VRF", - "state": { "route_distinguisher": "" }, - "interfaces": { "interface": { "Management1": {} } } - }, - "default": { - "interfaces": { - "interface": { - "Ethernet1": {}, - "Ethernet2": {}, - "Ethernet3": {}, - "Ethernet4": {}, - "Ethernet49/1": {}, - "Ethernet5": {}, - "Ethernet50/1": {}, - "Ethernet52/1": {}, - "Ethernet53/1": {}, - "Ethernet54/1": {}, - "Ethernet55/1": {}, - "Ethernet56/1": {}, - "Loopback0": {} - } - }, - "state": { "route_distinguisher": "" }, - "type": "DEFAULT_INSTANCE", - "name": "default" - } -} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text deleted file mode 100644 index cd1dbbba4..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-1922/show_vrf.text +++ /dev/null @@ -1,12 +0,0 @@ -Maximum number of vrfs allowed: 1023 - VRF RD Protocols State Interfaces ----------------- --------------- --------------- ------------------- --------------------------- - default ipv4,ipv6 v4:routing, Ethernet1, Ethernet2, - v6:no routing Ethernet3, Ethernet4, - Ethernet49/1, Ethernet5, - Ethernet50/1, Ethernet52/1, - Ethernet53/1, Ethernet54/1, - Ethernet55/1, Ethernet56/1, - Loopback0 - management ipv4,ipv6 v4:routing, Management1 - v6:no routing diff --git a/test/eos/mocked_data/test_get_network_instances/issue-509/expected_result.json b/test/eos/mocked_data/test_get_network_instances/issue-509/expected_result.json deleted file mode 100644 index 14f3b574a..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-509/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{"VRFA0": {"name": "VRFA0", "type": "L3VRF", "state": {"route_distinguisher": "201:201"}, "interfaces": {"interface": {"Vlan2": {}, "Vlan102": {}}}}, "VRFA1": {"name": "VRFA1", "type": "L3VRF", "state": {"route_distinguisher": "203:203"}, "interfaces": {"interface": {"Vlan3": {}, "Vlan103": {}}}}, "VRFA2": {"name": "VRFA2", "type": "L3VRF", "state": {"route_distinguisher": "205:205"}, "interfaces": {"interface": {"Ethernet1": {}, "Vlan100": {}}}}, "default": {"name": "default", "type": "DEFAULT_INSTANCE", "state": {"route_distinguisher": ""}, "interfaces": {"interface": {"Management1": {}, "Ethernet3": {}, "Vlan4": {}, "Vlan101": {}, "Vlan104": {}}}}} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-509/show_ip_interface.json b/test/eos/mocked_data/test_get_network_instances/issue-509/show_ip_interface.json deleted file mode 100644 index a697ecf52..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-509/show_ip_interface.json +++ /dev/null @@ -1,279 +0,0 @@ -{ - "interfaces": { - "Management1": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 23, - "address": "10.192.100.98" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Management1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "default", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Vlan3": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan3", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Ethernet3": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Ethernet3", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "default", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Ethernet1": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Ethernet1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Vlan103": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan103", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan102": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan102", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan2": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan2", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan100": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan100", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan4": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan4", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan101": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan101", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan104": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan104", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - } - } -} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-509/show_ipv6_interface.json b/test/eos/mocked_data/test_get_network_instances/issue-509/show_ipv6_interface.json deleted file mode 100644 index 582256041..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-509/show_ipv6_interface.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "interfaces": {}, - "errors": [ - "No IPv6 configured interfaces" - ] -} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text deleted file mode 100644 index 65fdb6529..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-509/show_vrf.text +++ /dev/null @@ -1,11 +0,0 @@ -Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- --------- ------------ ------------------------ ------------------- - VRFA0 201:201 ipv4 v4:routing; multicast, Vlan2, Vlan102 - v6:no routing - - VRFA1 203:203 ipv4 v4:routing; multicast, Vlan3, Vlan103 - v6:no routing - - VRFA2 205:205 ipv4 v4:routing; multicast, Ethernet1, Vlan100 - v6:no routing diff --git a/test/eos/mocked_data/test_get_network_instances/issue-796/expected_result.json b/test/eos/mocked_data/test_get_network_instances/issue-796/expected_result.json deleted file mode 100644 index 11370a1ce..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-796/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{"ABC": {"name": "ABC", "type": "L3VRF", "state": {"route_distinguisher": "1:0"}, "interfaces": {"interface": {"Management1": {}}}}, "DEF": {"name": "DEF", "type": "L3VRF", "state": {"route_distinguisher": "2:0"}, "interfaces": {"interface": {"Ethernet1": {}}}}, "default": {"interfaces": {"interface": {}}, "state": {"route_distinguisher": ""}, "type": "DEFAULT_INSTANCE", "name": "default"}} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-796/show_ip_interface.json b/test/eos/mocked_data/test_get_network_instances/issue-796/show_ip_interface.json deleted file mode 100644 index 780f4279a..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-796/show_ip_interface.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "interfaces": { - "Management1": { - "directedBroadcastEnabled": false, - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "virtualSecondaryIps": {}, - "dhcp": true, - "secondaryIps": {}, - "primaryIp": { - "maskLen": 23, - "address": "10.192.104.32" - }, - "virtualSecondaryIpsOrderedList": [], - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Management1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "addresslessForwarding": "isInvalid", - "vrf": "ABC", - "localProxyArp": false, - "injectHosts": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Ethernet1": { - "directedBroadcastEnabled": false, - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "virtualSecondaryIps": {}, - "dhcp": false, - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualSecondaryIpsOrderedList": [], - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Ethernet1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "addresslessForwarding": "isInvalid", - "vrf": "DEF", - "localProxyArp": false, - "injectHosts": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - } - } -} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-796/show_ipv6_interface.json b/test/eos/mocked_data/test_get_network_instances/issue-796/show_ipv6_interface.json deleted file mode 100644 index 582256041..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-796/show_ipv6_interface.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "interfaces": {}, - "errors": [ - "No IPv6 configured interfaces" - ] -} diff --git a/test/eos/mocked_data/test_get_network_instances/issue-796/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/issue-796/show_vrf.text deleted file mode 100644 index a4e955e40..000000000 --- a/test/eos/mocked_data/test_get_network_instances/issue-796/show_vrf.text +++ /dev/null @@ -1,9 +0,0 @@ -Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces ---------- --------- --------------- -------------------- ----------- - ABC 1:0 ipv4,ipv6 v4:no routing, Management1 - v6:no routing - - DEF 2:0 ipv4,ipv6 v4:no routing, Ethernet1 - v6:no routing - diff --git a/test/eos/mocked_data/test_get_network_instances/missing_v6/expected_result.json b/test/eos/mocked_data/test_get_network_instances/missing_v6/expected_result.json deleted file mode 100644 index 14e365769..000000000 --- a/test/eos/mocked_data/test_get_network_instances/missing_v6/expected_result.json +++ /dev/null @@ -1 +0,0 @@ -{"TEST": {"interfaces": {"interface": {"Ethernet1": {}, "Vlan103": {}, "Vlan102": {}, "Vlan101": {}, "Vlan100": {}, "Vlan104": {}}}, "state": {"route_distinguisher": "0:1"}, "type": "L3VRF", "name": "TEST"}, "default": {"interfaces": {"interface": {"Management1": {}, "Ethernet3": {}}}, "state": {"route_distinguisher": ""}, "type": "DEFAULT_INSTANCE", "name": "default"}, "NON": {"interfaces": {"interface": {}}, "state": {"route_distinguisher": ""}, "type": "L3VRF", "name": "NON"}, "TEST2": {"interfaces": {"interface": {}}, "state": {"route_distinguisher": "1234:4321"}, "type": "L3VRF", "name": "TEST2"}, "MGMT": {"interfaces": {"interface": {"Vlan2": {}, "Vlan3": {}, "Vlan4": {}}}, "state": {"route_distinguisher": "0:0"}, "type": "L3VRF", "name": "MGMT"}} diff --git a/test/eos/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json b/test/eos/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json deleted file mode 100644 index a697ecf52..000000000 --- a/test/eos/mocked_data/test_get_network_instances/missing_v6/show_ip_interface.json +++ /dev/null @@ -1,279 +0,0 @@ -{ - "interfaces": { - "Management1": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 23, - "address": "10.192.100.98" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Management1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "default", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Vlan3": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan3", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Ethernet3": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Ethernet3", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "default", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Ethernet1": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Ethernet1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Vlan103": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan103", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan102": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan102", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan2": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan2", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan100": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan100", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan4": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan4", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan101": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan101", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan104": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan104", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - } - } -} diff --git a/test/eos/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json b/test/eos/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json deleted file mode 100644 index 582256041..000000000 --- a/test/eos/mocked_data/test_get_network_instances/missing_v6/show_ipv6_interface.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "interfaces": {}, - "errors": [ - "No IPv6 configured interfaces" - ] -} diff --git a/test/eos/mocked_data/test_get_network_instances/missing_v6/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/missing_v6/show_vrf.text deleted file mode 100644 index ff52fbbb2..000000000 --- a/test/eos/mocked_data/test_get_network_instances/missing_v6/show_vrf.text +++ /dev/null @@ -1,14 +0,0 @@ -Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- ------------ ------------ ------------------------- ------------------- - MGMT 0:0 ipv4 v4:routing, Vlan2, Vlan3, Vlan4 - v6:no routing - - NON v4:incomplete, - v6:incomplete - - TEST 0:1 ipv4 v4:routing; multicast, Ethernet1, Vlan100, - v6:no routing Vlan101, Vlan102, - Vlan103, Vlan104 - TEST2 1234:4321 ipv4 v4:no routing, - v6:routing diff --git a/test/eos/mocked_data/test_get_network_instances/normal/expected_result.json b/test/eos/mocked_data/test_get_network_instances/normal/expected_result.json index 14e365769..dc3f3d294 100644 --- a/test/eos/mocked_data/test_get_network_instances/normal/expected_result.json +++ b/test/eos/mocked_data/test_get_network_instances/normal/expected_result.json @@ -1 +1,31 @@ -{"TEST": {"interfaces": {"interface": {"Ethernet1": {}, "Vlan103": {}, "Vlan102": {}, "Vlan101": {}, "Vlan100": {}, "Vlan104": {}}}, "state": {"route_distinguisher": "0:1"}, "type": "L3VRF", "name": "TEST"}, "default": {"interfaces": {"interface": {"Management1": {}, "Ethernet3": {}}}, "state": {"route_distinguisher": ""}, "type": "DEFAULT_INSTANCE", "name": "default"}, "NON": {"interfaces": {"interface": {}}, "state": {"route_distinguisher": ""}, "type": "L3VRF", "name": "NON"}, "TEST2": {"interfaces": {"interface": {}}, "state": {"route_distinguisher": "1234:4321"}, "type": "L3VRF", "name": "TEST2"}, "MGMT": {"interfaces": {"interface": {"Vlan2": {}, "Vlan3": {}, "Vlan4": {}}}, "state": {"route_distinguisher": "0:0"}, "type": "L3VRF", "name": "MGMT"}} +{ + "default": { + "name": "default", + "type": "DEFAULT_INSTANCE", + "state": { "route_distinguisher": "" }, + "interfaces": { + "interface": { + "Ethernet1": {}, + "Ethernet2": {}, + "Loopback0": {}, + "Management0": {} + } + } + }, + "foo": { + "name": "foo", + "type": "L3VRF", + "state": { "route_distinguisher": "0:1" }, + "interfaces": { + "interface": {} + } + }, + "bar": { + "name": "bar", + "type": "L3VRF", + "state": { "route_distinguisher": "" }, + "interfaces": { + "interface": {} + } + } +} diff --git a/test/eos/mocked_data/test_get_network_instances/normal/show_ip_interface.json b/test/eos/mocked_data/test_get_network_instances/normal/show_ip_interface.json deleted file mode 100644 index a697ecf52..000000000 --- a/test/eos/mocked_data/test_get_network_instances/normal/show_ip_interface.json +++ /dev/null @@ -1,279 +0,0 @@ -{ - "interfaces": { - "Management1": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 23, - "address": "10.192.100.98" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Management1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "default", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Vlan3": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan3", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Ethernet3": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Ethernet3", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "default", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Ethernet1": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Ethernet1", - "urpf": "disable", - "interfaceStatus": "connected", - "enabled": true, - "mtu": 1500, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "up", - "description": "" - }, - "Vlan103": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan103", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan102": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan102", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan2": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan2", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan100": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan100", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan4": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan4", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "MGMT", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan101": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan101", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - }, - "Vlan104": { - "interfaceAddress": { - "secondaryIpsOrderedList": [], - "broadcastAddress": "255.255.255.255", - "secondaryIps": {}, - "primaryIp": { - "maskLen": 0, - "address": "0.0.0.0" - }, - "virtualIp": { - "maskLen": 0, - "address": "0.0.0.0" - } - }, - "name": "Vlan104", - "urpf": "disable", - "interfaceStatus": "notconnect", - "enabled": true, - "mtu": 1478, - "vrf": "TEST", - "localProxyArp": false, - "proxyArp": false, - "lineProtocolStatus": "lowerLayerDown", - "description": "" - } - } -} diff --git a/test/eos/mocked_data/test_get_network_instances/normal/show_ipv6_interface.json b/test/eos/mocked_data/test_get_network_instances/normal/show_ipv6_interface.json deleted file mode 100644 index 582256041..000000000 --- a/test/eos/mocked_data/test_get_network_instances/normal/show_ipv6_interface.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "interfaces": {}, - "errors": [ - "No IPv6 configured interfaces" - ] -} diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json b/test/eos/mocked_data/test_get_network_instances/normal/show_vrf.json similarity index 100% rename from test/eos/mocked_data/test_get_network_instances/vrf/show_vrf.json rename to test/eos/mocked_data/test_get_network_instances/normal/show_vrf.json diff --git a/test/eos/mocked_data/test_get_network_instances/normal/show_vrf.text b/test/eos/mocked_data/test_get_network_instances/normal/show_vrf.text deleted file mode 100644 index d1e1d7e11..000000000 --- a/test/eos/mocked_data/test_get_network_instances/normal/show_vrf.text +++ /dev/null @@ -1,17 +0,0 @@ -Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- ------------ ------------ ------------------------- ------------------- - MGMT 0:0 ipv4,ipv6 v4:routing, Vlan2, Vlan3, Vlan4 - v6:no routing - - NON v4:incomplete, - v6:incomplete - - TEST 0:1 ipv4,ipv6 v4:routing; multicast, Ethernet1, Vlan100, - v6:no routing Vlan101, Vlan102, - Vlan103, Vlan104 - TEST2 1234:4321 ipv4,ipv6 v4:no routing, - v6:routing - - - diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt b/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt deleted file mode 100644 index 0cfbf0888..000000000 --- a/test/eos/mocked_data/test_get_network_instances/vrf/cli_version.txt +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json b/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json deleted file mode 100644 index dc3f3d294..000000000 --- a/test/eos/mocked_data/test_get_network_instances/vrf/expected_result.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "default": { - "name": "default", - "type": "DEFAULT_INSTANCE", - "state": { "route_distinguisher": "" }, - "interfaces": { - "interface": { - "Ethernet1": {}, - "Ethernet2": {}, - "Loopback0": {}, - "Management0": {} - } - } - }, - "foo": { - "name": "foo", - "type": "L3VRF", - "state": { "route_distinguisher": "0:1" }, - "interfaces": { - "interface": {} - } - }, - "bar": { - "name": "bar", - "type": "L3VRF", - "state": { "route_distinguisher": "" }, - "interfaces": { - "interface": {} - } - } -} diff --git a/test/eos/mocked_data/test_get_route_to/iss_1069/expected_result.json b/test/eos/mocked_data/test_get_route_to/iss_1069/expected_result.json index a13e763a5..1219f0660 100644 --- a/test/eos/mocked_data/test_get_route_to/iss_1069/expected_result.json +++ b/test/eos/mocked_data/test_get_route_to/iss_1069/expected_result.json @@ -1 +1,26 @@ -{"1.0.4.0/24": [{"current_active": true, "last_active": true, "age": 0, "next_hop": "169.254.123.2", "protocol": "eBGP", "outgoing_interface": "Vlan123", "preference": 200, "inactive_reason": "noReason", "routing_table": "default", "selected_next_hop": true, "protocol_attributes": {"metric": 0, "as_path": "65003", "local_preference": 100, "local_as": 65002, "remote_as": 65003, "remote_address": "169.254.123.2", "preference2": 0, "communities": []}}, {"current_active": true, "last_active": true, "age": 0, "next_hop": "169.254.123.2", "protocol": "eBGP", "outgoing_interface": "Vlan123", "preference": 200, "inactive_reason": "noReason", "routing_table": "default", "selected_next_hop": true, "protocol_attributes": {"metric": 0, "as_path": "65003", "local_preference": 100, "local_as": 65002, "remote_as": 65003, "remote_address": "169.254.123.2", "preference2": 0, "communities": []}}]} +{ + "1.0.4.0/24": [ + { + "current_active": true, + "last_active": true, + "age": 0, + "next_hop": "169.254.123.2", + "protocol": "eBGP", + "outgoing_interface": "Vlan123", + "preference": 200, + "inactive_reason": "noReason", + "routing_table": "default", + "selected_next_hop": true, + "protocol_attributes": { + "metric": 0, + "as_path": "65003", + "local_preference": 100, + "local_as": 65002, + "remote_as": 65003, + "remote_address": "169.254.123.2", + "preference2": 0, + "communities": [] + } + } + ] +} diff --git a/test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.json b/test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.json new file mode 100644 index 000000000..df8ebfb8f --- /dev/null +++ b/test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.json @@ -0,0 +1,37 @@ +{ + "vrfs": { + "default": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfacesV4": [ + "Ethernet1", + "Ethernet2", + "Loopback1", + "Management1", + "Vlan123" + ], + "interfacesV6": [ + "Management1" + ], + "interfaces": [ + "Ethernet1", + "Ethernet2", + "Loopback1", + "Management1", + "Vlan123" + ] + } + } +} diff --git a/test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.text b/test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.text deleted file mode 100644 index cc3e254b8..000000000 --- a/test/eos/mocked_data/test_get_route_to/iss_1069/show_vrf.text +++ /dev/null @@ -1,8 +0,0 @@ -Maximum number of vrfs allowed: 14 - VRF RD Protocols State Interfaces ----------- ------------ ------------- ----------------- ----------------------- - default ipv4,ipv6 v4:routing, Ethernet1, Ethernet2, - v6:no routing Loopback1, Management1, - Vlan123 - - diff --git a/test/eos/mocked_data/test_get_route_to/iss_1347/expected_result.json b/test/eos/mocked_data/test_get_route_to/iss_1347/expected_result.json index 5d7d474e2..2a9acfd0f 100644 --- a/test/eos/mocked_data/test_get_route_to/iss_1347/expected_result.json +++ b/test/eos/mocked_data/test_get_route_to/iss_1347/expected_result.json @@ -1 +1,268 @@ -{"1.0.4.0/24": [{"current_active": true, "last_active": true, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "noReason", "routing_table": "TEST", "selected_next_hop": true, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.2", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "TEST", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.3", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "TEST", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.4", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "TEST", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.1", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "TEST", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.4", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "TEST", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.3", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "TEST", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.1", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.224.6", "protocol": "eBGP", "outgoing_interface": "vxlan1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "TEST", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419 65405", "local_preference": 100, "local_as": 65323, "remote_as": 65405, "remote_address": "169.254.216.2", "preference2": 0, "communities": []}}, {"current_active": true, "last_active": true, "age": 0, "next_hop": "169.254.232.160", "protocol": "eBGP", "outgoing_interface": "Ethernet4/1", "preference": 20, "inactive_reason": "noReason", "routing_table": "default", "selected_next_hop": true, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.160", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.232.156", "protocol": "eBGP", "outgoing_interface": "Ethernet3/1", "preference": 20, "inactive_reason": "ecmpFast", "routing_table": "default", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.156", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.232.148", "protocol": "eBGP", "outgoing_interface": "Ethernet1/1", "preference": 20, "inactive_reason": "ecmpFast", "routing_table": "default", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.148", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.232.152", "protocol": "eBGP", "outgoing_interface": "Ethernet2/1", "preference": 20, "inactive_reason": "ecmpFast", "routing_table": "default", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.152", "preference2": 0, "communities": []}}, {"current_active": true, "last_active": true, "age": 0, "next_hop": "169.254.232.160", "protocol": "eBGP", "outgoing_interface": "Ethernet4/1", "preference": 20, "inactive_reason": "noReason", "routing_table": "default", "selected_next_hop": true, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.160", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.232.156", "protocol": "eBGP", "outgoing_interface": "Ethernet3/1", "preference": 20, "inactive_reason": "ecmpFast", "routing_table": "default", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.156", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.232.148", "protocol": "eBGP", "outgoing_interface": "Ethernet1/1", "preference": 20, "inactive_reason": "ecmpFast", "routing_table": "default", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.148", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "169.254.232.152", "protocol": "eBGP", "outgoing_interface": "Ethernet2/1", "preference": 20, "inactive_reason": "ecmpFast", "routing_table": "default", "selected_next_hop": false, "protocol_attributes": {"metric": 0, "as_path": "65418 65419", "local_preference": 100, "local_as": 65323, "remote_as": 65419, "remote_address": "169.254.232.152", "preference2": 0, "communities": []}}]} +{ + "1.0.4.0/24": [ + { + "current_active": true, + "last_active": true, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "noReason", + "routing_table": "TEST", + "selected_next_hop": true, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.2", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "TEST", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.3", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "TEST", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.4", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "TEST", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.1", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "TEST", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.4", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "TEST", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.3", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "TEST", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.1", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.224.6", + "protocol": "eBGP", + "outgoing_interface": "vxlan1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "TEST", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419 65405", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65405, + "remote_address": "169.254.216.2", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": true, + "last_active": true, + "age": 0, + "next_hop": "169.254.232.160", + "protocol": "eBGP", + "outgoing_interface": "Ethernet4/1", + "preference": 20, + "inactive_reason": "noReason", + "routing_table": "default", + "selected_next_hop": true, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65419, + "remote_address": "169.254.232.160", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.232.156", + "protocol": "eBGP", + "outgoing_interface": "Ethernet3/1", + "preference": 20, + "inactive_reason": "ecmpFast", + "routing_table": "default", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65419, + "remote_address": "169.254.232.156", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.232.148", + "protocol": "eBGP", + "outgoing_interface": "Ethernet1/1", + "preference": 20, + "inactive_reason": "ecmpFast", + "routing_table": "default", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65419, + "remote_address": "169.254.232.148", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "169.254.232.152", + "protocol": "eBGP", + "outgoing_interface": "Ethernet2/1", + "preference": 20, + "inactive_reason": "ecmpFast", + "routing_table": "default", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 0, + "as_path": "65418 65419", + "local_preference": 100, + "local_as": 65323, + "remote_as": 65419, + "remote_address": "169.254.232.152", + "preference2": 0, + "communities": [] + } + } + ] +} diff --git a/test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.json b/test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.json new file mode 100644 index 000000000..9b5662cc0 --- /dev/null +++ b/test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.json @@ -0,0 +1,61 @@ +{ + "vrfs": { + "default": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfaces": [ + "Ethernet1/1", + "Ethernet2/1", + "Ethernet3/1", + "Ethernet4/1", + "Loopback0", + "Loopback1", + "Vlan3001", + "Vlan3002", + "Vlan3003", + "Vlan3004", + "Vlan3005", + "Vlan3006" + ] + }, + "TEST": { + "routeDistinguisher": "65323:631", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfaces": [ + "Vlan2001", + "Vlan2002", + "Vlan2003", + "Vlan2004", + "Vlan2005", + "Vlan2006", + "Vlan2007", + "Vlan2008", + "Vlan2009" + ] + } + } +} diff --git a/test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.text b/test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.text deleted file mode 100644 index da8989453..000000000 --- a/test/eos/mocked_data/test_get_route_to/iss_1347/show_vrf.text +++ /dev/null @@ -1,12 +0,0 @@ -Maximum number of vrfs allowed: 1023 - VRF RD Protocols State Interfaces ----------------- --------------- --------------- -------------------- ----------------------------- - TEST 65323:631 ipv4,ipv6 v4:routing, Vlan2001, Vlan2002, Vlan2003, - v6:no routing Vlan2004, Vlan2005, Vlan2006, - Vlan2007, Vlan2008, Vlan2009 - default ipv4,ipv6 v4:routing, Ethernet1/1, Ethernet2/1, - v6:no routing Ethernet3/1, Ethernet4/1, - Loopback0, Loopback1, - Vlan3001, Vlan3002, Vlan3003, - Vlan3004, Vlan3004, Vlan3006 - diff --git a/test/eos/mocked_data/test_get_route_to/iss_736/expected_result.json b/test/eos/mocked_data/test_get_route_to/iss_736/expected_result.json index b8942c698..ce90fbf34 100644 --- a/test/eos/mocked_data/test_get_route_to/iss_736/expected_result.json +++ b/test/eos/mocked_data/test_get_route_to/iss_736/expected_result.json @@ -1 +1,48 @@ -{"1.0.4.0/24": [{"current_active": true, "last_active": true, "age": 0, "next_hop": "1.0.4.221", "protocol": "eBGP", "outgoing_interface": "Ethernet51/1", "preference": 200, "inactive_reason": "noReason", "routing_table": "default", "selected_next_hop": true, "protocol_attributes": {"metric": 175, "as_path": "(20901 21149)", "local_preference": 100, "local_as": 20948, "remote_as": 21149, "remote_address": "1.0.4.221", "preference2": 0, "communities": []}}, {"current_active": false, "last_active": false, "age": 0, "next_hop": "1.0.4.223", "protocol": "eBGP", "outgoing_interface": "Ethernet52/1", "preference": 200, "inactive_reason": "ecmpFast", "routing_table": "default", "selected_next_hop": false, "protocol_attributes": {"metric": 175, "as_path": "(20902 21149)", "local_preference": 100, "local_as": 20948, "remote_as": 21149, "remote_address": "1.0.4.223", "preference2": 0, "communities": []}}]} +{ + "1.0.4.0/24": [ + { + "current_active": true, + "last_active": true, + "age": 0, + "next_hop": "1.0.4.221", + "protocol": "eBGP", + "outgoing_interface": "Ethernet51/1", + "preference": 200, + "inactive_reason": "noReason", + "routing_table": "default", + "selected_next_hop": true, + "protocol_attributes": { + "metric": 175, + "as_path": "(20901 21149)", + "local_preference": 100, + "local_as": 20948, + "remote_as": 21149, + "remote_address": "1.0.4.221", + "preference2": 0, + "communities": [] + } + }, + { + "current_active": false, + "last_active": false, + "age": 0, + "next_hop": "1.0.4.223", + "protocol": "eBGP", + "outgoing_interface": "Ethernet52/1", + "preference": 200, + "inactive_reason": "ecmpFast", + "routing_table": "default", + "selected_next_hop": false, + "protocol_attributes": { + "metric": 175, + "as_path": "(20902 21149)", + "local_preference": 100, + "local_as": 20948, + "remote_as": 21149, + "remote_address": "1.0.4.223", + "preference2": 0, + "communities": [] + } + } + ] +} diff --git a/test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.json b/test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.json new file mode 100644 index 000000000..b514669d3 --- /dev/null +++ b/test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.json @@ -0,0 +1,24 @@ +{ + "vrfs": { + "default": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfaces": [ + "Ethernet51/1", + "Ethernet52/1" + ] + } + } +} diff --git a/test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.text b/test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.text deleted file mode 100644 index f70ab6aa8..000000000 --- a/test/eos/mocked_data/test_get_route_to/iss_736/show_vrf.text +++ /dev/null @@ -1,3 +0,0 @@ -Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- ------------ ------------ ------------------------- ------------------- diff --git a/test/eos/mocked_data/test_get_route_to/normal/expected_result.json b/test/eos/mocked_data/test_get_route_to/normal/expected_result.json index 94b00e6f4..79be002db 100644 --- a/test/eos/mocked_data/test_get_route_to/normal/expected_result.json +++ b/test/eos/mocked_data/test_get_route_to/normal/expected_result.json @@ -1 +1,58 @@ -{"1.0.4.0/24": [{"next_hop": "192.168.0.1", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "TEST", "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}, {"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}]} +{ + "1.0.4.0/24": [ + { + "next_hop": "192.168.0.1", + "preference": 200, + "protocol": "eBGP", + "selected_next_hop": true, + "current_active": true, + "routing_table": "TEST", + "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 + }, + { + "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-Channel1", + "last_active": true, + "inactive_reason": "", + "age": 0 + } + ] +} diff --git a/test/eos/mocked_data/test_get_route_to/normal/show_ip_route_vrf_default_1_0_4_0_24__bgp_detail.json b/test/eos/mocked_data/test_get_route_to/normal/show_ip_route_vrf_default_1_0_4_0_24__bgp_detail.json index 6b4417b24..841200c99 100644 --- a/test/eos/mocked_data/test_get_route_to/normal/show_ip_route_vrf_default_1_0_4_0_24__bgp_detail.json +++ b/test/eos/mocked_data/test_get_route_to/normal/show_ip_route_vrf_default_1_0_4_0_24__bgp_detail.json @@ -9,7 +9,7 @@ "routeAction": "forward", "vias": [ { - "interface": "Port-Channel2", + "interface": "Port-Channel1", "nexthopAddr": "192.168.0.1" } ], diff --git a/test/eos/mocked_data/test_get_route_to/normal/show_vrf.json b/test/eos/mocked_data/test_get_route_to/normal/show_vrf.json new file mode 100644 index 000000000..a325e4024 --- /dev/null +++ b/test/eos/mocked_data/test_get_route_to/normal/show_vrf.json @@ -0,0 +1,44 @@ +{ + "vrfs": { + "default": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfaces": [ + "Ethernet1", + "Port-Channel1" + ] + }, + "TEST": { + "routeDistinguisher": "0:1", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfaces": [ + "Ethernet2", + "Port-Channel2" + ] + } + } +} diff --git a/test/eos/mocked_data/test_get_route_to/normal/show_vrf.text b/test/eos/mocked_data/test_get_route_to/normal/show_vrf.text deleted file mode 100644 index 0f46f3c0f..000000000 --- a/test/eos/mocked_data/test_get_route_to/normal/show_vrf.text +++ /dev/null @@ -1,9 +0,0 @@ -Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- ------------ ------------ ------------------------- ------------------- - TEST 0:1 ipv4,ipv6 v4:routing; multicast, Ethernet1, Vlan100, - v6:routing Vlan101, Vlan102, - Vlan103, Vlan104 - - - diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/expected_result.json b/test/eos/mocked_data/test_get_route_to_longer/normal/expected_result.json index 874210f21..efa565154 100644 --- a/test/eos/mocked_data/test_get_route_to_longer/normal/expected_result.json +++ b/test/eos/mocked_data/test_get_route_to_longer/normal/expected_result.json @@ -1 +1,114 @@ -{"1.0.4.0/25": [{"next_hop": "192.168.0.1", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "TEST", "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}, {"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}], "1.0.4.128/25": [{"next_hop": "192.168.0.5", "preference": 200, "protocol": "eBGP", "selected_next_hop": true, "current_active": true, "routing_table": "TEST", "protocol_attributes": {"remote_as": 43515, "as_path": "1299 15169 43515", "local_preference": 50, "remote_address": "192.168.0.5", "preference2": 0, "metric": 0, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "local_as": 13335}, "outgoing_interface": "Port-Channel1", "last_active": true, "inactive_reason": "", "age": 0}, {"next_hop": "192.168.0.5", "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.5", "preference2": 0, "metric": 0, "communities": ["1299:1234", "1299:5678", "1299:91011", "1299:12134"], "local_as": 13335}, "outgoing_interface": "Port-Channel1", "last_active": true, "inactive_reason": "", "age": 0}]} +{ + "1.0.4.0/25": [ + { + "next_hop": "192.168.0.1", + "preference": 200, + "protocol": "eBGP", + "selected_next_hop": true, + "current_active": true, + "routing_table": "TEST", + "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 + }, + { + "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 + } + ], + "1.0.4.128/25": [ + { + "next_hop": "192.168.0.5", + "preference": 200, + "protocol": "eBGP", + "selected_next_hop": true, + "current_active": true, + "routing_table": "TEST", + "protocol_attributes": { + "remote_as": 43515, + "as_path": "1299 15169 43515", + "local_preference": 50, + "remote_address": "192.168.0.5", + "preference2": 0, + "metric": 0, + "communities": [ + "1299:1234", + "1299:5678", + "1299:91011", + "1299:12134" + ], + "local_as": 13335 + }, + "outgoing_interface": "Port-Channel1", + "last_active": true, + "inactive_reason": "", + "age": 0 + }, + { + "next_hop": "192.168.0.5", + "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.5", + "preference2": 0, + "metric": 0, + "communities": [ + "1299:1234", + "1299:5678", + "1299:91011", + "1299:12134" + ], + "local_as": 13335 + }, + "outgoing_interface": "Port-Channel1", + "last_active": true, + "inactive_reason": "", + "age": 0 + } + ] +} diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.json b/test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.json new file mode 100644 index 000000000..a325e4024 --- /dev/null +++ b/test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.json @@ -0,0 +1,44 @@ +{ + "vrfs": { + "default": { + "routeDistinguisher": "", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfaces": [ + "Ethernet1", + "Port-Channel1" + ] + }, + "TEST": { + "routeDistinguisher": "0:1", + "protocols": { + "ipv4": { + "supported": true, + "protocolState": "up", + "routingState": "up" + }, + "ipv6": { + "supported": true, + "protocolState": "up", + "routingState": "down" + } + }, + "vrfState": "up", + "interfaces": [ + "Ethernet2", + "Port-Channel2" + ] + } + } +} diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.text b/test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.text deleted file mode 100644 index eaf448fbd..000000000 --- a/test/eos/mocked_data/test_get_route_to_longer/normal/show_vrf.text +++ /dev/null @@ -1,6 +0,0 @@ -Maximum number of vrfs allowed: 14 - Vrf RD Protocols State Interfaces -------- ------------ ------------ ------------------------- ------------------- - TEST 0:1 ipv4,ipv6 v4:routing; multicast, Ethernet1, Vlan100, - v6:routing Vlan101, Vlan102, - Vlan103, Vlan104 diff --git a/test/eos/test_cli_syntax.py b/test/eos/test_cli_syntax.py deleted file mode 100644 index 791dca095..000000000 --- a/test/eos/test_cli_syntax.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -Tests for EOS cli_syntax -""" -from napalm.eos.utils.cli_syntax import cli_convert - - -def test_cli_no_change_v2(): - """ - Test no change for basic commands in version 2 - :return: - """ - commands = ["show version", "show interfaces"] - - for c in commands: - assert c == cli_convert(c, 2) - assert c == cli_convert(c, 1) - - -def test_cli_no_change_non_exist_version(): - """ - Test no change for basic commands and non-existing versions - :return: - """ - commands = ["show version", "show interfaces"] - - for c in commands: - assert c == cli_convert(c, 100000) - - -def test_cli_change_exact(): - """ - Test cli change for exact commands - """ - commands = ["show ipv6 bgp neighbors", "show lldp traffic"] - expect = ["show ipv6 bgp peers", "show lldp counters"] - - for c, e in zip(commands, expect): - assert e == cli_convert(c, 2) - assert c == cli_convert(e, 1) - - -def test_cli_change_long_commands(): - """ - Test cli change for long commands - """ - commands = ["show ipv6 bgp neighbors vrf all", "show lldp traffic | include test"] - expect = ["show ipv6 bgp peers vrf all", "show lldp counters | include test"] - - for c, e in zip(commands, expect): - assert e == cli_convert(c, 2) - assert c == cli_convert(e, 1) diff --git a/test/eos/test_heredoc.py b/test/eos/test_heredoc.py index 9190ff67e..cf5d891fa 100644 --- a/test/eos/test_heredoc.py +++ b/test/eos/test_heredoc.py @@ -57,9 +57,7 @@ def test_heredoc(self): "end", ] - self.device.device.run_commands.assert_called_with( - expected_result, fn0039_transform=False - ) + self.device.device.run_commands.assert_called_with(expected_result) def test_mode_comment(self): raw_config = dedent( @@ -111,9 +109,7 @@ def test_mode_comment(self): "end", ] - self.device.device.run_commands.assert_called_with( - expected_result, fn0039_transform=False - ) + self.device.device.run_commands.assert_called_with(expected_result) def test_heredoc_with_bangs(self): raw_config = dedent( @@ -150,6 +146,4 @@ def test_heredoc_with_bangs(self): "end", ] - self.device.device.run_commands.assert_called_with( - expected_result, fn0039_transform=False - ) + self.device.device.run_commands.assert_called_with(expected_result) From 5de951d896d57b854d8d3b278d4795e74434d268 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 10 Jul 2023 20:18:03 +0000 Subject: [PATCH 67/76] eos: update get_environment commands and tests Use new-format "show system ..." command for environment Update to also detect cEOS systems not having power supplies --- napalm/eos/eos.py | 9 +++++--- .../ceos430/expected_result.json | 14 ++++++++++++ .../ceos430/show_processes_top_once.text | 19 ++++++++++++++++ .../show_system_environment_cooling.json | 14 ++++++++++++ .../show_system_environment_temperature.json | 11 ++++++++++ .../ceos430/show_version.json | 22 +++++++++++++++++++ ...n => show_system_environment_cooling.json} | 0 ...son => show_system_environment_power.json} | 0 ... show_system_environment_temperature.json} | 0 ...n => show_system_environment_cooling.json} | 0 ...son => show_system_environment_power.json} | 0 ... show_system_environment_temperature.json} | 0 ...n => show_system_environment_cooling.json} | 0 ...son => show_system_environment_power.json} | 0 ... show_system_environment_temperature.json} | 0 ...n => show_system_environment_cooling.json} | 0 ... show_system_environment_temperature.json} | 0 ...n => show_system_environment_cooling.json} | 0 ...son => show_system_environment_power.json} | 0 ... show_system_environment_temperature.json} | 0 20 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 test/eos/mocked_data/test_get_environment/ceos430/expected_result.json create mode 100644 test/eos/mocked_data/test_get_environment/ceos430/show_processes_top_once.text create mode 100644 test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_cooling.json create mode 100644 test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_temperature.json create mode 100644 test/eos/mocked_data/test_get_environment/ceos430/show_version.json rename test/eos/mocked_data/test_get_environment/issue1671_top_mb/{show_environment_cooling.json => show_system_environment_cooling.json} (100%) rename test/eos/mocked_data/test_get_environment/issue1671_top_mb/{show_environment_power.json => show_system_environment_power.json} (100%) rename test/eos/mocked_data/test_get_environment/issue1671_top_mb/{show_environment_temperature.json => show_system_environment_temperature.json} (100%) rename test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/{show_environment_cooling.json => show_system_environment_cooling.json} (100%) rename test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/{show_environment_power.json => show_system_environment_power.json} (100%) rename test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/{show_environment_temperature.json => show_system_environment_temperature.json} (100%) rename test/eos/mocked_data/test_get_environment/issue810_7010t/{show_environment_cooling.json => show_system_environment_cooling.json} (100%) rename test/eos/mocked_data/test_get_environment/issue810_7010t/{show_environment_power.json => show_system_environment_power.json} (100%) rename test/eos/mocked_data/test_get_environment/issue810_7010t/{show_environment_temperature.json => show_system_environment_temperature.json} (100%) rename test/eos/mocked_data/test_get_environment/issue90_veos/{show_environment_cooling.json => show_system_environment_cooling.json} (100%) rename test/eos/mocked_data/test_get_environment/issue90_veos/{show_environment_temperature.json => show_system_environment_temperature.json} (100%) rename test/eos/mocked_data/test_get_environment/normal/{show_environment_cooling.json => show_system_environment_cooling.json} (100%) rename test/eos/mocked_data/test_get_environment/normal/{show_environment_power.json => show_system_environment_power.json} (100%) rename test/eos/mocked_data/test_get_environment/normal/{show_environment_temperature.json => show_system_environment_temperature.json} (100%) diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 37db5a8d1..6c6d3f52f 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -820,10 +820,13 @@ def extract_temperature_data(data): yield name, values sh_version_out = self._run_commands(["show version"]) - is_veos = sh_version_out[0]["modelName"].lower() == "veos" - commands = ["show environment cooling", "show environment temperature"] + is_veos = sh_version_out[0]["modelName"].lower() in ["veos", "ceoslab"] + commands = [ + "show system environment cooling", + "show system environment temperature", + ] if not is_veos: - commands.append("show environment power") + commands.append("show system environment power") fans_output, temp_output, power_output = self._run_commands(commands) else: fans_output, temp_output = self._run_commands(commands) diff --git a/test/eos/mocked_data/test_get_environment/ceos430/expected_result.json b/test/eos/mocked_data/test_get_environment/ceos430/expected_result.json new file mode 100644 index 000000000..90508e7c9 --- /dev/null +++ b/test/eos/mocked_data/test_get_environment/ceos430/expected_result.json @@ -0,0 +1,14 @@ +{ + "temperature": {}, + "power": {}, + "fans": {}, + "memory": { + "available_ram": 16012300, + "used_ram": 4580692 + }, + "cpu": { + "0": { + "%usage": 4.3 + } + } +} diff --git a/test/eos/mocked_data/test_get_environment/ceos430/show_processes_top_once.text b/test/eos/mocked_data/test_get_environment/ceos430/show_processes_top_once.text new file mode 100644 index 000000000..912ae600d --- /dev/null +++ b/test/eos/mocked_data/test_get_environment/ceos430/show_processes_top_once.text @@ -0,0 +1,19 @@ +top - 14:03:41 up 131 days, 21:26, 1 user, load average: 0.39, 0.29, 0.32 +Tasks: 383 total, 1 running, 382 sleeping, 0 stopped, 0 zombie +Cpu(s): 3.5%us, 0.5%sy, 0.0%ni, 95.7%id, 0.0%wa, 0.2%hi, 0.1%si, 0.0%st +Mem: 16012300k total, 4580692k used, 11431608k free, 200332k buffers +Swap: 0k total, 0k used, 0k free, 2395436k cached + + PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND + 6416 root 20 0 662m 105m 37m S 9.0 0.7 3592:55 SandFabric + 6420 root 20 0 662m 105m 37m S 7.2 0.7 3589:14 SandFabric + 2606 root 20 0 562m 88m 23m S 3.6 0.6 3237:39 Smbus + 4332 root 20 0 761m 224m 94m S 3.6 1.4 10642:24 SandFap + 6419 root 20 0 662m 105m 37m S 3.6 0.7 3596:53 SandFabric + 2675 root 20 0 553m 78m 20m S 1.8 0.5 37:26.89 VrmIr + 3850 root 20 0 558m 85m 21m S 1.8 0.5 597:34.22 Adt7462Agent + 3954 root 20 0 565m 96m 31m S 1.8 0.6 1809:51 XcvrAgent + 6424 root 20 0 662m 105m 37m S 1.8 0.7 3614:34 SandFabric +20866 dbarroso 20 0 26552 12m 9668 R 1.8 0.1 0:00.06 top + 1 root 20 0 26340 12m 9832 S 0.0 0.1 0:02.62 init + 2 root 20 0 0 0 0 S 0.0 0.0 0:01.36 kthreadd diff --git a/test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_cooling.json b/test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_cooling.json new file mode 100644 index 000000000..820008f2d --- /dev/null +++ b/test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_cooling.json @@ -0,0 +1,14 @@ +{ + "systemStatus": "unknownCoolingAlarmLevel", + "airflowDirection": "unknownAirflowDirection", + "currentZones": 1, + "configuredZones": 0, + "defaultZones": false, + "numCoolingZones": [], + "shutdownOnInsufficientFans": true, + "overrideFanSpeed": 0, + "minFanSpeed": 0, + "coolingMode": "automatic", + "fanTraySlots": [], + "powerSupplySlots": [] +} diff --git a/test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_temperature.json b/test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_temperature.json new file mode 100644 index 000000000..0a05a66dd --- /dev/null +++ b/test/eos/mocked_data/test_get_environment/ceos430/show_system_environment_temperature.json @@ -0,0 +1,11 @@ +{ + "systemStatus": "unknownTemperatureAlarmLevel", + "shutdownOnOverheat": false, + "powercycleOnOverheat": false, + "actionOnOverheat": "actionUnknown", + "recoveryModeOnOverheat": "recoveryModeNA", + "ambientThreshold": 45, + "tempSensors": [], + "cardSlots": [], + "powerSupplySlots": [] +} diff --git a/test/eos/mocked_data/test_get_environment/ceos430/show_version.json b/test/eos/mocked_data/test_get_environment/ceos430/show_version.json new file mode 100644 index 000000000..ecdaba003 --- /dev/null +++ b/test/eos/mocked_data/test_get_environment/ceos430/show_version.json @@ -0,0 +1,22 @@ +{ + "mfgName": "Arista", + "modelName": "cEOSLab", + "hardwareRevision": "", + "serialNumber": "DE5B7D98C24A207BE70876CC0AD5546F", + "systemMacAddress": "00:1c:73:78:8e:81", + "hwMacAddress": "00:00:00:00:00:00", + "configMacAddress": "00:00:00:00:00:00", + "version": "4.30.0F-31408673.4300F (engineering build)", + "architecture": "x86_64", + "internalVersion": "4.30.0F-31408673.4300F", + "internalBuildId": "a35f0dc7-2d65-4f2a-a010-279cf445fd8c", + "imageFormatVersion": "1.0", + "imageOptimization": "None", + "cEosToolsVersion": "(unknown)", + "kernelVersion": "5.15.0-56-generic", + "bootupTimestamp": 1688840924.7556078, + "uptime": 6527.436209201813, + "memTotal": 231066228, + "memFree": 221986768, + "isIntlVersion": false +} diff --git a/test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_environment_cooling.json b/test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_system_environment_cooling.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_environment_cooling.json rename to test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_system_environment_cooling.json diff --git a/test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_environment_power.json b/test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_system_environment_power.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_environment_power.json rename to test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_system_environment_power.json diff --git a/test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_environment_temperature.json b/test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_system_environment_temperature.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_environment_temperature.json rename to test/eos/mocked_data/test_get_environment/issue1671_top_mb/show_system_environment_temperature.json diff --git a/test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_environment_cooling.json b/test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_system_environment_cooling.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_environment_cooling.json rename to test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_system_environment_cooling.json diff --git a/test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_environment_power.json b/test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_system_environment_power.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_environment_power.json rename to test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_system_environment_power.json diff --git a/test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_environment_temperature.json b/test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_system_environment_temperature.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_environment_temperature.json rename to test/eos/mocked_data/test_get_environment/issue80_stacktrace_for_get_environment/show_system_environment_temperature.json diff --git a/test/eos/mocked_data/test_get_environment/issue810_7010t/show_environment_cooling.json b/test/eos/mocked_data/test_get_environment/issue810_7010t/show_system_environment_cooling.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue810_7010t/show_environment_cooling.json rename to test/eos/mocked_data/test_get_environment/issue810_7010t/show_system_environment_cooling.json diff --git a/test/eos/mocked_data/test_get_environment/issue810_7010t/show_environment_power.json b/test/eos/mocked_data/test_get_environment/issue810_7010t/show_system_environment_power.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue810_7010t/show_environment_power.json rename to test/eos/mocked_data/test_get_environment/issue810_7010t/show_system_environment_power.json diff --git a/test/eos/mocked_data/test_get_environment/issue810_7010t/show_environment_temperature.json b/test/eos/mocked_data/test_get_environment/issue810_7010t/show_system_environment_temperature.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue810_7010t/show_environment_temperature.json rename to test/eos/mocked_data/test_get_environment/issue810_7010t/show_system_environment_temperature.json diff --git a/test/eos/mocked_data/test_get_environment/issue90_veos/show_environment_cooling.json b/test/eos/mocked_data/test_get_environment/issue90_veos/show_system_environment_cooling.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue90_veos/show_environment_cooling.json rename to test/eos/mocked_data/test_get_environment/issue90_veos/show_system_environment_cooling.json diff --git a/test/eos/mocked_data/test_get_environment/issue90_veos/show_environment_temperature.json b/test/eos/mocked_data/test_get_environment/issue90_veos/show_system_environment_temperature.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/issue90_veos/show_environment_temperature.json rename to test/eos/mocked_data/test_get_environment/issue90_veos/show_system_environment_temperature.json diff --git a/test/eos/mocked_data/test_get_environment/normal/show_environment_cooling.json b/test/eos/mocked_data/test_get_environment/normal/show_system_environment_cooling.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/normal/show_environment_cooling.json rename to test/eos/mocked_data/test_get_environment/normal/show_system_environment_cooling.json diff --git a/test/eos/mocked_data/test_get_environment/normal/show_environment_power.json b/test/eos/mocked_data/test_get_environment/normal/show_system_environment_power.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/normal/show_environment_power.json rename to test/eos/mocked_data/test_get_environment/normal/show_system_environment_power.json diff --git a/test/eos/mocked_data/test_get_environment/normal/show_environment_temperature.json b/test/eos/mocked_data/test_get_environment/normal/show_system_environment_temperature.json similarity index 100% rename from test/eos/mocked_data/test_get_environment/normal/show_environment_temperature.json rename to test/eos/mocked_data/test_get_environment/normal/show_system_environment_temperature.json From cc2c31019a2d7c7946572e6ed94752898df449de Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 10 Jul 2023 21:19:50 +0000 Subject: [PATCH 68/76] eos: update bgp getters for new syntax show ip bgp neigh -> show ip bgp peers --- napalm/eos/eos.py | 23 ++++---- ..._Local_AS_Desc_BGP_state__remote_rou.text} | 0 ..._Local_AS_Desc_BGP_state__remote_rou.text} | 0 ..._Local_AS_Desc_BGP_state__remote_rou.text} | 0 ..._Local_AS_Desc_BGP_state__remote_rou.text} | 0 ..._Local_AS_Desc_BGP_state__remote_rou.text} | 0 ..._Local_AS_Desc_BGP_state__remote_rou.text} | 0 ....text => show_ipv6_bgp_peers_vrf_all.text} | 0 ....text => show_ipv6_bgp_peers_vrf_all.text} | 0 ....text => show_ipv6_bgp_peers_vrf_all.text} | 0 ....text => show_ipv6_bgp_peers_vrf_all.text} | 0 ... show_ip_bgp_1_0_4_0_24__vrf_default.json} | 0 ... => show_ip_bgp_1_0_4_0_24__vrf_TEST.json} | 0 ... show_ip_bgp_1_0_4_0_24__vrf_default.json} | 0 ... show_ip_bgp_1_0_4_0_24__vrf_default.json} | 0 ... => show_ip_bgp_1_0_4_0_24__vrf_TEST.json} | 0 ... show_ip_bgp_1_0_4_0_24__vrf_default.json} | 0 ..._1_0_4_0_24_longer_prefixes_vrf_TEST.json} | 0 ...0_4_0_24_longer_prefixes_vrf_default.json} | 0 ...n => show_ip_bgp_1_0_4_0_25_vrf_TEST.json} | 0 ...> show_ip_bgp_1_0_4_0_25_vrf_default.json} | 0 ...w_ip_bgp_1_0_4_128_25_detail_vrf_TEST.json | 57 ------------------- ...p_bgp_1_0_4_128_25_detail_vrf_default.json | 57 ------------------- 23 files changed, 12 insertions(+), 125 deletions(-) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1168/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1356/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue1759/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/issue944/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors/normal/{show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text => show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors_detail/issue1416/{show_ipv6_bgp_neighbors_vrf_all.text => show_ipv6_bgp_peers_vrf_all.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors_detail/issue53/{show_ipv6_bgp_neighbors_vrf_all.text => show_ipv6_bgp_peers_vrf_all.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors_detail/issue68_neighbor_no_local_address/{show_ipv6_bgp_neighbors_vrf_all.text => show_ipv6_bgp_peers_vrf_all.text} (100%) rename test/eos/mocked_data/test_get_bgp_neighbors_detail/normal/{show_ipv6_bgp_neighbors_vrf_all.text => show_ipv6_bgp_peers_vrf_all.text} (100%) rename test/eos/mocked_data/test_get_route_to/iss_1069/{show_ip_bgp_1_0_4_0_24__detail_vrf_default.json => show_ip_bgp_1_0_4_0_24__vrf_default.json} (100%) rename test/eos/mocked_data/test_get_route_to/iss_1347/{show_ip_bgp_1_0_4_0_24__detail_vrf_TEST.json => show_ip_bgp_1_0_4_0_24__vrf_TEST.json} (100%) rename test/eos/mocked_data/test_get_route_to/iss_1347/{show_ip_bgp_1_0_4_0_24__detail_vrf_default.json => show_ip_bgp_1_0_4_0_24__vrf_default.json} (100%) rename test/eos/mocked_data/test_get_route_to/iss_736/{show_ip_bgp_1_0_4_0_24__detail_vrf_default.json => show_ip_bgp_1_0_4_0_24__vrf_default.json} (100%) rename test/eos/mocked_data/test_get_route_to/normal/{show_ip_bgp_1_0_4_0_24__detail_vrf_TEST.json => show_ip_bgp_1_0_4_0_24__vrf_TEST.json} (100%) rename test/eos/mocked_data/test_get_route_to/normal/{show_ip_bgp_1_0_4_0_24__detail_vrf_default.json => show_ip_bgp_1_0_4_0_24__vrf_default.json} (100%) rename test/eos/mocked_data/test_get_route_to_longer/normal/{show_ip_bgp_1_0_4_0_24_longer_prefixes_detail_vrf_TEST.json => show_ip_bgp_1_0_4_0_24_longer_prefixes_vrf_TEST.json} (100%) rename test/eos/mocked_data/test_get_route_to_longer/normal/{show_ip_bgp_1_0_4_0_24_longer_prefixes_detail_vrf_default.json => show_ip_bgp_1_0_4_0_24_longer_prefixes_vrf_default.json} (100%) rename test/eos/mocked_data/test_get_route_to_longer/normal/{show_ip_bgp_1_0_4_0_25_detail_vrf_TEST.json => show_ip_bgp_1_0_4_0_25_vrf_TEST.json} (100%) rename test/eos/mocked_data/test_get_route_to_longer/normal/{show_ip_bgp_1_0_4_0_25_detail_vrf_default.json => show_ip_bgp_1_0_4_0_25_vrf_default.json} (100%) delete mode 100644 test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_TEST.json delete mode 100644 test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_default.json diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 6c6d3f52f..76b86290b 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -680,13 +680,16 @@ def get_re_group(res, key, default=None): except KeyError: return default - NEIGHBOR_FILTER = "bgp neighbors vrf all | include IPv[46] (Unicast|6PE):.*[0-9]+ | grep -v ' IPv[46] Unicast:/.' | remote AS |^Local AS|Desc|BGP state |remote router ID" # noqa + NEIGHBOR_FILTER = "vrf all | include IPv[46] (Unicast|6PE):.*[0-9]+ | grep -v ' IPv[46] Unicast:/.' | remote AS |^Local AS|Desc|BGP state |remote router ID" # noqa output_summary_cmds = self._run_commands( ["show ipv6 bgp summary vrf all", "show ip bgp summary vrf all"], encoding="json", ) output_neighbor_cmds = self._run_commands( - ["show ip " + NEIGHBOR_FILTER, "show ipv6 " + NEIGHBOR_FILTER], + [ + "show ip bgp neighbors " + NEIGHBOR_FILTER, + "show ipv6 bgp peers " + NEIGHBOR_FILTER, + ], encoding="text", ) @@ -1519,13 +1522,11 @@ def get_route_to(self, destination="", protocol="", longer=False): nexthop_interface_map[nexthop_ip] = next_hop.get("interface") metric = route_details.get("metric") if _vrf not in vrf_cache.keys(): - command = ( - "show ip{ipv} bgp {dest} {longer} detail vrf {_vrf}".format( - ipv=ipv, - dest=destination, - longer="longer-prefixes" if longer else "", - _vrf=_vrf, - ) + command = "show ip{ipv} bgp {dest} {longer} vrf {_vrf}".format( + ipv=ipv, + dest=destination, + longer="longer-prefixes" if longer else "", + _vrf=_vrf, ) vrf_cache.update( { @@ -1933,7 +1934,7 @@ def _append(bgp_dict, peer_info): summary_commands = [] if not neighbor_address: commands.append("show ip bgp neighbors vrf all") - commands.append("show ipv6 bgp neighbors vrf all") + commands.append("show ipv6 bgp peers vrf all") summary_commands.append("show ip bgp summary vrf all") summary_commands.append("show ipv6 bgp summary vrf all") else: @@ -1946,7 +1947,7 @@ def _append(bgp_dict, peer_info): commands.append("show ip bgp neighbors %s vrf all" % neighbor_address) summary_commands.append("show ip bgp summary vrf all") elif peer_ver == 6: - commands.append("show ipv6 bgp neighbors %s vrf all" % neighbor_address) + commands.append("show ipv6 bgp peers %s vrf all" % neighbor_address) summary_commands.append("show ipv6 bgp summary vrf all") raw_output = self._run_commands(commands, encoding="text") diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1168/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1356/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue1759/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue58_neighbor_down/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/issue944/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text b/test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_neighbors_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote.text rename to test/eos/mocked_data/test_get_bgp_neighbors/normal/show_ipv6_bgp_peers_vrf_all___include_IPv_46___Unicast_6PE_____0_9_____grep__v___IPv_46__Unicast_______remote_AS___Local_AS_Desc_BGP_state__remote_rou.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors_detail/issue1416/show_ipv6_bgp_neighbors_vrf_all.text b/test/eos/mocked_data/test_get_bgp_neighbors_detail/issue1416/show_ipv6_bgp_peers_vrf_all.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors_detail/issue1416/show_ipv6_bgp_neighbors_vrf_all.text rename to test/eos/mocked_data/test_get_bgp_neighbors_detail/issue1416/show_ipv6_bgp_peers_vrf_all.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors_detail/issue53/show_ipv6_bgp_neighbors_vrf_all.text b/test/eos/mocked_data/test_get_bgp_neighbors_detail/issue53/show_ipv6_bgp_peers_vrf_all.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors_detail/issue53/show_ipv6_bgp_neighbors_vrf_all.text rename to test/eos/mocked_data/test_get_bgp_neighbors_detail/issue53/show_ipv6_bgp_peers_vrf_all.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors_detail/issue68_neighbor_no_local_address/show_ipv6_bgp_neighbors_vrf_all.text b/test/eos/mocked_data/test_get_bgp_neighbors_detail/issue68_neighbor_no_local_address/show_ipv6_bgp_peers_vrf_all.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors_detail/issue68_neighbor_no_local_address/show_ipv6_bgp_neighbors_vrf_all.text rename to test/eos/mocked_data/test_get_bgp_neighbors_detail/issue68_neighbor_no_local_address/show_ipv6_bgp_peers_vrf_all.text diff --git a/test/eos/mocked_data/test_get_bgp_neighbors_detail/normal/show_ipv6_bgp_neighbors_vrf_all.text b/test/eos/mocked_data/test_get_bgp_neighbors_detail/normal/show_ipv6_bgp_peers_vrf_all.text similarity index 100% rename from test/eos/mocked_data/test_get_bgp_neighbors_detail/normal/show_ipv6_bgp_neighbors_vrf_all.text rename to test/eos/mocked_data/test_get_bgp_neighbors_detail/normal/show_ipv6_bgp_peers_vrf_all.text diff --git a/test/eos/mocked_data/test_get_route_to/iss_1069/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json b/test/eos/mocked_data/test_get_route_to/iss_1069/show_ip_bgp_1_0_4_0_24__vrf_default.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to/iss_1069/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json rename to test/eos/mocked_data/test_get_route_to/iss_1069/show_ip_bgp_1_0_4_0_24__vrf_default.json diff --git a/test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__detail_vrf_TEST.json b/test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__vrf_TEST.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__detail_vrf_TEST.json rename to test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__vrf_TEST.json diff --git a/test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json b/test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__vrf_default.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json rename to test/eos/mocked_data/test_get_route_to/iss_1347/show_ip_bgp_1_0_4_0_24__vrf_default.json diff --git a/test/eos/mocked_data/test_get_route_to/iss_736/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json b/test/eos/mocked_data/test_get_route_to/iss_736/show_ip_bgp_1_0_4_0_24__vrf_default.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to/iss_736/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json rename to test/eos/mocked_data/test_get_route_to/iss_736/show_ip_bgp_1_0_4_0_24__vrf_default.json diff --git a/test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__detail_vrf_TEST.json b/test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__vrf_TEST.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__detail_vrf_TEST.json rename to test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__vrf_TEST.json diff --git a/test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json b/test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__vrf_default.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__detail_vrf_default.json rename to test/eos/mocked_data/test_get_route_to/normal/show_ip_bgp_1_0_4_0_24__vrf_default.json diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_detail_vrf_TEST.json b/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_vrf_TEST.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_detail_vrf_TEST.json rename to test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_vrf_TEST.json diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_detail_vrf_default.json b/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_vrf_default.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_detail_vrf_default.json rename to test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_24_longer_prefixes_vrf_default.json diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_detail_vrf_TEST.json b/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_vrf_TEST.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_detail_vrf_TEST.json rename to test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_vrf_TEST.json diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_detail_vrf_default.json b/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_vrf_default.json similarity index 100% rename from test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_detail_vrf_default.json rename to test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_0_25_vrf_default.json diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_TEST.json b/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_TEST.json deleted file mode 100644 index 1789d4dd3..000000000 --- a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_TEST.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "vrfs": { - "TEST": { - "routerId": "192.168.256.1", - "vrf": "default", - "bgpRouteEntries": { - "1.0.4.128/25": { - "totalPaths": 1, - "bgpAdvertisedPeerGroups": {}, - "totalAdvertisedPeers": 0, - "maskLength": 20, - "bgpRoutePaths": [ - { - "asPathEntry": { - "asPathType": "External", - "asPath": "1299 15169 43515" - }, - "med": 0, - "localPreference": 50, - "weight": 0, - "nextHop": "192.168.0.5", - "routeType": { - "atomicAggregator": false, - "valid": true, - "ecmpContributor": false, - "active": true, - "backup": false, - "stale": false, - "suppressed": false, - "ecmpHead": false, - "queued": false, - "ecmp": false - }, - "routeDetail": { - "origin": "Igp", - "peerEntry": { - "peerRouterId": "192.168.256.1", - "peerAddr": "192.168.0.5" - }, - "extCommunityList": [], - "communityList": [ - "1299:1234", - "1299:5678", - "1299:91011", - "1299:12134" - ], - "recvdFromRRClient": false - } - } - ], - "address": "1.0.4.128" - } - }, - "asn": 13335 - } - } -} diff --git a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_default.json b/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_default.json deleted file mode 100644 index 6ac90ca10..000000000 --- a/test/eos/mocked_data/test_get_route_to_longer/normal/show_ip_bgp_1_0_4_128_25_detail_vrf_default.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "vrfs": { - "default": { - "routerId": "192.168.256.1", - "vrf": "default", - "bgpRouteEntries": { - "1.0.4.128/25": { - "totalPaths": 1, - "bgpAdvertisedPeerGroups": {}, - "totalAdvertisedPeers": 0, - "maskLength": 20, - "bgpRoutePaths": [ - { - "asPathEntry": { - "asPathType": "External", - "asPath": "1299 15169 43515" - }, - "med": 0, - "localPreference": 50, - "weight": 0, - "nextHop": "192.168.0.5", - "routeType": { - "atomicAggregator": false, - "valid": true, - "ecmpContributor": false, - "active": true, - "backup": false, - "stale": false, - "suppressed": false, - "ecmpHead": false, - "queued": false, - "ecmp": false - }, - "routeDetail": { - "origin": "Igp", - "peerEntry": { - "peerRouterId": "192.168.256.1", - "peerAddr": "192.168.0.5" - }, - "extCommunityList": [], - "communityList": [ - "1299:1234", - "1299:5678", - "1299:91011", - "1299:12134" - ], - "recvdFromRRClient": false - } - } - ], - "address": "1.0.4.128" - } - }, - "asn": 13335 - } - } -} From 75461b6065ffbf386e5164b107e7bd66b549b866 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Mon, 10 Jul 2023 21:49:32 +0000 Subject: [PATCH 69/76] eos: update get_snmp_information command syntax show snmp -> show snmp v2-mib --- napalm/eos/eos.py | 6 +++++- ...show_snmp_chassis.json => show_snmp_v2_mib_chassis.json} | 0 ...show_snmp_contact.json => show_snmp_v2_mib_contact.json} | 0 ...ow_snmp_location.json => show_snmp_v2_mib_location.json} | 0 4 files changed, 5 insertions(+), 1 deletion(-) rename test/eos/mocked_data/test_get_snmp_information/normal/{show_snmp_chassis.json => show_snmp_v2_mib_chassis.json} (100%) rename test/eos/mocked_data/test_get_snmp_information/normal/{show_snmp_contact.json => show_snmp_v2_mib_contact.json} (100%) rename test/eos/mocked_data/test_get_snmp_information/normal/{show_snmp_location.json => show_snmp_v2_mib_location.json} (100%) diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 76b86290b..71f5c5743 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -1640,7 +1640,11 @@ def get_snmp_information(self): # Default values snmp_dict = {"chassis_id": "", "location": "", "contact": "", "community": {}} - commands = ["show snmp chassis", "show snmp location", "show snmp contact"] + commands = [ + "show snmp v2-mib chassis", + "show snmp v2-mib location", + "show snmp v2-mib contact", + ] snmp_config = self._run_commands(commands, encoding="json") for line in snmp_config: for k, v in line.items(): diff --git a/test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_chassis.json b/test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_v2_mib_chassis.json similarity index 100% rename from test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_chassis.json rename to test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_v2_mib_chassis.json diff --git a/test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_contact.json b/test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_v2_mib_contact.json similarity index 100% rename from test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_contact.json rename to test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_v2_mib_contact.json diff --git a/test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_location.json b/test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_v2_mib_location.json similarity index 100% rename from test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_location.json rename to test/eos/mocked_data/test_get_snmp_information/normal/show_snmp_v2_mib_location.json From 805f98f7f458da31807d58ca1a863f9551b93283 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Wed, 11 Oct 2023 16:20:01 -0500 Subject: [PATCH 70/76] eos: update get_users commands show user-accounts -> show users accounts --- napalm/eos/eos.py | 2 +- .../{show_user_account.json => show_users_accounts.json} | 0 .../normal/{show_user_account.json => show_users_accounts.json} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename test/eos/mocked_data/test_get_users/no_sshkey/{show_user_account.json => show_users_accounts.json} (100%) rename test/eos/mocked_data/test_get_users/normal/{show_user_account.json => show_users_accounts.json} (100%) diff --git a/napalm/eos/eos.py b/napalm/eos/eos.py index 71f5c5743..2a4c209df 100644 --- a/napalm/eos/eos.py +++ b/napalm/eos/eos.py @@ -1679,7 +1679,7 @@ def _sshkey_type(sshkey): users = {} - commands = ["show user-account"] + commands = ["show users accounts"] user_items = self._run_commands(commands)[0].get("users", {}) for user, user_details in user_items.items(): diff --git a/test/eos/mocked_data/test_get_users/no_sshkey/show_user_account.json b/test/eos/mocked_data/test_get_users/no_sshkey/show_users_accounts.json similarity index 100% rename from test/eos/mocked_data/test_get_users/no_sshkey/show_user_account.json rename to test/eos/mocked_data/test_get_users/no_sshkey/show_users_accounts.json diff --git a/test/eos/mocked_data/test_get_users/normal/show_user_account.json b/test/eos/mocked_data/test_get_users/normal/show_users_accounts.json similarity index 100% rename from test/eos/mocked_data/test_get_users/normal/show_user_account.json rename to test/eos/mocked_data/test_get_users/normal/show_users_accounts.json From 9c09afe0c171ea2e61b18237082a788b0f3a0fd6 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Fri, 13 Oct 2023 15:46:58 -0500 Subject: [PATCH 71/76] eos: add optional real-device integration test --- test/eos/test_integration.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 test/eos/test_integration.py diff --git a/test/eos/test_integration.py b/test/eos/test_integration.py new file mode 100644 index 000000000..fc14e05c0 --- /dev/null +++ b/test/eos/test_integration.py @@ -0,0 +1,31 @@ +import os +import pytest + +from napalm.eos import eos +from napalm.base.base import NetworkDriver + + +@pytest.fixture +def integration_device(): + with eos.EOSDriver( + os.environ["NAPALM_INTEGRATION_HOST"], + os.environ["NAPALM_USERNAME"], + os.environ["NAPALM_PASSWORD"], + ) as d: + yield d + + +@pytest.mark.skipif( + os.getenv("NAPALM_INTEGRATION_HOST") is None, reason="No integration host specified" +) +def test_eos_foo(integration_device): + getters = [s for s in dir(NetworkDriver) if s.startswith("get_")] + + getter_options = {"get_route_to": {"destination": "0.0.0.0/0", "longer": True}} + + for getter in getters: + try: + ret = getattr(integration_device, getter)(**getter_options.get(getter, {})) + assert ret + except NotImplementedError: + pass From 1858e725d582be1b11c056a62a7768c3293d6fa3 Mon Sep 17 00:00:00 2001 From: Urs Baumann Date: Mon, 23 Oct 2023 18:41:23 +0200 Subject: [PATCH 72/76] NXOS_SSH/IOS XE IPv6 Regex update (#2016) --- napalm/ios/ios.py | 2 +- napalm/nxos_ssh/nxos_ssh.py | 17 ++++-- .../ipv6/expected_result.json | 59 +++++++++++++++++++ .../ipv6/show_bgp_all_summary_vrf_all.txt | 29 +++++++++ 4 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/expected_result.json create mode 100644 test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/show_bgp_all_summary_vrf_all.txt diff --git a/napalm/ios/ios.py b/napalm/ios/ios.py index df7a78400..322962c70 100644 --- a/napalm/ios/ios.py +++ b/napalm/ios/ios.py @@ -59,7 +59,7 @@ IP_ADDR_REGEX = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" IPV4_ADDR_REGEX = IP_ADDR_REGEX IPV6_ADDR_REGEX_1 = r"::" -IPV6_ADDR_REGEX_2 = r"[0-9a-fA-F:]{1,39}::[0-9a-fA-F:]{1,39}" +IPV6_ADDR_REGEX_2 = r"[0-9a-fA-F:]{0,39}::[0-9a-fA-F:]{0,39}" IPV6_ADDR_REGEX_3 = ( r"[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}:" "[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}:[0-9a-fA-F]{1,4}" diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index bdb01f5a9..6fa051937 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -38,7 +38,7 @@ IP_ADDR_REGEX = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" IPV4_ADDR_REGEX = IP_ADDR_REGEX IPV6_ADDR_REGEX_1 = r"::" -IPV6_ADDR_REGEX_2 = r"[0-9a-fA-F:]{1,39}::[0-9a-fA-F:]{1,39}" +IPV6_ADDR_REGEX_2 = r"[0-9a-fA-F:]{0,39}::[0-9a-fA-F:]{0,39}" IPV6_ADDR_REGEX_3 = ( r"[0-9a-fA-F]{1,3}:[0-9a-fA-F]{1,3}:[0-9a-fA-F]{1,3}:[0-9a-fA-F]{1,3}:" r"[0-9a-fA-F]{1,3}:[0-9a-fA-F]{1,3}:[0-9a-fA-F]{1,3}:[0-9a-fA-F]{1,3}" @@ -264,13 +264,22 @@ def bgp_normalize_table_data(bgp_table): 4 65535 163664 163693 145 0 0 3w2d 3 2001:db8:e0:dd::1 4 10 327491 327278 145 0 0 3w1d 4 + 2001:db8:e0:df:: + 4 12345678 + 327465 327268 145 0 0 3w1d 4 Normalize this so the line wrap doesn't exit. """ bgp_table = bgp_table.strip() - bgp_multiline_pattern = r"({})\s*\n".format(IPV4_OR_IPV6_REGEX) - # Strip out the newline - return re.sub(bgp_multiline_pattern, r"\1", bgp_table) + # Remove newline after ipv6 address + bgp_ipv6_multiline_pattern = r"({})\s*\n".format(IPV4_OR_IPV6_REGEX) + bgp_table = re.sub(bgp_ipv6_multiline_pattern, r"\1", bgp_table) + # Remove newline after a long AS number + bgp_long_as_multiline_pattern = r"((?:{})\s*\d*\s*\d*)\s*\n".format( + IPV4_OR_IPV6_REGEX + ) + bgp_table = re.sub(bgp_long_as_multiline_pattern, r"\1", bgp_table) + return bgp_table def bgp_table_parser(bgp_table): diff --git a/test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/expected_result.json b/test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/expected_result.json new file mode 100644 index 000000000..7623433ae --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/expected_result.json @@ -0,0 +1,59 @@ +{ + "RED3": { + "router_id": "10.1.0.18", + "peers": { + "2001:db8:4:701::2": { + "is_enabled": true, + "uptime": 1987200, + "remote_as": 65535, + "address_family": { + "ipv6": { + "sent_prefixes": -1, + "accepted_prefixes": -1, + "received_prefixes": 3 + } + }, + "is_up": true, + "remote_id": "0.0.0.0", + "local_as": 65535, + "description": "" + }, + "2001:db8:e0:df::": { + "is_enabled": true, + "uptime": 1900800, + "remote_as": 12345678, + "address_family": { + "ipv6": { + "sent_prefixes": -1, + "accepted_prefixes": -1, + "received_prefixes": 4 + } + }, + "is_up": true, + "remote_id": "0.0.0.0", + "local_as": 65535, + "description": "" + }, + "2001:db8:e0:dd::1": { + "is_enabled": true, + "uptime": 1900800, + "remote_as": 10, + "address_family": { + "ipv6": { + "sent_prefixes": -1, + "accepted_prefixes": -1, + "received_prefixes": 4 + } + }, + "is_up": true, + "remote_id": "0.0.0.0", + "local_as": 65535, + "description": "" + } + } + }, + "global": { + "router_id": "10.1.0.16", + "peers": {} + } +} \ No newline at end of file diff --git a/test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/show_bgp_all_summary_vrf_all.txt b/test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/show_bgp_all_summary_vrf_all.txt new file mode 100644 index 000000000..7287514bc --- /dev/null +++ b/test/nxos_ssh/mocked_data/test_get_bgp_neighbors/ipv6/show_bgp_all_summary_vrf_all.txt @@ -0,0 +1,29 @@ +BGP summary information for VRF default, address family IPv4 Unicast +BGP router identifier 10.1.0.16, local AS number 65535 +BGP table version is 361, IPv4 Unicast config peers 2, capable peers 2 +13 network entries and 17 paths using 2224 bytes of memory +BGP attribute entries [4/576], BGP AS path entries [1/14] +BGP community entries [295/10792], BGP clusterlist entries [0/0] +13 received paths for inbound soft reconfiguration +4 identical, 9 modified, 0 filtered received paths using 72 bytes + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd + + +BGP summary information for VRF RED3, address family IPv6 Unicast +BGP router identifier 10.1.0.18, local AS number 65535 +BGP table version is 145, IPv6 Unicast config peers 3, capable peers 3 +12 network entries and 15 paths using 2136 bytes of memory +BGP attribute entries [16/2304], BGP AS path entries [6/72] +BGP community entries [295/10792], BGP clusterlist entries [0/0] +11 received paths for inbound soft reconfiguration +3 identical, 8 modified, 0 filtered received paths using 64 bytes + +Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd +2001:db8:4:701::2 + 4 65535 163664 163693 145 0 0 3w2d 3 +2001:db8:e0:dd::1 + 4 10 327491 327278 145 0 0 3w1d 4 +2001:db8:e0:df:: + 4 12345678 + 327465 327268 145 0 0 3w1d 4 From d9c41a55a1ee1742c9509913443d2cca2c7a21ec Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 15 Nov 2023 09:37:37 -0800 Subject: [PATCH 73/76] Drop PY3.7 support in napalm 5.0.0; add PY3.12 tests --- .github/workflows/commit.yaml | 2 +- README.md | 3 +++ setup.py | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/commit.yaml b/.github/workflows/commit.yaml index 0329a5554..8494d6c4b 100644 --- a/.github/workflows/commit.yaml +++ b/.github/workflows/commit.yaml @@ -10,7 +10,7 @@ jobs: strategy: max-parallel: 4 matrix: - python-version: [3.7, 3.8, 3.9, 3.10.9, 3.11] + python-version: [3.8, 3.9, 3.10.9, 3.11, 3.12.0] steps: - name: Checkout repository diff --git a/README.md b/README.md index 5a642d103..764f39bff 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,9 @@ Install pip install napalm ``` +*Note*: Beginning with release 5.0.0 and later, NAPALM offers support for +Python 3.8+ only. + *Note*: Beginning with release 4.0.0 and later, NAPALM offers support for Python 3.7+ only. diff --git a/setup.py b/setup.py index 0a3bbe374..25bf112df 100644 --- a/setup.py +++ b/setup.py @@ -26,10 +26,11 @@ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Operating System :: POSIX :: Linux", "Operating System :: MacOS", ], From cc84e926cc1c848fbefe55831c6d61e713d90d3a Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 15 Nov 2023 09:38:40 -0800 Subject: [PATCH 74/76] Require ncclient >= 0.6.15 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7a20077a..66ba95708 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ netmiko>=4.1.0 junos-eznc>=2.6.3 scp lxml>=4.3.0 -ncclient +ncclient>=0.6.15 ttp ttp_templates netutils>=1.0.0 From b762c194ec42a35d5f26f65ae66acfc1605c59ed Mon Sep 17 00:00:00 2001 From: Kirk Byers Date: Wed, 15 Nov 2023 09:43:26 -0800 Subject: [PATCH 75/76] PIP dependency resolver wouldn't allow this --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 66ba95708..b7a20077a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ netmiko>=4.1.0 junos-eznc>=2.6.3 scp lxml>=4.3.0 -ncclient>=0.6.15 +ncclient ttp ttp_templates netutils>=1.0.0 From d3dd5d26153871eb78fb0cd84b2eca865330a235 Mon Sep 17 00:00:00 2001 From: Brandon Ewing Date: Wed, 31 Jan 2024 10:12:32 -0600 Subject: [PATCH 76/76] require junos-eznc >= 2.7.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7a20077a..ccd3ef5b2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ netaddr pyYAML pyeapi>=1.0.2 netmiko>=4.1.0 -junos-eznc>=2.6.3 +junos-eznc>=2.7.0 scp lxml>=4.3.0 ncclient