[Python-modules-commits] [napalm-base] 01/05: Import napalm-base_0.21.0.orig.tar.gz

Vincent Bernat bernat at moszumanska.debian.org
Sun Dec 25 10:19:08 UTC 2016


This is an automated email from the git hooks/post-receive script.

bernat pushed a commit to branch master
in repository napalm-base.

commit 1aa738594c35043d7f88c6115cd12bf12611dedf
Author: Vincent Bernat <bernat at debian.org>
Date:   Sun Dec 25 11:16:19 2016 +0100

    Import napalm-base_0.21.0.orig.tar.gz
---
 PKG-INFO                                           |   2 +-
 napalm_base.egg-info/PKG-INFO                      |   2 +-
 napalm_base.egg-info/SOURCES.txt                   |   3 +
 napalm_base.egg-info/entry_points.txt              |   1 +
 napalm_base.egg-info/requires.txt                  |   1 +
 napalm_base/base.py                                | 128 +++++++++++++++++-
 napalm_base/clitools/cl_napalm_configure.py        |   2 +-
 napalm_base/clitools/cl_napalm_test.py             |   6 +-
 .../{cl_napalm_test.py => cl_napalm_validate.py}   |  28 ++--
 napalm_base/clitools/helpers.py                    |  11 +-
 napalm_base/constants.py                           |  64 +++++++++
 napalm_base/exceptions.py                          |   4 +
 napalm_base/helpers.py                             |   1 +
 napalm_base/test/base.py                           |  39 ++++++
 napalm_base/test/conftest.py                       |  27 ++--
 napalm_base/test/double.py                         |   2 +-
 napalm_base/test/getters.py                        | 143 ++++++++++++++++-----
 napalm_base/test/models.py                         |  36 ++++++
 napalm_base/utils/string_parsers.py                |   5 +-
 napalm_base/validate.py                            | 125 ++++++++++++++++++
 requirements.txt                                   |   1 +
 setup.cfg                                          |  11 +-
 setup.py                                           |   5 +-
 23 files changed, 572 insertions(+), 75 deletions(-)

diff --git a/PKG-INFO b/PKG-INFO
index 7e31242..e0cb296 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: napalm-base
-Version: 0.18.0
+Version: 0.21.0
 Summary: Network Automation and Programmability Abstraction Layer with Multivendor support
 Home-page: https://github.com/napalm-automation/napalm-base
 Author: David Barroso
diff --git a/napalm_base.egg-info/PKG-INFO b/napalm_base.egg-info/PKG-INFO
index 7e31242..e0cb296 100644
--- a/napalm_base.egg-info/PKG-INFO
+++ b/napalm_base.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: napalm-base
-Version: 0.18.0
+Version: 0.21.0
 Summary: Network Automation and Programmability Abstraction Layer with Multivendor support
 Home-page: https://github.com/napalm-automation/napalm-base
 Author: David Barroso
diff --git a/napalm_base.egg-info/SOURCES.txt b/napalm_base.egg-info/SOURCES.txt
index a727a17..590c02d 100644
--- a/napalm_base.egg-info/SOURCES.txt
+++ b/napalm_base.egg-info/SOURCES.txt
@@ -4,8 +4,10 @@ setup.cfg
 setup.py
 napalm_base/__init__.py
 napalm_base/base.py
+napalm_base/constants.py
 napalm_base/exceptions.py
 napalm_base/helpers.py
+napalm_base/validate.py
 napalm_base.egg-info/PKG-INFO
 napalm_base.egg-info/SOURCES.txt
 napalm_base.egg-info/dependency_links.txt
@@ -15,6 +17,7 @@ napalm_base.egg-info/top_level.txt
 napalm_base/clitools/__init__.py
 napalm_base/clitools/cl_napalm_configure.py
 napalm_base/clitools/cl_napalm_test.py
+napalm_base/clitools/cl_napalm_validate.py
 napalm_base/clitools/helpers.py
 napalm_base/test/__init__.py
 napalm_base/test/base.py
diff --git a/napalm_base.egg-info/entry_points.txt b/napalm_base.egg-info/entry_points.txt
index 30cf208..2a3eb91 100644
--- a/napalm_base.egg-info/entry_points.txt
+++ b/napalm_base.egg-info/entry_points.txt
@@ -1,4 +1,5 @@
 [console_scripts]
 cl_napalm_configure = napalm_base.clitools.cl_napalm_configure:main
 cl_napalm_test = napalm_base.clitools.cl_napalm_test:main
+cl_napalm_validate = napalm_base.clitools.cl_napalm_validate:main
 
diff --git a/napalm_base.egg-info/requires.txt b/napalm_base.egg-info/requires.txt
index d8a6f3e..5760f0d 100644
--- a/napalm_base.egg-info/requires.txt
+++ b/napalm_base.egg-info/requires.txt
@@ -1,3 +1,4 @@
 jtextfsm
 jinja2
 netaddr
+pyYAML
diff --git a/napalm_base/base.py b/napalm_base/base.py
index 7a94d4c..9a512ec 100644
--- a/napalm_base/base.py
+++ b/napalm_base/base.py
@@ -23,10 +23,14 @@ import sys
 import napalm_base.exceptions
 import napalm_base.helpers
 
+import napalm_base.constants as c
+
+from napalm_base import validate
+
 
 class NetworkDriver(object):
 
-    def __init__(self, hostname, username, password, timeout, optional_args):
+    def __init__(self, hostname, username, password, timeout=60, optional_args=None):
         """
         This is the base class you have to inherit from when writing your own Network Driver to
         manage any device. You will, in addition, have to override all the methods specified on
@@ -89,6 +93,16 @@ class NetworkDriver(object):
         """
         raise NotImplementedError
 
+    def is_alive(self):
+        """
+        Returns a flag with the connection state.
+        Depends on the nature of API used by each driver.
+        The state does not reflect only on the connection status (when SSH), it must also take into
+        consideration other parameters, e.g.: NETCONF session might not be usable, althought the
+        underlying SSH session is still open etc.
+        """
+        raise NotImplementedError
+
     def load_template(self, template_name, template_source=None,
                       template_path=None, **template_vars):
         """
@@ -543,7 +557,7 @@ class NetworkDriver(object):
         """
         raise NotImplementedError
 
-    def cli(self, *commands):
+    def cli(self, commands):
 
         """
         Will execute a list of commands and return the output in a dictionary format.
@@ -1096,7 +1110,8 @@ class NetworkDriver(object):
         """
         raise NotImplementedError
 
-    def ping(self, destination, source='', ttl=0, timeout=0, size=0, count=0):
+    def ping(self, destination, source=c.PING_SOURCE, ttl=c.PING_TTL, timeout=c.PING_TIMEOUT,
+             size=c.PING_SIZE, count=c.PING_COUNT):
         """
         Executes ping on the device and returns a dictionary with the result
 
@@ -1159,7 +1174,11 @@ class NetworkDriver(object):
         """
         raise NotImplementedError
 
-    def traceroute(self, destination, source='', ttl=0, timeout=0):
+    def traceroute(self,
+                   destination,
+                   source=c.TRACEROUTE_SOURCE,
+                   ttl=c.TRACEROUTE_TTL,
+                   timeout=c.TRACEROUTE_TIMEOUT):
         """
         Executes traceroute on the device and returns a dictionary with the result.
 
@@ -1379,3 +1398,104 @@ class NetworkDriver(object):
               empty string
         """
         raise NotImplementedError
+
+    def get_network_instances(self, name=''):
+        """
+        Return a dictionary of network instances (VRFs) configured, including default/global
+
+        Args:
+            name(string) - Name of the network instance to return, default is all.
+
+        Returns:
+            A dictionary of network instances in OC format:
+            * name (dict)
+              * name (unicode)
+              * type (unicode)
+              * state (dict)
+                * route_distinguisher (unicode)
+              * interfaces (dict)
+                * interface (dict)
+                  * interface name: (dict)
+
+        Example:
+        {
+            u'MGMT': {
+                u'name': u'MGMT',
+                u'type': u'L3VRF',
+                u'state': {
+                    u'route_distinguisher': u'123:456',
+                },
+                u'interfaces': {
+                    u'interface': {
+                        u'Management1': {}
+                    }
+                }
+            }
+            u'default': {
+                u'name': u'default',
+                u'type': u'DEFAULT_INSTANCE',
+                u'state': {
+                    u'route_distinguisher': None,
+                },
+                u'interfaces: {
+                    u'interface': {
+                        u'Ethernet1': {}
+                        u'Ethernet2': {}
+                        u'Ethernet3': {}
+                        u'Ethernet4': {}
+                    }
+                }
+            }
+        }
+        """
+        raise NotImplementedError
+
+    def get_firewall_policies(self):
+        """
+        Returns a dictionary of lists of dictionaries where the first key is an unique policy
+        name and the inner dictionary contains the following keys:
+
+        * position (int)
+        * packet_hits (int)
+        * byte_hits (int)
+        * id (text_type)
+        * enabled (bool)
+        * schedule (text_type)
+        * log (text_type)
+        * l3_src (text_type)
+        * l3_dst (text_type)
+        * service (text_type)
+        * src_zone (text_type)
+        * dst_zone (text_type)
+        * action (text_type)
+
+        Example::
+
+        {
+            'policy_name': [{
+                'position': 1,
+                'packet_hits': 200,
+                'byte_hits': 83883,
+                'id': '230',
+                'enabled': True,
+                'schedule': 'Always',
+                'log': 'all',
+                'l3_src': 'any',
+                'l3_dst': 'any',
+                'service': 'HTTP',
+                'src_zone': 'port2',
+                'dst_zone': 'port3',
+                'action': 'Permit'
+            }]
+        }
+        """
+        raise NotImplementedError
+
+    def compliance_report(self, validation_file='validate.yml'):
+        """
+        Return a compliance report.
+
+        Verify that the device complies with the given validation file and writes a compliance
+        report file. See https://napalm.readthedocs.io/en/latest/validate.html.
+        """
+        return validate.compliance_report(self, validation_file=validation_file)
diff --git a/napalm_base/clitools/cl_napalm_configure.py b/napalm_base/clitools/cl_napalm_configure.py
index 1251a33..fce6b32 100644
--- a/napalm_base/clitools/cl_napalm_configure.py
+++ b/napalm_base/clitools/cl_napalm_configure.py
@@ -52,7 +52,7 @@ def run(vendor, hostname, user, password, strategy, optional_args, config_file,
 
 
 def main():
-    args = build_help()
+    args = build_help(configure=True)
     configure_logging(logger, args.debug)
 
     print(run(args.vendor, args.hostname, args.user, args.password, args.strategy,
diff --git a/napalm_base/clitools/cl_napalm_test.py b/napalm_base/clitools/cl_napalm_test.py
index 86b14bd..5f934c1 100644
--- a/napalm_base/clitools/cl_napalm_test.py
+++ b/napalm_base/clitools/cl_napalm_test.py
@@ -18,7 +18,7 @@ from napalm_base.clitools.helpers import parse_optional_args
 # stdlib
 import sys
 import logging
-logger = logging.getLogger(__file__)
+logger = logging.getLogger('cl_napalm_test.py')
 
 
 def main():
@@ -30,13 +30,13 @@ def main():
 
     optional_args = parse_optional_args(args.optional_args)
     logger.debug('Connecting to device "{}" with user "{}" and optional_args={}'.format(
-                 device=args.hostname, user=args.user, optional_args=optional_args))
+                 args.hostname, args.user, optional_args))
 
     with driver(args.hostname,
                 args.user,
                 args.password,
                 optional_args=optional_args) as device:
-        logger.debug('Successfully connected to the device: {}'.format(device))
+        logger.debug('Successfully connected to the device: {}'.format(device.hostname))
         print('Successfully connected to the device')
     sys.exit(0)
 
diff --git a/napalm_base/clitools/cl_napalm_test.py b/napalm_base/clitools/cl_napalm_validate.py
old mode 100644
new mode 100755
similarity index 55%
copy from napalm_base/clitools/cl_napalm_test.py
copy to napalm_base/clitools/cl_napalm_validate.py
index 86b14bd..69b55a0
--- a/napalm_base/clitools/cl_napalm_test.py
+++ b/napalm_base/clitools/cl_napalm_validate.py
@@ -1,11 +1,12 @@
 # -*- coding: utf-8 -*-
 '''
-NAPALM CLI Tools: test connectivity
-===================================
+NAPALM CLI Tools: validate
+===========================
 
-Module to test connectivity with the network device through NAPALM.
+Validating deployments from the shell.
 '''
-from __future__ import absolute_import
+
+# Python3 support
 from __future__ import print_function
 from __future__ import unicode_literals
 
@@ -17,12 +18,13 @@ from napalm_base.clitools.helpers import parse_optional_args
 
 # stdlib
 import sys
+import json
 import logging
-logger = logging.getLogger(__file__)
+logger = logging.getLogger('cl_napalm_validate.py')
 
 
 def main():
-    args = build_help(connect_test=True)
+    args = build_help(validate=True)
     configure_logging(logger, args.debug)
 
     logger.debug('Getting driver for OS "{driver}"'.format(driver=args.vendor))
@@ -30,14 +32,12 @@ def main():
 
     optional_args = parse_optional_args(args.optional_args)
     logger.debug('Connecting to device "{}" with user "{}" and optional_args={}'.format(
-                 device=args.hostname, user=args.user, optional_args=optional_args))
-
-    with driver(args.hostname,
-                args.user,
-                args.password,
-                optional_args=optional_args) as device:
-        logger.debug('Successfully connected to the device: {}'.format(device))
-        print('Successfully connected to the device')
+                 args.hostname, args.user, optional_args))
+
+    with driver(args.hostname, args.user, args.password, optional_args=optional_args) as device:
+        logger.debug('Generating compliance report')
+        print(json.dumps(device.compliance_report(args.validation_file), indent=4))
+        logger.debug('Closing session')
     sys.exit(0)
 
 
diff --git a/napalm_base/clitools/helpers.py b/napalm_base/clitools/helpers.py
index 92db9e6..329884b 100644
--- a/napalm_base/clitools/helpers.py
+++ b/napalm_base/clitools/helpers.py
@@ -16,7 +16,7 @@ import getpass
 import argparse
 
 
-def build_help(connect_test=False):
+def build_help(connect_test=False, validate=False, configure=False):
     parser = argparse.ArgumentParser(
         description='Command line tool to handle configuration on devices using NAPALM.'
                     'The script will print the diff on the screen',
@@ -60,7 +60,7 @@ def build_help(connect_test=False):
         action='store_true',
         help='Enables debug mode; more verbosity.'
     )
-    if not connect_test:
+    if configure:
         parser.add_argument(
             '--strategy', '-s',
             dest='strategy',
@@ -81,6 +81,13 @@ def build_help(connect_test=False):
             default=None,
             help='Only returns diff, it does not deploy the configuration.',
         )
+    elif validate:
+        parser.add_argument(
+            '--validation_file', '-f',
+            dest='validation_file',
+            action='store',
+            help='Validation file containing resources derised states'
+        )
     args = parser.parse_args()
 
     if args.password is None:
diff --git a/napalm_base/constants.py b/napalm_base/constants.py
new file mode 100644
index 0000000..c7b7823
--- /dev/null
+++ b/napalm_base/constants.py
@@ -0,0 +1,64 @@
+"""Constants to be used across NAPALM drivers."""
+
+from __future__ import unicode_literals
+
+CONFIG_LOCK = True  # must be changed soon!
+TIMEOUT = 60  # seconds
+
+INTERFACE_NULL_SPEED = -1
+
+BGP_NEIGHBOR_NULL_COUNTER = -1
+
+SNMP_AUTHORIZATION_MODE_MAP = {
+  'read-only': 'ro',
+  'read-write': 'rw'
+}
+
+ROUTE_COMMON_PROTOCOL_FIELDS = [
+    'destination',
+    'prefix_length',
+    'protocol',
+    'current_active',
+    'last_active',
+    'age',
+    'next_hop',
+    'outgoing_interface',
+    'selected_next_hop',
+    'preference',
+    'inactive_reason',
+    'routing_table'
+]  # identifies the list of fileds common for all protocols
+ROUTE_PROTOCOL_SPECIFIC_FIELDS = {
+    'bgp': [
+        'local_as',
+        'remote_as',
+        'as_path',
+        'communities',
+        'local_preference',
+        'preference2',
+        'remote_address',
+        'metric',
+        'metric2'
+    ],
+    'isis': [
+        'level',
+        'metric',
+        'local_as'
+    ],
+    'static': [  # nothing specific to static routes
+    ]
+}
+
+TRACEROUTE_TTL = 255
+TRACEROUTE_SOURCE = ''
+TRACEROUTE_TIMEOUT = 2
+TRACEROUTE_NULL_HOST_NAME = '*'
+TRACEROUTE_NULL_IP_ADDRESS = '*'
+
+OPTICS_NULL_LEVEL = '-Inf'
+
+PING_SOURCE = ''
+PING_TTL = 255
+PING_TIMEOUT = 2
+PING_SIZE = 100
+PING_COUNT = 5
diff --git a/napalm_base/exceptions.py b/napalm_base/exceptions.py
index e5b4942..86dbbd6 100644
--- a/napalm_base/exceptions.py
+++ b/napalm_base/exceptions.py
@@ -55,3 +55,7 @@ class TemplateNotImplemented(Exception):
 
 class TemplateRenderException(Exception):
     pass
+
+
+class ValidationException(Exception):
+    pass
diff --git a/napalm_base/helpers.py b/napalm_base/helpers.py
index 0dc3bfe..ed7d63f 100644
--- a/napalm_base/helpers.py
+++ b/napalm_base/helpers.py
@@ -27,6 +27,7 @@ from napalm_base.utils import py23_compat
 class _MACFormat(mac_unix):
     pass
 
+
 _MACFormat.word_fmt = '%.2X'
 
 
diff --git a/napalm_base/test/base.py b/napalm_base/test/base.py
index bca1f91..1760198 100644
--- a/napalm_base/test/base.py
+++ b/napalm_base/test/base.py
@@ -166,6 +166,28 @@ class TestGettersNetworkDriver(object):
 
         return correct_class and same_keys
 
+    def test_get_firewall_policies(self):
+        try:
+            policies = self.device.get_firewall_policies()
+        except NotImplementedError:
+            raise SkipTest()
+
+        result = len(policies) > 0
+
+        for policy_name, policy_details in policies.items():
+            for policy_term in policy_details:
+                result = result and self._test_model(models.firewall_policies, policy_term)
+
+        self.assertTrue(result)
+
+    def test_is_alive(self):
+        try:
+            alive = self.device.is_alive()
+        except NotImplementedError:
+            raise SkipTest()
+        result = self._test_model(models.alive, alive)
+        self.assertTrue(result)
+
     def test_get_facts(self):
         try:
             facts = self.device.get_facts()
@@ -530,3 +552,20 @@ class TestGettersNetworkDriver(object):
             assert get_config['candidate'] == "" if config != "candidate" else True
             assert get_config['startup'] == "" if config != "startup" else True
             assert get_config['running'] == "" if config != "running" else True
+
+    def test_get_network_instances(self):
+        """Test get_network_instances method."""
+        try:
+            get_network_instances = self.device.get_network_instances()
+        except NotImplementedError:
+            raise SkipTest()
+
+        result = isinstance(get_network_instances, dict)
+        for network_instance_name, network_instance in get_network_instances.items():
+            result = result and self._test_model(models.network_instance, network_instance)
+            result = result and \
+                self._test_model(models.network_instance_state, network_instance['state'])
+            result = result and \
+                self._test_model(models.network_instance_interfaces, network_instance['interfaces'])
+
+        self.assertTrue(result)
diff --git a/napalm_base/test/conftest.py b/napalm_base/test/conftest.py
index da117c7..c3f6d48 100644
--- a/napalm_base/test/conftest.py
+++ b/napalm_base/test/conftest.py
@@ -7,7 +7,7 @@ from __future__ import unicode_literals
 import json
 import os
 
-NAPALM_TEST_MOCK = os.getenv('NAPALM_TEST_MOCK', default=True)
+NAPALM_TEST_MOCK = eval("{}".format(os.getenv('NAPALM_TEST_MOCK', default=True)))
 NAPALM_HOSTNAME = os.getenv('NAPALM_HOSTNAME', default='127.0.0.1')
 NAPALM_USERNAME = os.getenv('NAPALM_USERNAME', default='vagrant')
 NAPALM_PASSWORD = os.getenv('NAPALM_PASSWORD', default='vagrant')
@@ -31,19 +31,20 @@ def set_device_parameters(request):
 
 def pytest_generate_tests(metafunc, basefile):
     """Generate test cases dynamically."""
-    path = os.path.join(os.path.dirname(basefile), 'mocked_data', metafunc.function.__name__)
+    if metafunc.function.__dict__.get('build_test_cases', False):
+        path = os.path.join(os.path.dirname(basefile), 'mocked_data', metafunc.function.__name__)
 
-    if os.path.exists(path):
-        sub_folders = os.listdir(path)
-    else:
-        sub_folders = []
+        if os.path.exists(path):
+            sub_folders = os.listdir(path)
+        else:
+            sub_folders = []
 
-    test_cases = []
-    for test_case in sub_folders:
-        if os.path.isdir(os.path.join(path, test_case)):
-            test_cases.append(test_case)
+        test_cases = []
+        for test_case in sub_folders:
+            if os.path.isdir(os.path.join(path, test_case)):
+                test_cases.append(test_case)
 
-    if not test_cases:
-        test_cases.append("no_test_case_found")
+        if not test_cases:
+            test_cases.append("no_test_case_found")
 
-    metafunc.parametrize("test_case", test_cases)
+        metafunc.parametrize("test_case", test_cases)
diff --git a/napalm_base/test/double.py b/napalm_base/test/double.py
index 7e7ef1a..4872ea2 100644
--- a/napalm_base/test/double.py
+++ b/napalm_base/test/double.py
@@ -34,7 +34,7 @@ class BaseTestDouble(object):
     @staticmethod
     def sanitize_text(text):
         """Remove some weird characters from text, useful for building filenames from commands."""
-        regexp = r'[\[\]\*\^\+\s\|\/\$\%\!\"]'
+        regexp = '[^a-zA-Z0-9]'
         return re.sub(regexp, '_', text)[0:150]
 
     @staticmethod
diff --git a/napalm_base/test/getters.py b/napalm_base/test/getters.py
index 256fcf5..364f973 100644
--- a/napalm_base/test/getters.py
+++ b/napalm_base/test/getters.py
@@ -3,14 +3,21 @@ from __future__ import print_function
 from __future__ import unicode_literals
 
 import functools
-import itertools
+
+# python2/3 support
+try:
+    from itertools import izip_longest as zip_longest
+except ImportError:
+    from itertools import zip_longest
+
+import inspect
 import json
 import os
 
-
-import helpers
-import models
 import pytest
+from napalm_base.test import helpers
+from napalm_base.test import models
+from napalm_base import NetworkDriver
 
 # text_type is 'unicode' for py2 and 'str' for py3
 from napalm_base.utils.py23_compat import text_type
@@ -22,7 +29,7 @@ NAPALM_TEST_MOCK = os.getenv('NAPALM_TEST_MOCK', default=True)
 def list_dicts_diff(prv, nxt):
     """Compare two lists of dicts."""
     result = []
-    for prv_element, nxt_element in itertools.izip_longest(prv, nxt, fillvalue={}):
+    for prv_element, nxt_element in zip_longest(prv, nxt, fillvalue={}):
         intermediate_result = dict_diff(prv_element, nxt_element)
         if intermediate_result:
             result.append(intermediate_result)
@@ -31,7 +38,7 @@ def list_dicts_diff(prv, nxt):
 
 def dict_diff(prv, nxt):
     """Return a dict of keys that differ with another config object."""
-    keys = set(prv.keys() + nxt.keys())
+    keys = set(list(prv.keys()) + list(nxt.keys()))
     result = {}
 
     for k in keys:
@@ -53,6 +60,8 @@ def dict_diff(prv, nxt):
 
 def wrap_test_cases(func):
     """Wrap test cases."""
+    func.__dict__['build_test_cases'] = True
+
     @functools.wraps(func)
     def wrapper(cls, test_case):
         for patched_attr in cls.device.patched_attrs:
@@ -63,7 +72,7 @@ def wrap_test_cases(func):
         try:
             # This is an ugly, ugly, ugly hack because some python objects don't load
             # as expected. For example, dicts where integers are strings
-            result = json.loads(json.dumps(func(cls)))
+            result = json.loads(json.dumps(func(cls, test_case)))
         except IOError:
             if test_case == "no_test_case_found":
                 pytest.fail("No test case for '{}' found".format(func.__name__))
@@ -103,15 +112,51 @@ def wrap_test_cases(func):
 class BaseTestGetters(object):
     """Base class for testing drivers."""
 
+    def test_method_signatures(self):
+        """Test that all methods have the same signature."""
+        errors = {}
+        cls = self.driver
+        # Create fictional driver instance (py3 needs bound methods)
+        tmp_obj = cls(hostname='test', username='admin', password='pwd')
+        attrs = [m for m, v in inspect.getmembers(tmp_obj)]
+        for attr in attrs:
+            func = getattr(tmp_obj, attr)
+            if attr.startswith('_') or not inspect.ismethod(func):
+                continue
+            try:
+                orig = getattr(NetworkDriver, attr)
+                orig_spec = inspect.getargspec(orig)
+            except AttributeError:
+                orig_spec = 'Method does not exist in napalm_base'
+            func_spec = inspect.getargspec(func)
+            if orig_spec != func_spec:
+                errors[attr] = (orig_spec, func_spec)
+
+        EXTRA_METHODS = ['__init__', ]
+        for method in EXTRA_METHODS:
+            orig_spec = inspect.getargspec(getattr(NetworkDriver, method))
+            func_spec = inspect.getargspec(getattr(cls, method))
+            if orig_spec != func_spec:
+                errors[attr] = (orig_spec, func_spec)
+
+        assert not errors, "Some methods vary. \n{}".format(errors.keys())
+
+    @wrap_test_cases
+    def test_is_alive(self, test_case):
+        """Test is_alive method."""
+        alive = self.device.is_alive()
+        assert helpers.test_model(models.alive, alive)
+        return alive
+
     @wrap_test_cases
-    def test_get_facts(self):
+    def test_get_facts(self, test_case):
         """Test get_facts method."""
         facts = self.device.get_facts()
         assert helpers.test_model(models.facts, facts)
         return facts
 
     @wrap_test_cases
-    def test_get_interfaces(self):
+    def test_get_interfaces(self, test_case):
         """Test get_interfaces."""
         get_interfaces = self.device.get_interfaces()
         assert len(get_interfaces) > 0
@@ -122,7 +167,7 @@ class BaseTestGetters(object):
         return get_interfaces
 
     @wrap_test_cases
-    def test_get_lldp_neighbors(self):
+    def test_get_lldp_neighbors(self, test_case):
         """Test get_lldp_neighbors."""
         get_lldp_neighbors = self.device.get_lldp_neighbors()
         assert len(get_lldp_neighbors) > 0
@@ -134,7 +179,7 @@ class BaseTestGetters(object):
         return get_lldp_neighbors
 
     @wrap_test_cases
-    def test_get_interfaces_counters(self):
+    def test_get_interfaces_counters(self, test_case):
         """Test get_interfaces_counters."""
         get_interfaces_counters = self.device.get_interfaces_counters()
         assert len(self.device.get_interfaces_counters()) > 0
@@ -145,7 +190,7 @@ class BaseTestGetters(object):
         return get_interfaces_counters
 
     @wrap_test_cases
-    def test_get_environment(self):
+    def test_get_environment(self, test_case):
         """Test get_environment."""
         environment = self.device.get_environment()
         assert len(environment) > 0
@@ -167,7 +212,7 @@ class BaseTestGetters(object):
         return environment
 
     @wrap_test_cases
-    def test_get_bgp_neighbors(self):
+    def test_get_bgp_neighbors(self, test_case):
         """Test get_bgp_neighbors."""
         get_bgp_neighbors = self.device.get_bgp_neighbors()
         assert 'global' in get_bgp_neighbors.keys()
@@ -184,7 +229,7 @@ class BaseTestGetters(object):
         return get_bgp_neighbors
 
     @wrap_test_cases
-    def test_get_lldp_neighbors_detail(self):
+    def test_get_lldp_neighbors_detail(self, test_case):
         """Test get_lldp_neighbors_detail."""
         get_lldp_neighbors_detail = self.device.get_lldp_neighbors_detail()
         assert len(get_lldp_neighbors_detail) > 0
@@ -196,7 +241,7 @@ class BaseTestGetters(object):
         return get_lldp_neighbors_detail
 
     @wrap_test_cases
-    def test_get_bgp_config(self):
+    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
@@ -209,7 +254,7 @@ class BaseTestGetters(object):
         return get_bgp_config
 
     @wrap_test_cases
-    def test_get_bgp_neighbors_detail(self):
+    def test_get_bgp_neighbors_detail(self, test_case):
         """Test get_bgp_neighbors_detail."""
         get_bgp_neighbors_detail = self.device.get_bgp_neighbors_detail()
 
@@ -225,7 +270,7 @@ class BaseTestGetters(object):
         return get_bgp_neighbors_detail
 
     @wrap_test_cases
-    def test_get_arp_table(self):
+    def test_get_arp_table(self, test_case):
         """Test get_arp_table."""
         get_arp_table = self.device.get_arp_table()
         assert len(get_arp_table) > 0
@@ -236,7 +281,7 @@ class BaseTestGetters(object):
         return get_arp_table
 
     @wrap_test_cases
-    def test_get_ntp_peers(self):
+    def test_get_ntp_peers(self, test_case):
         """Test get_ntp_peers."""
         get_ntp_peers = self.device.get_ntp_peers()
         assert len(get_ntp_peers) > 0
@@ -248,7 +293,19 @@ class BaseTestGetters(object):
         return get_ntp_peers
 
     @wrap_test_cases
-    def test_get_ntp_stats(self):
+    def test_get_ntp_servers(self, test_case):
+        """Test get_ntp_servers."""
+        get_ntp_servers = self.device.get_ntp_servers()
+        assert len(get_ntp_servers) > 0
+
+        for server, server_details in get_ntp_servers.items():
+            assert isinstance(server, text_type)
+            assert helpers.test_model(models.ntp_server, server_details)
+
+        return get_ntp_servers
+
+    @wrap_test_cases
+    def test_get_ntp_stats(self, test_case):
         """Test get_ntp_stats."""
         get_ntp_stats = self.device.get_ntp_stats()
         assert len(get_ntp_stats) > 0
@@ -259,7 +316,7 @@ class BaseTestGetters(object):
         return get_ntp_stats
 
     @wrap_test_cases
-    def test_get_interfaces_ip(self):
+    def test_get_interfaces_ip(self, test_case):
         """Test get_interfaces_ip."""
         get_interfaces_ip = self.device.get_interfaces_ip()
         assert len(get_interfaces_ip) > 0
@@ -275,7 +332,7 @@ class BaseTestGetters(object):
         return get_interfaces_ip
 
     @wrap_test_cases
-    def test_get_mac_address_table(self):
+    def test_get_mac_address_table(self, test_case):
         """Test get_mac_address_table."""
         get_mac_address_table = self.device.get_mac_address_table()
         assert len(get_mac_address_table) > 0
@@ -286,7 +343,7 @@ class BaseTestGetters(object):
         return get_mac_address_table
 
     @wrap_test_cases
-    def test_get_route_to(self):
+    def test_get_route_to(self, test_case):
         """Test get_route_to."""
         destination = '1.0.4.0/24'
         protocol = 'bgp'
@@ -301,7 +358,7 @@ class BaseTestGetters(object):
         return get_route_to
 
     @wrap_test_cases
-    def test_get_snmp_information(self):
+    def test_get_snmp_information(self, test_case):
         """Test get_snmp_information."""
         get_snmp_information = self.device.get_snmp_information()
 
@@ -316,7 +373,7 @@ class BaseTestGetters(object):
         return get_snmp_information
 
     @wrap_test_cases
-    def test_get_probes_config(self):
+    def test_get_probes_config(self, test_case):
         """Test get_probes_config."""
         get_probes_config = self.device.get_probes_config()
 
@@ -329,7 +386,7 @@ class BaseTestGetters(object):
         return get_probes_config
 
     @wrap_test_cases
-    def test_get_probes_results(self):
+    def test_get_probes_results(self, test_case):
         """Test get_probes_results."""
         get_probes_results = self.device.get_probes_results()
         assert len(get_probes_results) > 0
@@ -341,7 +398,7 @@ class BaseTestGetters(object):
         return get_probes_results
 
     @wrap_test_cases
-    def test_ping(self):
+    def test_ping(self, test_case):
         """Test ping."""
         destination = '8.8.8.8'
         get_ping = self.device.ping(destination)
@@ -356,7 +413,7 @@ class BaseTestGetters(object):
         return get_ping
 
     @wrap_test_cases
-    def test_traceroute(self):
+    def test_traceroute(self, test_case):
         """Test traceroute."""
         destination = '8.8.8.8'
         get_traceroute = self.device.traceroute(destination)
@@ -370,7 +427,7 @@ class BaseTestGetters(object):
         return get_traceroute
 
     @wrap_test_cases
-    def test_get_users(self):
+    def test_get_users(self, test_case):
         """Test get_users."""
         get_users = self.device.get_users()
         assert len(get_users)
@@ -382,7 +439,7 @@ class BaseTestGetters(object):
         return get_users
 
     @wrap_test_cases
-    def test_get_optics(self):
+    def test_get_optics(self, test_case):
         """Test get_optics."""
         get_optics = self.device.get_optics()
         assert isinstance(get_optics, dict)
@@ -405,7 +462,7 @@ class BaseTestGetters(object):
         return get_optics
 
     @wrap_test_cases
-    def test_get_config(self):
+    def test_get_config(self, test_case):
         """Test get_config method."""
         get_config = self.device.get_config()
 
@@ -415,7 +472,7 @@ class BaseTestGetters(object):
         return get_config
 
     @wrap_test_cases
-    def test_get_config_filtered(self):
+    def test_get_config_filtered(self, test_case):
         """Test get_config method."""
         for config in ['running', 'startup', 'candidate']:
             get_config = self.device.get_config(retrieve=config)
@@ -425,3 +482,27 @@ class BaseTestGetters(object):
             assert get_config['running'] == "" if config != "running" else True
 
         return get_config
+
+    @wrap_test_cases
+    def test_get_network_instances(self, test_case):
+        """Test get_network_instances method."""
+        get_network_instances = self.device.get_network_instances()
+
+        assert isinstance(get_network_instances, dict)
+        for network_instance_name, network_instance in get_network_instances.items():
+            assert helpers.test_model(models.network_instance, network_instance)
+            assert helpers.test_model(models.network_instance_state, network_instance['state'])
+            assert helpers.test_model(models.network_instance_interfaces,
+                                      network_instance['interfaces'])
+
+        return get_network_instances
+
+    @wrap_test_cases
+    def test_get_firewall_policies(self, test_case):
+        """Test get_firewall_policies method."""
+        get_firewall_policies = self.device.get_firewall_policies()
+        assert len(get_firewall_policies) > 0
+        for policy_name, policy_details in get_firewall_policies.items():
+            for policy_term in policy_details:
+                assert helpers.test_model(models.firewall_policies, policy_term)
+        return get_firewall_policies
diff --git a/napalm_base/test/models.py b/napalm_base/test/models.py
index e980528..37bd84f 100644
--- a/napalm_base/test/models.py
+++ b/napalm_base/test/models.py
@@ -2,6 +2,10 @@
 # text_type is 'unicode' for py2 and 'str' for py3
 from napalm_base.utils.py23_compat import text_type
 
+alive = {
+    'is_alive': bool
+}
+
 facts = {
     'os_version': text_type,
     'uptime': int,
@@ -12,6 +16,7 @@ facts = {
     'hostname': text_type,
     'fqdn': text_type
 }
+
 interface = {
     'is_up': bool,
     'is_enabled': bool,
... 237 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/napalm-base.git



More information about the Python-modules-commits mailing list