From 3ebfba8eafb562d4f23ebc2d30b4fdb6438ab942 Mon Sep 17 00:00:00 2001 From: Arzhel Younsi Date: Fri, 10 Feb 2017 11:59:42 +1100 Subject: [PATCH 1/7] Fix issues #201 (#203) * Fix for multiple getters Fix for issue reported in: https://github.com/napalm-automation/napalm-base/issues/180#issuecomment-277608980 After getting a suggestion of how to fix it from @dbarrosop * Remove converting a dict to a list of 1 dict Per review suggestion. * Fix tests * Fix tests, add _name tests * Fix regex issue, add test * Fix pylama issue --- napalm_base/validate.py | 41 ++++--- .../mocked_data/non_strict_fail/validate.yml | 70 ++++++------ .../mocked_data/non_strict_pass/validate.yml | 66 +++++------ .../mocked_data/strict_fail/validate.yml | 82 +++++++------- .../strict_pass/get_lldp_neighbors.json | 10 ++ .../mocked_data/strict_pass/report.yml | 16 ++- .../mocked_data/strict_pass/validate.yml | 107 +++++++++++------- .../mocked_data/strict_pass_skip/validate.yml | 60 +++++----- 8 files changed, 255 insertions(+), 197 deletions(-) create mode 100644 test/unit/validate/mocked_data/strict_pass/get_lldp_neighbors.json diff --git a/napalm_base/validate.py b/napalm_base/validate.py index a6362fab..be53f8af 100644 --- a/napalm_base/validate.py +++ b/napalm_base/validate.py @@ -123,27 +123,42 @@ def _compare_getter(src, dst): if isinstance(src, py23_compat.string_types): m = re.search(src, py23_compat.text_type(dst)) return m is not None + elif(type(src) == type(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])] + for x, y in pairs if x != y] + return empty_tree(diff_lists) else: return src == dst +def empty_tree(input_list): + """Recursively iterate through values in nested lists.""" + for item in input_list: + if not isinstance(item, list) or not empty_tree(item): + return False + return True + + def compliance_report(cls, validation_file=None): report = {} validation_source = _get_validation_file(validation_file) - for getter, expected_results in validation_source.items(): - if getter == "get_config": - # TBD - pass - else: - key = expected_results.pop("_name", "") or getter - - try: - kwargs = expected_results.pop('_kwargs', {}) - actual_results = getattr(cls, getter)(**kwargs) - report[key] = _compare_getter(expected_results, actual_results) - except NotImplementedError: - report[key] = {"skipped": True, "reason": "NotImplemented"} + for validation_check in validation_source: + for getter, expected_results in validation_check.items(): + if getter == "get_config": + # TBD + pass + else: + key = expected_results.pop("_name", "") or getter + + try: + kwargs = expected_results.pop('_kwargs', {}) + actual_results = getattr(cls, getter)(**kwargs) + report[key] = _compare_getter(expected_results, actual_results) + except NotImplementedError: + report[key] = {"skipped": True, "reason": "NotImplemented"} complies = all([e.get("complies", True) for e in report.values()]) report["skipped"] = [k for k, v in report.items() if v.get("skipped", False)] diff --git a/test/unit/validate/mocked_data/non_strict_fail/validate.yml b/test/unit/validate/mocked_data/non_strict_fail/validate.yml index 4332402b..efec536e 100644 --- a/test/unit/validate/mocked_data/non_strict_fail/validate.yml +++ b/test/unit/validate/mocked_data/non_strict_fail/validate.yml @@ -1,39 +1,39 @@ --- -get_facts: - os_version: 7.0\(3\)I2\(2d\) - interface_list: - list: - - Vlan5 - - Vlan666 - hostname: n9k2 +- get_facts: + os_version: 7.0\(3\)I2\(2d\) + interface_list: + list: + - Vlan5 + - Vlan666 + hostname: n9k2 -get_bgp_neighbors: - default: - router_id: 192.6.6.6 - peers: - 192.6.7.8: - is_enabled: false - 192.0.2.3: - is_enabled: false - 192.0.2.2: - is_enabled: true - address_family: - ipv4: - sent_prefixes: 5 - ipv6: - sent_prefixes: 6 +- get_bgp_neighbors: + default: + router_id: 192.6.6.6 + peers: + 192.6.7.8: + is_enabled: false + 192.0.2.3: + is_enabled: false + 192.0.2.2: + is_enabled: true + address_family: + ipv4: + sent_prefixes: 5 + ipv6: + sent_prefixes: 6 -get_interfaces_ip: - Ethernet2/1: - ipv4: - 192.0.2.1: - prefix_length: 30 +- get_interfaces_ip: + Ethernet2/1: + ipv4: + 192.0.2.1: + prefix_length: 30 -get_route_to: - _kwargs: - destination: 185.155.180.192/26 - "10.155.180.192/26": - list: - - next_hop: 10.155.180.22 - outgoing_interface: "irb.0" - protocol: "OSPF" +- get_route_to: + _kwargs: + destination: 185.155.180.192/26 + "10.155.180.192/26": + list: + - next_hop: 10.155.180.22 + outgoing_interface: "irb.0" + protocol: "OSPF" diff --git a/test/unit/validate/mocked_data/non_strict_pass/validate.yml b/test/unit/validate/mocked_data/non_strict_pass/validate.yml index 3b07451c..f079f380 100644 --- a/test/unit/validate/mocked_data/non_strict_pass/validate.yml +++ b/test/unit/validate/mocked_data/non_strict_pass/validate.yml @@ -1,37 +1,37 @@ --- -get_facts: - os_version: 7.0\(3\)I2\(2d\) - interface_list: - list: - - Vlan5 - - Vlan100 - hostname: n9k2 +- get_facts: + os_version: 7.0\(3\)I2\(2d\) + interface_list: + list: + - Vlan5 + - Vlan100 + hostname: n9k2 -get_bgp_neighbors: - default: - router_id: 192.0.2.2 - peers: - 192.0.2.3: - is_enabled: false - 192.0.2.2: - is_enabled: true - address_family: - ipv4: - sent_prefixes: 5 - ipv6: - sent_prefixes: 2 +- get_bgp_neighbors: + default: + router_id: 192.0.2.2 + peers: + 192.0.2.3: + is_enabled: false + 192.0.2.2: + is_enabled: true + address_family: + ipv4: + sent_prefixes: 5 + ipv6: + sent_prefixes: 2 -get_interfaces_ip: - Ethernet2/1: - ipv4: - 192.0.2.1: - prefix_length: 30 +- get_interfaces_ip: + Ethernet2/1: + ipv4: + 192.0.2.1: + prefix_length: 30 -get_route_to: - _kwargs: - destination: 185.155.180.192/26 - "10.155.180.192/26": - list: - - next_hop: 10.155.180.22 - outgoing_interface: "irb.0" - protocol: "BGP" +- get_route_to: + _kwargs: + destination: 185.155.180.192/26 + "10.155.180.192/26": + list: + - next_hop: 10.155.180.22 + outgoing_interface: "irb.0" + protocol: "BGP" diff --git a/test/unit/validate/mocked_data/strict_fail/validate.yml b/test/unit/validate/mocked_data/strict_fail/validate.yml index 9e27ac32..605b7cff 100644 --- a/test/unit/validate/mocked_data/strict_fail/validate.yml +++ b/test/unit/validate/mocked_data/strict_fail/validate.yml @@ -1,46 +1,46 @@ --- -get_facts: - os_version: 7.0\(3\)I2\(2d\) - interface_list: - _mode: strict - list: - - Vlan5 - - Vlan100 - hostname: n9k2 +- get_facts: + os_version: 7.0\(3\)I2\(2d\) + interface_list: + _mode: strict + list: + - Vlan5 + - Vlan100 + hostname: n9k2 -get_bgp_neighbors: - default: - router_id: 192.0.2.2 - peers: - _mode: strict - 192.0.2.2: - is_enabled: true - address_family: - ipv4: - sent_prefixes: ^[1-9] - ipv6: - sent_prefixes: ^[1-9] +- get_bgp_neighbors: + default: + router_id: 192.0.2.2 + peers: + _mode: strict + 192.0.2.2: + is_enabled: true + address_family: + ipv4: + sent_prefixes: ^[1-9] + ipv6: + sent_prefixes: ^[1-9] -get_route_to: - _kwargs: - destination: 185.155.180.192/26 - "10.155.180.192/26": - list: - - next_hop: 10.155.180.22 - outgoing_interface: "irb.0" - protocol: "BGP" - _mode: strict +- get_route_to: + _kwargs: + destination: 185.155.180.192/26 + "10.155.180.192/26": + list: + - next_hop: 10.155.180.22 + outgoing_interface: "irb.0" + protocol: "BGP" + _mode: strict -get_interfaces_ip: - Ethernet2/1: - ipv4: - 192.0.2.1: - prefix_length: 30 +- get_interfaces_ip: + Ethernet2/1: + ipv4: + 192.0.2.1: + prefix_length: 30 -ping: - _kwargs: - destination: 8.8.8.8 - source: 192.168.1.1 - success: - packet_loss: 0 - _mode: strict +- ping: + _kwargs: + destination: 8.8.8.8 + source: 192.168.1.1 + success: + packet_loss: 0 + _mode: strict diff --git a/test/unit/validate/mocked_data/strict_pass/get_lldp_neighbors.json b/test/unit/validate/mocked_data/strict_pass/get_lldp_neighbors.json new file mode 100644 index 00000000..de6cd42e --- /dev/null +++ b/test/unit/validate/mocked_data/strict_pass/get_lldp_neighbors.json @@ -0,0 +1,10 @@ +{ + "ge-1/0/2": [{ + "hostname": "fw1b.private.lon2", + "port": "ethernet1/13" + }], + "ge-1/0/3": [{ + "hostname": "border2.private.lon2", + "port": "519" + }] +} diff --git a/test/unit/validate/mocked_data/strict_pass/report.yml b/test/unit/validate/mocked_data/strict_pass/report.yml index 23e14207..f3aae2c8 100644 --- a/test/unit/validate/mocked_data/strict_pass/report.yml +++ b/test/unit/validate/mocked_data/strict_pass/report.yml @@ -27,9 +27,23 @@ get_interfaces_ip: missing: [] present: Ethernet2/1: {complies: true, nested: true} -ping: +ping1: complies: true extra: [] missing: [] present: success: {complies: true, nested: true} +ping2: + complies: true + extra: [] + missing: [] + present: + success: {complies: true, nested: true} + +get_lldp_neighbors: + complies: true + extra: [] + missing: [] + present: + ge-1/0/2: {complies: true, nested: false} + ge-1/0/3: {complies: true, nested: False} diff --git a/test/unit/validate/mocked_data/strict_pass/validate.yml b/test/unit/validate/mocked_data/strict_pass/validate.yml index 4a63e0c6..d95b0620 100644 --- a/test/unit/validate/mocked_data/strict_pass/validate.yml +++ b/test/unit/validate/mocked_data/strict_pass/validate.yml @@ -1,51 +1,70 @@ --- -get_facts: - os_version: 7.0\(3\)I2\(2d\) - interface_list: - _mode: strict - list: [Vlan5,Vlan100, Vlan40, Vlan41, GigabitEthernet0/1, GigabitEthernet0/2, GigabitEthernet0/3, - GigabitEthernet0/4, GigabitEthernet0/5, GigabitEthernet0/6, GigabitEthernet0/7, - GigabitEthernet0/8, Port-channel1] - hostname: n9k2 +- get_facts: + os_version: 7.0\(3\)I2\(2d\) + interface_list: + _mode: strict + list: [Vlan5,Vlan100, Vlan40, Vlan41, GigabitEthernet0/1, GigabitEthernet0/2, GigabitEthernet0/3, + GigabitEthernet0/4, GigabitEthernet0/5, GigabitEthernet0/6, GigabitEthernet0/7, + GigabitEthernet0/8, Port-channel1] + hostname: n9k2 -ping: - _kwargs: - destination: 8.8.8.8 - source: 192.168.1.1 - success: - packet_loss: 0 - _mode: strict +- ping: + _name: ping1 + _kwargs: + destination: 8.8.8.8 + source: 192.168.1.1 + success: + packet_loss: 0 + _mode: strict -get_route_to: - _kwargs: - destination: 185.155.180.192/26 - "10.155.180.192/26": - list: - - next_hop: 10.155.180.22 - outgoing_interface: "irb.0" - protocol: "BGP" - - next_hop: 10.155.180.18 - outgoing_interface: "ge-1/0/0.0" - protocol: "BGP" +- ping: + _name: ping2 + _kwargs: + destination: 8.8.8.8 + source: 192.168.1.1 + success: + packet_loss: 0 _mode: strict -get_bgp_neighbors: - default: - router_id: 192.0.2.2 - peers: +- get_route_to: + _kwargs: + destination: 185.155.180.192/26 + "10.155.180.192/26": + list: + - next_hop: 10.155.180.22 + outgoing_interface: "irb.0" + protocol: "BGP" + - next_hop: 10.155.180.18 + outgoing_interface: "ge-1/0/0.0" + protocol: "BGP" _mode: strict - 192.0.2.3: - is_enabled: false - 192.0.2.2: - is_enabled: true - address_family: - ipv4: - sent_prefixes: ^[1-9] - ipv6: - sent_prefixes: ^[1-9] -get_interfaces_ip: - Ethernet2/1: - ipv4: - 192.0.2.1: - prefix_length: 30 +- get_bgp_neighbors: + default: + router_id: 192.0.2.2 + peers: + _mode: strict + 192.0.2.3: + is_enabled: false + 192.0.2.2: + is_enabled: true + address_family: + ipv4: + sent_prefixes: ^[1-9] + ipv6: + sent_prefixes: ^[1-9] + +- get_interfaces_ip: + Ethernet2/1: + ipv4: + 192.0.2.1: + prefix_length: 30 + +- get_lldp_neighbors: + _mode: strict + ge-1/0/2: + - hostname: fw1[ab].private.lon2 + port: "ethernet1/13" + ge-1/0/3: + - hostname: "border2.private.lon2" + port: "519" diff --git a/test/unit/validate/mocked_data/strict_pass_skip/validate.yml b/test/unit/validate/mocked_data/strict_pass_skip/validate.yml index 231574a8..13e8a957 100644 --- a/test/unit/validate/mocked_data/strict_pass_skip/validate.yml +++ b/test/unit/validate/mocked_data/strict_pass_skip/validate.yml @@ -1,34 +1,34 @@ --- -get_facts: - os_version: 7.0\(3\)I2\(2d\) - interface_list: - _mode: strict - list: [Vlan5,Vlan100, Vlan40, Vlan41, GigabitEthernet0/1, GigabitEthernet0/2, GigabitEthernet0/3, - GigabitEthernet0/4, GigabitEthernet0/5, GigabitEthernet0/6, GigabitEthernet0/7, - GigabitEthernet0/8, Port-channel1] - hostname: n9k2 +- get_facts: + os_version: 7.0\(3\)I2\(2d\) + interface_list: + _mode: strict + list: [Vlan5,Vlan100, Vlan40, Vlan41, GigabitEthernet0/1, GigabitEthernet0/2, GigabitEthernet0/3, + GigabitEthernet0/4, GigabitEthernet0/5, GigabitEthernet0/6, GigabitEthernet0/7, + GigabitEthernet0/8, Port-channel1] + hostname: n9k2 -method_not_implemented: - something: asd +- method_not_implemented: + something: asd -get_bgp_neighbors: - _name: "check_bgp_neighbors_have_prefixes" - default: - router_id: 192.0.2.2 - peers: - _mode: strict - 192.0.2.3: - is_enabled: false - 192.0.2.2: - is_enabled: true - address_family: - ipv4: - sent_prefixes: 5 - ipv6: - sent_prefixes: 2 +- get_bgp_neighbors: + _name: "check_bgp_neighbors_have_prefixes" + default: + router_id: 192.0.2.2 + peers: + _mode: strict + 192.0.2.3: + is_enabled: false + 192.0.2.2: + is_enabled: true + address_family: + ipv4: + sent_prefixes: 5 + ipv6: + sent_prefixes: 2 -get_interfaces_ip: - Ethernet2/1: - ipv4: - 192.0.2.1: - prefix_length: 30 +- get_interfaces_ip: + Ethernet2/1: + ipv4: + 192.0.2.1: + prefix_length: 30 From 8879442b25249fbf61fac17140ac0ed6f02c22da Mon Sep 17 00:00:00 2001 From: David Barroso Date: Mon, 20 Feb 2017 12:24:40 -0800 Subject: [PATCH 2/7] Deprecate IBM driver (#211) * Deprecate IBM driver * Removing IBM from the tests --- test/unit/TestGetNetworkDriver.py | 2 +- test/unit/requirements.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/unit/TestGetNetworkDriver.py b/test/unit/TestGetNetworkDriver.py index 15c4f379..faf28e95 100644 --- a/test/unit/TestGetNetworkDriver.py +++ b/test/unit/TestGetNetworkDriver.py @@ -17,7 +17,7 @@ class TestGetNetworkDriver(unittest.TestCase): drivers_common = ('eos', 'ios', 'iosxr', 'IOS-XR', 'junos', 'ros', 'nxos', 'pluribus', 'panos', 'vyos') - drivers_py2_only = ('fortios', 'ibm') + drivers_py2_only = ('fortios', ) if PY2: # All drivers support python2 network_drivers = drivers_common + drivers_py2_only diff --git a/test/unit/requirements.txt b/test/unit/requirements.txt index 3f5800b8..d96eca92 100644 --- a/test/unit/requirements.txt +++ b/test/unit/requirements.txt @@ -1,7 +1,6 @@ ddt napalm-eos napalm-fortios -napalm-ibm napalm-ios napalm-iosxr napalm-junos From adc5b326817eb11e065ad0a714b1e596318df2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kostka?= Date: Thu, 23 Feb 2017 22:39:36 +0100 Subject: [PATCH 3/7] Update Vagrantfile for routeros with new box --- vagrant/Vagrantfile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile index caf9d122..01c354f0 100644 --- a/vagrant/Vagrantfile +++ b/vagrant/Vagrantfile @@ -70,12 +70,14 @@ Vagrant.configure(2) do |config| end config.vm.define "ros" do |ros| - ros.vm.box = "mikrotik-chr-6.36" - + ros.vm.box = "chr-6.37.4" ros.vm.network :forwarded_port, guest: 22, host: 12205, id: 'ssh' - - ros.vm.network "private_network", virtualbox__intnet: "link_1", ip: "169.254.1.11", auto_config: false - ros.vm.network "private_network", virtualbox__intnet: "link_2", ip: "169.254.1.11", auto_config: false + ros.vm.network :forwarded_port, guest: 8728, host: 8728, id: 'api' + ros.vm.network :forwarded_port, guest: 8729, host: 8729, id: 'apis' + ros.ssh.username = 'admin' + ros.ssh.password = '' + ros.ssh.insert_key = false + config.vm.synced_folder ".", "/vagrant", :disabled => true end config.vm.define "vyos" do |vyos| From 11af7539cdeba360bac41adccce3c46068e84682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kostka?= Date: Sat, 25 Feb 2017 22:37:36 +0100 Subject: [PATCH 4/7] Added download link. --- vagrant/Vagrantfile | 1 + 1 file changed, 1 insertion(+) diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile index 01c354f0..aa500692 100644 --- a/vagrant/Vagrantfile +++ b/vagrant/Vagrantfile @@ -70,6 +70,7 @@ Vagrant.configure(2) do |config| end config.vm.define "ros" do |ros| + # Download from https://drive.google.com/open?id=0B7lhzJhvsd-8dFB0NnNFUm52cjA ros.vm.box = "chr-6.37.4" ros.vm.network :forwarded_port, guest: 22, host: 12205, id: 'ssh' ros.vm.network :forwarded_port, guest: 8728, host: 8728, id: 'api' From 3363ae2806b50a773c1a5985826f25837cbc0cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Kostka?= Date: Mon, 27 Feb 2017 21:53:49 +0100 Subject: [PATCH 5/7] Obvious api name --- vagrant/Vagrantfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vagrant/Vagrantfile b/vagrant/Vagrantfile index aa500692..75cc662d 100644 --- a/vagrant/Vagrantfile +++ b/vagrant/Vagrantfile @@ -74,7 +74,7 @@ Vagrant.configure(2) do |config| ros.vm.box = "chr-6.37.4" ros.vm.network :forwarded_port, guest: 22, host: 12205, id: 'ssh' ros.vm.network :forwarded_port, guest: 8728, host: 8728, id: 'api' - ros.vm.network :forwarded_port, guest: 8729, host: 8729, id: 'apis' + ros.vm.network :forwarded_port, guest: 8729, host: 8729, id: 'apissl' ros.ssh.username = 'admin' ros.ssh.password = '' ros.ssh.insert_key = false From 842a801aba325b0bd85772cb9a5fd2e87ecfe6f2 Mon Sep 17 00:00:00 2001 From: Mircea Ulinic Date: Thu, 16 Mar 2017 13:43:19 +0000 Subject: [PATCH 6/7] Add __del__ to close on exit --- napalm_base/base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/napalm_base/base.py b/napalm_base/base.py index 01e1aa69..548fe5ac 100644 --- a/napalm_base/base.py +++ b/napalm_base/base.py @@ -59,6 +59,14 @@ def __exit__(self, exc_type, exc_value, exc_traceback): if exc_type is not None: self.__raise_clean_exception(exc_type, exc_value, exc_traceback) + def __del__(self): + """ + This method is used to cleanup when the program is terminated suddenly. + We need to make sure the connection is closed properly and the configuration DB + is released (unlocked). + """ + self.close() + @staticmethod def __raise_clean_exception(exc_type, exc_value, exc_traceback): """ From 2e41424a07b076cf38f2968c119fa75e8bc0df49 Mon Sep 17 00:00:00 2001 From: Mircea Ulinic Date: Thu, 16 Mar 2017 13:47:18 +0000 Subject: [PATCH 7/7] Version 0.23.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d1b8ff88..7ecdeff6 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ setup( name="napalm-base", - version='0.23.0', + version='0.23.1', packages=find_packages(), author="David Barroso", author_email="dbarrosop@dravetech.com",