-
-
Notifications
You must be signed in to change notification settings - Fork 14
Developing NetDoc
You are invited to contribute to the improvement of NetDoc. Before starting, please open a issue in the NetDoc repository and discuss your idea.
To begin, you need to fork the NetDoc repository on GitHub.
Next, set up your local environment as follows:
mkdir ~/src
cd ~/src
ln -s /opt/netbox
git clone https://github.com/USERNAME/netdoc
git checkout -b NEWBRANCH
After executing the above commands, ensure that:
-
~/src/netbox
points to your local NetBox installation. -
~/src/netdoc
points to your forked NetDoc repository.
Replace the following placeholders in the script:
- USERNAME: replace with your GitHub username.
- NEWBRANCH: replace with the name of the branch you are creating.
Please note that a local NetBox configuration with the NetDoc plugin installed is assumed. Refer to the third chapter on how to install NetBox with NetDoc.
Within the third chapter, NetDoc is initially installed from the official PyPI repository. However, for development purposes, it is necessary to utilize a locally available version of NetDoc.
sudo -u netbox echo "-e ${HOME}/src/netdoc" > /opt/netbox/local_requirements.txt
sudo -u netbox /opt/netbox/upgrade.sh
To circumvent potential permission conflicts, it is advisable to reinstall NetBox using your individual user account when performing a development installation.
During the development process, it is essential to monitor logs in real-time and frequently restart daemons. As a common practice, I am accustomed to manually initiating daemons from the command-line interface (CLI).
/opt/netbox/venv/bin/python3 manage.py runserver 0.0.0.0:8000 --insecure
/opt/netbox/venv/bin/python3 manage.py rqworker high default low
Before committing a pull request, it is crucial to test your environment. Testing locally will save you time.
The PostgreSQL user configured in NetBox must have the privilege to create new databases:
sudo -u postgres psql
alter user netbox createdb;
Install additional prerequisites:
sudo apt install pre-commit
/opt/netbox/venv/bin/pip install pylint
Lint your code:
cd ~/src/netdoc
pre-commit run --all-files
/opt/netbox/venv/bin/pylint --rcfile=.pylintrc netdoc
Test your code:
/opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py test netdoc --keepdb
If everything is functioning correctly, you can proceed to commit your code and create a pull request.
In order to support new devices, the following steps should be taken:
- Incorporate the new discovery mode into the DiscoveryModeChoices class in the dictionaries.py file
- Eventually modify the Credential class accordingly in the models.py file.
- Eventually make adjustments to nornir_inventory.py to enable the passing of attributes from NetDoc inventory to Nornir.
- Integrate the new discovery script into the discoverers module. Thoroughly test and debug the discovery script using scripts/discovery_immediate.py.
- Include the new ingestor scripts within the ingestors module.
- Develop a new testing scenario.
For further guidance and as an example, please refer to this pull request.
In order to support new stencils, the following steps should be taken:
- Define new device roles into DeviceImageChoices on models.py.
- Add the css style into DRAWIO_ROLE_MAP on utils.py using Draw.io web application as template (export a diagram containing only one stencil in XML format).
- Add the stencil in PNG format into netdoc/static/netdoc/img (export a diagram containing only one stencil in PNG format, with a transparent background, without including the diagram in the image file).
For further guidance and as an example, please refer to this pull request.
In order to support new diagrams, the following steps should be taken:
- Define new diagram types into DiagramModeChoices on models.py.
- Add the functions to get the diagram data and to export it in Draw.io format into netdoc/utls.py: in the example linked below
get_site_topology_data
andget_site_drawio_topology
implement the newsite
diagram type.
For further guidance and as an example, please refer to this pull request.
Using and developing NetDoc requires to debug disvoery, parser, and ingestor scripts. In order, follow the below paragraphs.
Manually discover one or more devices:
from netdoc import tasks
tasks.discovery(["172.25.82.34","172.25.82.39","172.25.82.40"])
Manually parse downloaded logs using official NTC templates:
import textfsm
import pprint
template_file = 'ntc_templates/templates/cisco_xr_show_ipv4_interface.textfsm'
raw_output_file = 'tests/cisco_xr/show_ipv4_interface/cisco_xr_show_ipv4_interface.raw'
with open(template_file) as fd_t, open(raw_output_file) as fd_o:
re_table = textfsm.TextFSM(fd_t)
parsed_header = re_table.header
parsed_output = re_table.ParseText(fd_o.read())
pprint.pprint(parsed_header)
pprint.pprint(parsed_output)
If you find errors on NTC tempaltes, please open an issue on NTC.
Manually parse NetDoc logs using official NTC templates:
from netdoc import models
import importlib
from netdoc import functions
import logging
import pprint
request = "show vrf"
mode = "netmiko_cisco_nxos"
request = "show ip interface"
mode = None
logs = models.DiscoveryLog.objects.all()
request = None # or "show vrf"
mode = None # or "netmiko_cisco_nxos"
if mode:
logs = logs.filter(discoverable__mode=mode)
if request:
logs = logs.filter(request=request)
logs = logs.filter(success=True)
for log in logs:
try:
functions.log_parse(log)
except:
pass
print('Command: ', log.command)
print('ID: ', log.id)
print('Address: ', log.discoverable.address)
print('Device: ', log.discoverable.device)
print('Parsed: ', log.parsed)
print('Items: ', len(log.parsed_output))
pprint.pprint(log.parsed_output)
print('-' * 70)
Manually ingest NetDoc parsed logs using official NTC templates:
from netdoc import models
import importlib
from netdoc.ingestors import functions
import logging
request = None # or "show vrf"
mode = None # or "netmiko_cisco_nxos"
logs = models.DiscoveryLog.objects.all()
if mode:
logs = logs.filter(discoverable__mode=mode)
if request:
logs = logs.filter(request=request)
logs = logs.filter(parsed=True)
for log in logs:
try:
functions.log_ingest(log)
except functions.NoIngestor:
pass
except functions.Postponed as err:
print(err)