Skip to content

Commit 3571631

Browse files
committed
Merge branch 'develop'
2 parents d5f24b3 + f45fc4f commit 3571631

File tree

96 files changed

+8338
-2618
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+8338
-2618
lines changed

Diff for: .gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ test/unit/test_devices.py
6363

6464
report.json
6565
tags
66+
.pytest_cache/
6667

6768
docs/integrations/ansible/modules/napalm_*/
6869
docs/integrations/ansible/modules/source/*.json
69-
docs/napalm_ansible_repo/
70+
docs/napalm_ansible_repo/

Diff for: README.md

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ SaltStack
6060

6161
Beginning with release code named `Carbon` (2016.11), [NAPALM is fully integrated](https://mirceaulinic.net/2016-11-30-salt-carbon-released/) in SaltStack - no additional modules required. For setup recommendations, please see [napalm-salt](https://github.com/napalm-automation/napalm-salt). For documentation and usage examples, you can check the modules documentation, starting from the [release notes](https://docs.saltstack.com/en/develop/topics/releases/2016.11.0.html#network-automation-napalm) and [this blog post](https://mirceaulinic.net/2016-11-17-network-orchestration-with-salt-and-napalm/).
6262

63+
StackStorm
64+
----------
65+
66+
NAPALM is usable from StackStorm using the [NAPALM integration pack](https://github.com/StackStorm-Exchange/stackstorm-napalm). See that repository for instructions on installing and configuring the pack to work with StackStorm. General StackStorm documentation can be found at [https://docs.stackstorm.com/](https://docs.stackstorm.com/), and StackStorm can be easily spun up for testing using [Vagrant](https://github.com/StackStorm/st2vagrant) or [Docker](https://github.com/StackStorm/st2-docker).
67+
6368

6469
Contact
6570
=======
@@ -105,6 +110,7 @@ Blog Posts
105110
* [NAPALM, Ansible, and Cisco IOS](https://pynet.twb-tech.com/blog/automation/napalm-ios.html) by Kirk Byers
106111
* [Adding Cisco IOS support to NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support)](https://projectme10.wordpress.com/2015/12/07/adding-cisco-ios-support-to-napalm-network-automation-and-programmability-abstraction-layer-with-multivendor-support/) by Gabriele Gerbino
107112
* [Network orchestration with Salt and NAPALM](https://mirceaulinic.net/2016-11-17-network-orchestration-with-salt-and-napalm/) by Mircea Ulinic
113+
* [Network Configuration Consistency with StackStorm and NAPALM](https://stackstorm.com/2017/04/11/ensuring-network-configuration-consistency-stackstorm-napalm/) by Matt Oswalt
108114

109115
Presentations
110116
-------------

Diff for: docs/support/index.rst

+14-15
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,15 @@ General support matrix
88

99

1010

11-
===================== ========== ============= ============ ============ ============
12-
_ EOS JunOS IOS-XR NXOS IOS
13-
===================== ========== ============= ============ ============ ============
14-
**Module Name** napalm-eos napalm-junos napalm-iosxr napalm-nxos napalm-ios
15-
**Driver Name** eos junos iosxr nxos ios
16-
**Structured data** Yes Yes No Yes No
17-
**Minimum version** 4.15.0F 12.1 5.1.0 6.1 [#g1]_ 12.4(20)T
18-
**Backend library** `pyeapi`_ `junos-eznc`_ `pyIOSXR`_ `pynxos`_ `netmiko`_
19-
**Caveats** :doc:`eos` :doc:`nxos` :doc:`ios`
20-
===================== ========== ============= ============ ============ ============
11+
===================== ========== ============= ============ ============ ============ ============
12+
_ EOS Junos IOS-XR NX-OS NX-OS SSH IOS
13+
===================== ========== ============= ============ ============ ============ ============
14+
**Driver Name** eos junos iosxr nxos nxos_ssh ios
15+
**Structured data** Yes Yes No Yes No No
16+
**Minimum version** 4.15.0F 12.1 5.1.0 6.1 [#g1]_ 12.4(20)T
17+
**Backend library** `pyeapi`_ `junos-eznc`_ `pyIOSXR`_ `pynxos`_ `netmiko`_ `netmiko`_
18+
**Caveats** :doc:`eos` :doc:`nxos` :doc:`nxos` :doc:`ios`
19+
===================== ========== ============= ============ ============ ============ ============
2120

2221
.. _pyeapi: https://github.com/arista-eosplus/pyeapi
2322
.. _junos-eznc: https://github.com/Juniper/py-junos-eznc
@@ -34,18 +33,18 @@ Configuration support matrix
3433
----------------------------
3534

3635
===================== ========== ===== ========== ============== ==============
37-
_ EOS JunOS IOS-XR NXOS IOS
36+
_ EOS Junos IOS-XR NX-OS IOS
3837
===================== ========== ===== ========== ============== ==============
3938
**Config. replace** Yes Yes Yes Yes Yes
4039
**Config. merge** Yes Yes Yes Yes Yes
4140
**Compare config** Yes Yes Yes [#c1]_ Yes [#c4]_ Yes
42-
**Atomic Changes** Yes Yes Yes Yes/No [#c5]_ Yes
41+
**Atomic Changes** Yes Yes Yes Yes/No [#c5]_ Yes/No [#c5]_
4342
**Rollback** Yes [#c2]_ Yes Yes Yes/No [#c5]_ Yes
4443
===================== ========== ===== ========== ============== ==============
4544

4645
.. [#c1] Hand-crafted by the API as the device doesn't support the feature.
4746
.. [#c2] Not supported but emulated. Check caveats.
48-
.. [#c4] For merges, the diff is simply the merge config itself. See caveats.
47+
.. [#c4] For merges, the diff is very simplistic. See caveats.
4948
.. [#c5] No for merges. See caveats.
5049
5150
.. warning:: Before building a workflow to deploy configuration it is important you understand what the table above means;
@@ -67,10 +66,10 @@ Other methods
6766
.. |no| unicode:: U+0274C .. No
6867

6968
============================== ===== ===== ====== ====== =====
70-
_ EOS JunOS IOS-XR NXOS IOS
69+
_ EOS Junos IOS-XR NX-OS IOS
7170
============================== ===== ===== ====== ====== =====
7271
**load_template** |yes| |yes| |yes| |yes| |yes|
73-
**ping** |yes| |yes| |no| |no| |yes|
72+
**ping** |yes| |yes| |no| |yes| |yes|
7473
**traceroute** |yes| |yes| |yes| |yes| |yes|
7574
============================== ===== ===== ====== ====== =====
7675

Diff for: docs/tutorials/lab.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ Create a file named ``Vagrantfile`` (no file extension) in your working director
3535

3636
The above content is also available on `GitHub <https://raw.githubusercontent.com/napalm-automation/napalm/master/docs/tutorials/Vagrantfile>`_.
3737

38-
This Vagrantfile creates a base box and a vEOS box when you call "vagrant up"::
38+
This Vagrantfile creates a base box and a vEOS box when you call ``vagrant up``::
3939

40-
$ vagrant up
40+
$ vagrant up --provider virtualbox
4141
... [output omitted] ...
4242

4343
$ vagrant status

Diff for: docs/tutorials/wrapup.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ You've now tried the main pieces of NAPALM:
99
Shutting down
1010
-------------
1111

12-
Shut down the Vagrant virtual boxes. You can recreate them later using ``vagrant up`` if needed.
12+
Shut down the Vagrant virtual boxes. You can recreate them later using ``vagrant up`` if needed.::
1313

1414
$ vagrant destroy -f
1515

Diff for: docs/validate/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ then write the desired state using the same format the getter would retrieve it.
3636
'%usage': '<15.0'
3737

3838
- get_bgp_neighbors:
39-
default:
39+
global:
4040
router_id: 192.0.2.2
4141
peers:
4242
_mode: strict

Diff for: napalm/base/__init__.py

+19-9
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
]
3636

3737

38-
def get_network_driver(module_name, prepend=True):
38+
def get_network_driver(name, prepend=True):
3939
"""
4040
Searches for a class derived form the base NAPALM class NetworkDriver in a specific library.
4141
The library name must repect the following pattern: napalm_[DEVICE_OS].
@@ -48,7 +48,7 @@ def get_network_driver(module_name, prepend=True):
4848
.. _`Read the Docs`: \
4949
http://napalm.readthedocs.io/
5050
51-
:param module_name: the name of the device operating system or the name of the library.
51+
:param name: the name of the device operating system or the name of the library.
5252
:return: the first class derived from NetworkDriver, found in the library.
5353
:raise ModuleImportError: when the library is not installed or a derived class from \
5454
NetworkDriver was not found.
@@ -67,16 +67,16 @@ def get_network_driver(module_name, prepend=True):
6767
napalm.base.exceptions.ModuleImportError: Cannot import "napalm_wrong". Is the library \
6868
installed?
6969
"""
70-
if module_name == "mock":
70+
if name == "mock":
7171
return MockDriver
7272

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

7676
# Only lowercase allowed
77-
module_name = module_name.lower()
77+
name = name.lower()
7878
# Try to not raise error when users requests IOS-XR for e.g.
79-
module_install_name = module_name.replace('-', '')
79+
module_install_name = name.replace('-', '')
8080
community_install_name = "napalm_{name}".format(name=module_install_name)
8181
custom_install_name = "custom_napalm.{name}".format(name=module_install_name)
8282
# Can also request using napalm_[SOMETHING]
@@ -87,12 +87,22 @@ def get_network_driver(module_name, prepend=True):
8787
try:
8888
module = importlib.import_module(module_name)
8989
break
90-
except ImportError:
91-
pass
90+
except ImportError as e:
91+
try:
92+
# gotta love py23 differences
93+
message = e.message
94+
except AttributeError:
95+
message = e.msg
96+
if "No module named" in message:
97+
# py2 doesn't have ModuleNotFoundError exception
98+
failed_module = message.split()[-1]
99+
if failed_module.replace("'", "") in module_name:
100+
continue
101+
raise e
92102
else:
93103
raise ModuleImportError(
94104
'Cannot import "{install_name}". Is the library installed?'.format(
95-
install_name=module_install_name
105+
install_name=name
96106
)
97107
)
98108

Diff for: napalm/base/canonical_map.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
base_interfaces = {
66
"ATM": "ATM",
77
"AT": "ATM",
8+
"B": "Bdi",
9+
"Bd": "Bdi",
10+
"Bdi": "Bdi",
811
"EOBC": "EOBC",
912
"EO": "EOBC",
1013
"Ethernet": "Ethernet",
@@ -50,9 +53,13 @@
5053
"MFR": "MFR",
5154
"Multilink": "Multilink",
5255
"Mu": "Multilink",
53-
"PortChannel": "PortChannel",
54-
"Port-Channel": "PortChannel",
55-
"Po": "PortChannel",
56+
"n": "nve",
57+
"nv": "nve",
58+
"nve": "nve",
59+
"PortChannel": "Port-channel",
60+
"Port-channel": "Port-channel",
61+
"Port-Channel": "Port-channel",
62+
"Po": "Port-channel",
5663
"POS": "POS",
5764
"PO": "POS",
5865
"Serial": "Serial",
@@ -91,7 +98,7 @@
9198
"Management": "Ma",
9299
"MFR": "MFR",
93100
"Multilink": "Mu",
94-
"PortChannel": "Po",
101+
"Port-channel": "Po",
95102
"POS": "PO",
96103
"Serial": "Se",
97104
"TenGigabitEthernet": "Te",

Diff for: napalm/base/exceptions.py

+21-14
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@
1717
from __future__ import unicode_literals
1818

1919

20-
class ModuleImportError(Exception):
20+
class NapalmException(Exception):
21+
'''
22+
Base Exception Class.
23+
'''
24+
pass
25+
26+
27+
class ModuleImportError(NapalmException):
2128
pass
2229

2330

24-
class ConnectionException(Exception):
31+
class ConnectionException(NapalmException):
2532
'''
2633
Unable to connect to the network device.
2734
'''
@@ -59,59 +66,59 @@ class ConnectionClosedException(ConnectionException):
5966
pass
6067

6168

62-
class ReplaceConfigException(Exception):
69+
class ReplaceConfigException(NapalmException):
6370
pass
6471

6572

66-
class MergeConfigException(Exception):
73+
class MergeConfigException(NapalmException):
6774
pass
6875

6976

70-
class CommitError(Exception):
77+
class CommitError(NapalmException):
7178
'''
7279
Raised when unable to commit the candidate config
7380
into the running config.
7481
'''
7582
pass
7683

7784

78-
class LockError(Exception):
85+
class LockError(NapalmException):
7986
'''
8087
Unable to lock the candidate config.
8188
'''
8289
pass
8390

8491

85-
class UnlockError(Exception):
92+
class UnlockError(NapalmException):
8693
'''
8794
Unable to unlock the candidate config.
8895
'''
8996
pass
9097

9198

92-
class SessionLockedException(Exception):
99+
class SessionLockedException(NapalmException):
93100
pass
94101

95102

96-
class CommandTimeoutException(Exception):
103+
class CommandTimeoutException(NapalmException):
97104
pass
98105

99106

100-
class CommandErrorException(Exception):
107+
class CommandErrorException(NapalmException):
101108
pass
102109

103110

104-
class DriverTemplateNotImplemented(Exception):
111+
class DriverTemplateNotImplemented(NapalmException):
105112
pass
106113

107114

108-
class TemplateNotImplemented(Exception):
115+
class TemplateNotImplemented(NapalmException):
109116
pass
110117

111118

112-
class TemplateRenderException(Exception):
119+
class TemplateRenderException(NapalmException):
113120
pass
114121

115122

116-
class ValidationException(Exception):
123+
class ValidationException(NapalmException):
117124
pass

Diff for: napalm/base/netmiko_helpers.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# The contents of this file are licensed under the Apache License, Version 2.0
2+
# (the "License"); you may not use this file except in compliance with the
3+
# License. You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations under
11+
# the License.
12+
from __future__ import unicode_literals
13+
import inspect
14+
from netmiko import BaseConnection
15+
16+
17+
def netmiko_args(optional_args):
18+
"""Check for Netmiko arguments that were passed in as NAPALM optional arguments.
19+
20+
Return a dictionary of these optional args that will be passed into the Netmiko
21+
ConnectHandler call.
22+
"""
23+
netmiko_args, _, _, netmiko_defaults = inspect.getargspec(BaseConnection.__init__)
24+
25+
check_self = netmiko_args.pop(0)
26+
if check_self != 'self':
27+
raise ValueError("Error processing Netmiko arguments")
28+
29+
netmiko_argument_map = dict(zip(netmiko_args, netmiko_defaults))
30+
31+
# Netmiko arguments that are integrated into NAPALM already
32+
netmiko_filter = ['ip', 'host', 'username', 'password', 'device_type', 'timeout']
33+
34+
# Filter out all of the arguments that are integrated into NAPALM
35+
for k in netmiko_filter:
36+
netmiko_argument_map.pop(k)
37+
38+
# Check if any of these arguments were passed in as NAPALM optional_args
39+
netmiko_optional_args = {}
40+
for k, v in netmiko_argument_map.items():
41+
try:
42+
netmiko_optional_args[k] = optional_args[k]
43+
except KeyError:
44+
pass
45+
46+
# Return these arguments for use with establishing Netmiko SSH connection
47+
return netmiko_optional_args

0 commit comments

Comments
 (0)