Skip to content
This repository has been archived by the owner on Sep 17, 2019. It is now read-only.

Release 0.26.0 #317

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b5d57aa
Validate using python object
mirceaulinic Jun 2, 2017
a961002
Validate string before evaluating (#274)
dbarrosop Jul 12, 2017
83d51ae
Bump version to 0.24.3 (#275)
dbarrosop Jul 12, 2017
4865720
Fix napalm validate so identical strings will work (#288)
ktbyers Aug 2, 2017
ef47e15
Correct link under "compliance_report" function (#289)
bdlamprecht Aug 2, 2017
42729d5
Convert napalm_base testing to tox (#284)
bewing Aug 8, 2017
fbe3347
Search parent modules in load_template
bewing Aug 4, 2017
896ebd4
load_template unit test fixes
bewing Aug 4, 2017
604bbda
Test search path building
bewing Aug 7, 2017
ee1b76d
If tox was merged I would've caught this
bewing Aug 7, 2017
37e58f4
PEP8
bewing Aug 7, 2017
2e1148a
Didn't use this subclass
bewing Aug 7, 2017
7868afc
pylama
bewing Aug 8, 2017
8959976
Rename template directory
bewing Aug 8, 2017
6d4e46a
Add requested value to the validate report (#291)
dbarrosop Aug 9, 2017
13ecc39
Clean up search_path creation
bewing Aug 9, 2017
cb9ecd4
__enter__ was swallowing the exception and returning False (#299)
dbarrosop Aug 10, 2017
a249e1b
Merge pull request #294 from bewing/lt_walk
bewing Aug 22, 2017
ae1bab0
Remove constraint on _rpc method for MockDriver that requires junos p…
nickethier Aug 22, 2017
0bc3eef
Implemented generic napalm tool with debugging capabilities (#292)
dbarrosop Aug 22, 2017
24cb28a
py3 requires you to cast keys and values into a list (#300)
dbarrosop Aug 25, 2017
cac3372
Version 0.25.0 (#302)
mirceaulinic Aug 25, 2017
e21f10f
Merge branch 'master' into develop
dbarrosop Aug 25, 2017
231a407
Add tests for validation from source (#308)
ubaumann Sep 14, 2017
bcebcd1
add get_ipv6_neighbors_table()
pierky Sep 20, 2017
4b94704
Fixing issue with long checking
ktbyers Sep 24, 2017
c8b5401
Merge branch 'enh-validate' into develop
ubaumann Sep 26, 2017
25cdd55
Merge pull request #1 from ubaumann/develop
ubaumann Sep 26, 2017
9102ca1
Merge pull request #313 from ubaumann/enh-validate
mirceaulinic Sep 27, 2017
62968a7
Merge remote-tracking branch 'upstream/develop' into get_ipv6_neighbo…
pierky Sep 27, 2017
7aefac2
Merge pull request #312 from ktbyers/develop2
ktbyers Sep 27, 2017
b47f89b
age is in seconds
pierky Sep 30, 2017
a5972f4
Merge pull request #311 from pierky/get_ipv6_neighbors_table
ktbyers Sep 30, 2017
f3f325a
Remove download counter which no longer works
ogenstad Oct 7, 2017
e495f45
Merge pull request #314 from ogenstad/remove_badge
mirceaulinic Oct 7, 2017
2ecc11a
Add github templates
ktbyers Oct 23, 2017
9ae7c8f
Force Travis to re-test
ktbyers Oct 23, 2017
ae75271
Merge pull request #318 from napalm-automation/fix-github-templates
ktbyers Oct 23, 2017
664433f
Final release: 1.0.0
mirceaulinic Nov 7, 2017
f94c48d
Import get_network_driver from the new code base
mirceaulinic Nov 8, 2017
a8ed608
napalm major version as int
mirceaulinic Nov 8, 2017
1e1d530
Import NetworkDriver from napalm.base when napalm>=2.0.0 is installed
mirceaulinic Nov 15, 2017
f8a154e
Merge pull request #319 from napalm-automation/migrate-napalm-base
mirceaulinic Nov 16, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/ISSUE_TEMPLATE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### The NAPALM Project has reunified!

Please submit all NAPALM issues to:
https://github.com/napalm-automation/napalm/issues


### DO NOT submit any issues to this repository.
7 changes: 7 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### The NAPALM Project has reunified!

Please submit all NAPALM pull requests to:
https://github.com/napalm-automation/napalm/pulls


### DO NOT submit any pull requests to this repository.
17 changes: 7 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ python:
- 2.7
- 3.4
- 3.5
- 3.6

install:
- pip install .
- pip install -r requirements-dev.txt
- pip install -r requirements.txt
- pip install -r test/unit/requirements.txt

- pip install tox-travis
- pip install coveralls
deploy:
provider: pypi
user: dbarroso
Expand All @@ -21,8 +19,7 @@ deploy:
branch: master

script:
- nosetests ./test/unit/TestGetNetworkDriver.py
- nosetests ./test/unit/TestHelpers.py
- nosetests ./test/unit/TestNapalmTestFramework.py
- py.test test/unit/validate
- pylama .
- tox
after_success:
- coveralls
- if [ $TRAVIS_TAG ]; then curl -X POST https://readthedocs.org/build/napalm; fi
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
[![PyPI](https://img.shields.io/pypi/v/napalm-base.svg)](https://pypi.python.org/pypi/napalm-base)
[![PyPI](https://img.shields.io/pypi/dm/napalm-base.svg)](https://pypi.python.org/pypi/napalm-base)
[![Build Status](https://travis-ci.org/napalm-automation/napalm-base.svg?branch=master)](https://travis-ci.org/napalm-automation/napalm-base)


Expand Down
161 changes: 91 additions & 70 deletions napalm_base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

# Python std lib
import sys
import inspect
import importlib
import pkg_resources

# Verify Python Version that is running
Expand All @@ -32,83 +30,106 @@
except AttributeError:
raise RuntimeError('NAPALM requires Python 2.7 or Python3')

# NAPALM base
from napalm_base.base import NetworkDriver
from napalm_base.exceptions import ModuleImportError
from napalm_base.mock import MockDriver
from napalm_base.utils import py23_compat
# Try to import napalm
try:
import napalm
HAS_NAPALM = True
try:
NAPALM_MAJOR = int(napalm.__version__.split('.')[0])
except AttributeError:
NAPALM_MAJOR = 0
except ImportError:
HAS_NAPALM = False

try:
__version__ = pkg_resources.get_distribution('napalm-base').version
except pkg_resources.DistributionNotFound:
__version__ = "Not installed"


__all__ = [
'get_network_driver', # export the function
'NetworkDriver' # also export the base class
]

if HAS_NAPALM and NAPALM_MAJOR >= 2:
# If napalm >= 2.0.0 is installed, then import get_network_driver
from napalm import get_network_driver
from napalm.base import NetworkDriver
else:
# Import std lib
import inspect
import importlib

# Import local modules
from napalm_base.exceptions import ModuleImportError
from napalm_base.mock import MockDriver
from napalm_base.utils import py23_compat
from napalm_base.base import NetworkDriver

def get_network_driver(module_name, prepend=True):
"""
Searches for a class derived form the base NAPALM class NetworkDriver in a specific library.
The library name must repect the following pattern: napalm_[DEVICE_OS].
NAPALM community supports a list of devices and provides the corresponding libraries; for
full reference please refer to the `Supported Network Operation Systems`_ paragraph on
`Read the Docs`_.

.. _`Supported Network Operation Systems`: \
http://napalm.readthedocs.io/en/latest/#supported-network-operating-systems
.. _`Read the Docs`: \
http://napalm.readthedocs.io/

module_name
The name of the device operating system or the name of the library.

:return: The first class derived from NetworkDriver, found in the library.

:raise ModuleImportError: When the library is not installed or a derived class from \
NetworkDriver was not found.

Example:

.. code-block:: python

>>> get_network_driver('junos')
<class 'napalm_junos.junos.JunOSDriver'>
>>> get_network_driver('IOS-XR')
<class 'napalm_iosxr.iosxr.IOSXRDriver'>
>>> get_network_driver('napalm_eos')
<class 'napalm_eos.eos.EOSDriver'>
>>> get_network_driver('wrong')
napalm_base.exceptions.ModuleImportError: Cannot import "napalm_wrong". Is the library \
installed?
"""
if module_name == "mock":
return MockDriver

if not (isinstance(module_name, py23_compat.string_types) and len(module_name) > 0):
raise ModuleImportError('Please provide a valid driver name.')

try:
# Only lowercase allowed
module_name = module_name.lower()
# Try to not raise error when users requests IOS-XR for e.g.
module_install_name = module_name.replace('-', '')
# Can also request using napalm_[SOMETHING]
if 'napalm_' not in module_install_name and prepend is True:
module_install_name = 'napalm_{name}'.format(name=module_install_name)
module = importlib.import_module(module_install_name)
except ImportError:
raise ModuleImportError(
'Cannot import "{install_name}". Is the library installed?'.format(
install_name=module_install_name
)
)

def get_network_driver(module_name, prepend=True):
"""
Searches for a class derived form the base NAPALM class NetworkDriver in a specific library.
The library name must repect the following pattern: napalm_[DEVICE_OS].
NAPALM community supports a list of devices and provides the corresponding libraries; for
full reference please refer to the `Supported Network Operation Systems`_ paragraph on
`Read the Docs`_.

.. _`Supported Network Operation Systems`: \
http://napalm.readthedocs.io/en/latest/#supported-network-operating-systems
.. _`Read the Docs`: \
http://napalm.readthedocs.io/

:param module_name: the name of the device operating system or the name of the library.
:return: the first class derived from NetworkDriver, found in the library.
:raise ModuleImportError: when the library is not installed or a derived class from \
NetworkDriver was not found.

Example::

.. code-block:: python

>>> get_network_driver('junos')
<class 'napalm_junos.junos.JunOSDriver'>
>>> get_network_driver('IOS-XR')
<class 'napalm_iosxr.iosxr.IOSXRDriver'>
>>> get_network_driver('napalm_eos')
<class 'napalm_eos.eos.EOSDriver'>
>>> get_network_driver('wrong')
napalm_base.exceptions.ModuleImportError: Cannot import "napalm_wrong". Is the library \
installed?
"""
if module_name == "mock":
return MockDriver

if not (isinstance(module_name, py23_compat.string_types) and len(module_name) > 0):
raise ModuleImportError('Please provide a valid driver name.')
for name, obj in inspect.getmembers(module):
if inspect.isclass(obj) and issubclass(obj, NetworkDriver):
return obj

try:
# Only lowercase allowed
module_name = module_name.lower()
# Try to not raise error when users requests IOS-XR for e.g.
module_install_name = module_name.replace('-', '')
# Can also request using napalm_[SOMETHING]
if 'napalm_' not in module_install_name and prepend is True:
module_install_name = 'napalm_{name}'.format(name=module_install_name)
module = importlib.import_module(module_install_name)
except ImportError:
# looks like you don't have any Driver class in your module...
raise ModuleImportError(
'Cannot import "{install_name}". Is the library installed?'.format(
install_name=module_install_name
)
)
'No class inheriting "napalm_base.base.NetworkDriver" found in "{install_name}".'
.format(install_name=module_install_name))

for name, obj in inspect.getmembers(module):
if inspect.isclass(obj) and issubclass(obj, NetworkDriver):
return obj

# looks like you don't have any Driver class in your module...
raise ModuleImportError(
'No class inheriting "napalm_base.base.NetworkDriver" found in "{install_name}".'
.format(install_name=module_install_name))
__all__ = [
'get_network_driver', # export the function
'NetworkDriver' # also export the base class
]
108 changes: 73 additions & 35 deletions napalm_base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
from __future__ import print_function
from __future__ import unicode_literals

# std libs
import sys

# local modules
import napalm_base.exceptions
import napalm_base.helpers
Expand All @@ -29,7 +26,6 @@


class NetworkDriver(object):

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
Expand All @@ -47,17 +43,19 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None)
raise NotImplementedError

def __enter__(self):
try:
self.open()
except Exception: # noqa
exc_info = sys.exc_info()
return self.__raise_clean_exception(exc_info[0], exc_info[1], exc_info[2])
self.open()
return self

def __exit__(self, exc_type, exc_value, exc_traceback):
self.close()
if exc_type is not None:
return self.__raise_clean_exception(exc_type, exc_value, exc_traceback)
if exc_type is not None and (
exc_type.__name__ not in dir(napalm_base.exceptions) and
exc_type.__name__ not in __builtins__.keys()):
epilog = ("NAPALM didn't catch this exception. Please, fill a bugfix on "
"https://github.com/napalm-automation/napalm/issues\n"
"Don't forget to include this traceback.")
print(epilog)
return False

def __del__(self):
"""
Expand All @@ -71,27 +69,6 @@ def __del__(self):
except Exception:
pass

@staticmethod
def __raise_clean_exception(exc_type, exc_value, exc_traceback):
"""
This method is going to check if the exception exc_type is part of the builtins exceptions
or part of the napalm exceptions. If it is not, it will print a message on the screen
giving instructions to fill a bug.

Finally it will raise the original exception.

:param exc_type: Exception class.
:param exc_value: Exception object.
:param exc_traceback: Traceback.
"""
if (exc_type.__name__ not in dir(napalm_base.exceptions) and
exc_type.__name__ not in __builtins__.keys()):
epilog = ("NAPALM didn't catch this exception. Please, fill a bugfix on "
"https://github.com/napalm-automation/napalm/issues\n"
"Don't forget to include this traceback.")
print(epilog)
return False

def open(self):
"""
Opens a connection to the device.
Expand All @@ -114,6 +91,30 @@ def is_alive(self):
"""
raise NotImplementedError

def pre_connection_tests(self):
"""
This is a helper function used by the cli tool cl_napalm_show_tech. Drivers
can override this method to do some tests, show information, enable debugging, etc.
before a connection with the device is attempted.
"""
raise NotImplementedError

def connection_tests(self):
"""
This is a helper function used by the cli tool cl_napalm_show_tech. Drivers
can override this method to do some tests, show information, enable debugging, etc.
before a connection with the device has been successful.
"""
raise NotImplementedError

def post_connection_tests(self):
"""
This is a helper function used by the cli tool cl_napalm_show_tech. Drivers
can override this method to do some tests, show information, enable debugging, etc.
after a connection with the device has been closed successfully.
"""
raise NotImplementedError

def load_template(self, template_name, template_source=None,
template_path=None, **template_vars):
"""
Expand Down Expand Up @@ -1537,11 +1538,48 @@ def get_firewall_policies(self):
"""
raise NotImplementedError

def compliance_report(self, validation_file='validate.yml'):
def get_ipv6_neighbors_table(self):
"""
Get IPv6 neighbors table information.

Return a list of dictionaries having the following set of keys:
* interface (string)
* mac (string)
* ip (string)
* age (float) in seconds
* state (string)

For example::
[
{
'interface' : 'MgmtEth0/RSP0/CPU0/0',
'mac' : '5c:5e:ab:da:3c:f0',
'ip' : '2001:db8:1:1::1',
'age' : 1454496274.84,
'state' : 'REACH'
},
{
'interface': 'MgmtEth0/RSP0/CPU0/0',
'mac' : '66:0e:94:96:e0:ff',
'ip' : '2001:db8:1:1::2',
'age' : 1435641582.49,
'state' : 'STALE'
}
]
"""
raise NotImplementedError

def compliance_report(self, validation_file=None, validation_source=None):
"""
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.
report file. See https://napalm.readthedocs.io/en/latest/validate/index.html.

:param validation_file: Path to the file containing compliance definition. Default is None.
:param validation_source: Dictionary containing compliance rules.
:raise ValidationException: File is not valid.
:raise NotImplementedError: Method not implemented.
"""
return validate.compliance_report(self, validation_file=validation_file)
return validate.compliance_report(self, validation_file=validation_file,
validation_source=validation_source)
Loading