Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .bandit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ skips: []
# No need to check for security issues in the test scripts!
exclude_dirs:
- "./tests/"
- "./docs/"
3 changes: 2 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import toml

sys.path.insert(0, os.path.abspath("../.."))
sys.path.append(os.path.abspath("sphinxext"))
toml_dict = toml.load("../../pyproject.toml")


Expand All @@ -33,7 +34,7 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "m2r2"]
extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "m2r2", "exec"]

autodoc_default_options = {
"members": True,
Expand Down
1 change: 1 addition & 0 deletions docs/source/netutils/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Netutils Functions
dns/index
interface/index
ip/index
lib_mapping/index
mac/index
password/index
ping/index
Expand Down
151 changes: 151 additions & 0 deletions docs/source/netutils/lib_mapping/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
*****************
Library Mappings
*****************

These dictionaries provide mappings in expected vendor names between Netmiko, NAPALM, pyntc, ntc-templates, pyats, and scrapli. For each non-reversed mapper, the keys of the dictionary represent the driver used for that library while the values represent the "normalized" driver based on netmiko.

These dictionaries allow you to keep your Source of Truth platform data consistent and still easily switch between automation libraries. For example, you may be storing your device platform data in Nautobot. In a Nautobot platform, you can store the NAPALM driver needed for that platform. What if you wanted to write
a python script to leverage the backup capabilities of pyntc? Here's an example of how you could use the following dictionaries to perform mappings from your stored Nautobot NAPALM driver to the pyntc driver needed for your script.

.. code-block:: python

import pynautobot
from netutils.lib_mapper import NAPALM_LIB_MAPPER, PYNTC_LIB_MAPPER_REVERSE
from pyntc import ntc_device as NTC


# Get device from Nautobot
nautobot = pynautobot.api(url="http://mynautobotinstance.com",token="mytoken")

# Get Napalm driver and save for later use.
device = nautobot.dcim.devices.get(name="mydevice")
sot_driver = device.platform.napalm_driver


# Connect to device via Napalm
driver = napalm.get_network_driver("ios")

device = driver(
hostname="device.name",
username="demo",
password="secret"
)

# Do Napalm tasks

pyntc_driver = PYNTC_LIB_MAPPER_REVERSE.get(NAPALM_LIB_MAPPER.get(sot_driver))
net_con = NTC(host=device.name, username="demo", password="secret", device_type=pyntc_driver)

# Do pyntc tasks

Another use case could be using an example like the above in an Ansible filter. That would allow you to write a filter utilizing whichever automation library you needed without having to store the driver for each one in your Source of Truth.

Napalm Mapper
===================
.. exec::
import json
from netutils.lib_mapper import NAPALM_LIB_MAPPER
json_obj = json.dumps(NAPALM_LIB_MAPPER, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Reverse Napalm Mapper
=====================
.. exec::
import json
from netutils.lib_mapper import NAPALM_LIB_MAPPER_REVERSE
json_obj = json.dumps(NAPALM_LIB_MAPPER_REVERSE, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

PyNTC Mapper
==============
.. exec::
import json
from netutils.lib_mapper import PYNTC_LIB_MAPPER
json_obj = json.dumps(PYNTC_LIB_MAPPER, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Reverse PyNTC Mapper
====================
.. exec::
import json
from netutils.lib_mapper import PYNTC_LIB_MAPPER_REVERSE
json_obj = json.dumps(PYNTC_LIB_MAPPER_REVERSE, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Ansible Mapper
==============
.. exec::
import json
from netutils.lib_mapper import ANSIBLE_LIB_MAPPER
json_obj = json.dumps(ANSIBLE_LIB_MAPPER, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Reverse Ansible Mapper
======================
.. exec::
import json
from netutils.lib_mapper import ANSIBLE_LIB_MAPPER_REVERSE
json_obj = json.dumps(ANSIBLE_LIB_MAPPER_REVERSE, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

PyATS Mapper
==============
.. exec::
import json
from netutils.lib_mapper import PYATS_LIB_MAPPER
json_obj = json.dumps(PYATS_LIB_MAPPER, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Reverse PyATS Mapper
====================
.. exec::
import json
from netutils.lib_mapper import PYATS_LIB_MAPPER_REVERSE
json_obj = json.dumps(PYATS_LIB_MAPPER_REVERSE, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Scrapli Mapper
==============
.. exec::
import json
from netutils.lib_mapper import SCRAPLI_LIB_MAPPER
json_obj = json.dumps(SCRAPLI_LIB_MAPPER, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Reverse Scrapli Mapper
======================
.. exec::
import json
from netutils.lib_mapper import SCRAPLI_LIB_MAPPER_REVERSE
json_obj = json.dumps(SCRAPLI_LIB_MAPPER_REVERSE, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

NTC Templates Mapper
====================
.. exec::
import json
from netutils.lib_mapper import NTCTEMPLATES_LIB_MAPPER
json_obj = json.dumps(NTCTEMPLATES_LIB_MAPPER, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")

Reverse NTC Templates Mapper
============================
.. exec::
import json
from netutils.lib_mapper import NTCTEMPLATES_LIB_MAPPER_REVERSE
json_obj = json.dumps(NTCTEMPLATES_LIB_MAPPER_REVERSE, sort_keys=True, indent=4)
json_obj = json_obj[:-1] + " }"
print(f".. code-block:: JavaScript\n\n {json_obj}\n\n")


46 changes: 46 additions & 0 deletions docs/source/sphinxext/exec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""File used to define sphinx exec directive."""
import sys
from os.path import basename

try:
from StringIO import StringIO
except ImportError:
from io import StringIO

from docutils.parsers.rst import Directive
from docutils import nodes, statemachine


class ExecDirective(Directive):
"""Execute the specified python code and insert the output into the document."""

has_content = True

def run(self):
"""Function used when adding the directive to an index.rst."""
old_stdoutout, sys.stdout = sys.stdout, StringIO()

tab_width = self.options.get("tab-width", self.state.document.settings.tab_width)
source = self.state_machine.input_lines.source(self.lineno - self.state_machine.input_offset - 1)

try:
exec("\n".join(self.content)) # pylint: disable=exec-used
text = sys.stdout.getvalue()
lines = statemachine.string2lines(text, tab_width, convert_whitespace=True)
self.state_machine.insert_input(lines, source)
return []
except Exception: # pylint: disable=W0703
return [
nodes.error(
None,
nodes.paragraph(text="Unable to execute python code at %s:%d:" % (basename(source), self.lineno)),
nodes.paragraph(text=str(sys.exc_info()[1])),
)
]
finally:
sys.stdout = old_stdoutout


def setup(app):
"""Adds class as sphinx directive."""
app.add_directive("exec", ExecDirective)
2 changes: 1 addition & 1 deletion netutils/lib_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
"viptela": "cisco_viptella",
}

SCRAPLI = {
SCRAPLI_LIB_MAPPER = {
"cisco_iosxe": "cisco_ios",
"cisco_iosxr": "cisco_xr",
"cisco_nxos": "cisco_nxos",
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ classifiers = [
include = [
"CHANGELOG.md",
"LICENSE",
"netutils/protocols.json",
"README.md",
"netutils/protocols.json"
]

[tool.poetry.dependencies]
Expand Down