Skip to content

Commit 3041445

Browse files
authored
Merge pull request #4 from napalm-automation/develop
Release 1.0.0
2 parents de10217 + e82b108 commit 3041445

30 files changed

+771
-1
lines changed

.gitignore

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
5+
# C extensions
6+
*.so
7+
8+
# Distribution / packaging
9+
.Python
10+
env/
11+
bin/
12+
build/
13+
develop-eggs/
14+
dist/
15+
eggs/
16+
lib/
17+
lib64/
18+
parts/
19+
sdist/
20+
var/
21+
*.egg-info/
22+
.installed.cfg
23+
*.egg
24+
25+
# Installer logs
26+
pip-log.txt
27+
pip-delete-this-directory.txt
28+
29+
# Unit test / coverage reports
30+
htmlcov/
31+
.tox/
32+
.coverage
33+
.cache
34+
nosetests.xml
35+
coverage.xml
36+
37+
# Translations
38+
*.mo
39+
40+
# Mr Developer
41+
.mr.developer.cfg
42+
.project
43+
.pydevproject
44+
45+
# Rope
46+
.ropeproject
47+
48+
# Django stuff:
49+
*.log
50+
*.pot
51+
52+
# Sphinx documentation
53+
docs/_build/
54+
docs/_static/
55+
56+
.idea
57+
.DS_Store
58+
59+
env
60+
*.swp
61+
62+
test/unit/test_devices.py
63+
64+
report.json
65+
tags
66+
.pytest_cache/
67+

.travis.yml

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
sudo: required
2+
3+
language: python
4+
python:
5+
- 2.7
6+
- 3.6
7+
- 3.6
8+
9+
matrix:
10+
include:
11+
- python: 3.6
12+
env: TOXENV=black
13+
- python: 3.6
14+
env: TOXENV=pylama
15+
16+
install:
17+
- pip install tox tox-travis coveralls
18+
19+
script:
20+
- tox
21+
22+
deploy:
23+
provider: pypi
24+
user: ogenstad
25+
password:
26+
secure: N1fnrXFMsJ4+uc5hNwSQv4tw7/BNV8Fd/IjTvIbxVocloDAwf7+mnwB6CTj2WrN3B9/2BLWtZj20tcxp7qD6zugWJt4RqnnqCjHAGq2qu2p3SqtHYJ1tCnoJzaNrnrj1Oklyi58dlIR5qv5495Ig+2ghOfg/lRELfZUjuDHoQv7e6E9olGtuDpQ7sqLW4emU/9+gdm6ebE7+V9nuHQA2JGpQcDpqvhbzokCkrn96Xfmvorw9g1fCR6Me0AcsbcMYuCbJJbPJ6iWEdc60PyetT7l68DFDtIIEev91exPUWDYiSQhLDREOoDtCaDyVwJPM4ZHPOgyDveKu02//CMBJMkmYwbm+SapJ9F7JOrQLORKlerTmpRg+pm2ZpzkUb13F545z1CNP+r0+GGWSuci+ALdG3stiFdLf7RF/xxZ5RzYNWyFw6yFt+yEMDHJbkv3yGRNjNK6pNLPlvAmmz76BINplk4NeKz0REffvnEF56MxjqUFr4WA6ieCGF00F+ECifW53cv38h7rP3DPmYSgY4YDAtXTblwkzMYCz8U0Ob4vJgIsPs6YpVN3/tCNI/21rdvYiSpP0wgKQvPt67KuFeVInaHTARjUK3/XZfd/qGNgkrl+TSWAvVvQlhkZTUlJqBvnt23PHnvy3qu5KiBwlu5l+hSUERNiqgBaA8cwd4nA=
27+
distributions: "sdist bdist_wheel"
28+
on:
29+
tags: true
30+
branch: master
31+
32+
after_success:
33+
- coveralls

Dockerfile

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM python:3.6
2+
3+
COPY . /napalm-inspector
4+
5+
RUN pip install /napalm-inspector
6+
7+
ENV FLASK_APP napalm_inspector
8+
9+
ENTRYPOINT flask run --host=0.0.0.0

MANIFEST.in

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
include requirements*
2+
graft napalm_inspector/static
3+
graft napalm_inspector/templates

Makefile

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CONTAINER_NAME := "napalm-inspector"
2+
3+
4+
.PHONY: docker
5+
docker:
6+
docker build . --tag napalm-inspector:latest
7+
8+
9+
.PHONY: start
10+
start: stop
11+
docker run -it --name $(CONTAINER_NAME) -p 5000:5000 napalm-inspector:latest
12+
13+
14+
.PHONY: stop
15+
stop:
16+
@docker rm $(CONTAINER_NAME) -f || exit 0

README.md

+36-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,36 @@
1-
# napalm-inspector
1+
[![Build Status](https://travis-ci.org/napalm-automation/napalm-inspector.svg?branch=develop)](https://travis-ci.org/napalm-automation/napalm-inspector)
2+
[![Coverage Status](https://coveralls.io/repos/github/napalm-automation/napalm-inspector/badge.svg?branch=develop)](https://coveralls.io/github/napalm-automation/napalm-inspector?branch=develop)
3+
4+
NAPALM-Inspector
5+
================
6+
7+
The NAPALM Inspector is a web application aimed to help with troubleshooting the getters in NAPALM. If you have found a bug in one of the getters you can use this tool as an easy way to help the developers figure out what's going on.
8+
9+
Once the application is up and running visit [http://127.0.0.1:5000](http://127.0.0.1:5000) and choose the platform and getter you want to test. You will be asked to provide the information your network devices, i.e. when the application will ask you for the output from a command like `show version` then you just paste the output into the form and move on from there.
10+
11+
Installation
12+
============
13+
14+
```bash
15+
pip install napalm-inspector
16+
export FLASK_APP=napalm_inspector
17+
flask run
18+
```
19+
20+
Running from Docker
21+
===================
22+
23+
```bash
24+
git clone https://github.com/napalm-automation/napalm-inspector
25+
cd napalm-inspector
26+
make docker
27+
make start
28+
```
29+
30+
Press Control+C to end the application when done.
31+
32+
Once you are done you can remove the container
33+
34+
```bash
35+
make stop
36+
```

napalm_inspector/__init__.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from flask import Flask
2+
3+
4+
def create_app():
5+
app = Flask(__name__)
6+
7+
from napalm_inspector.errors import bp as errors_bp
8+
9+
app.register_blueprint(errors_bp)
10+
11+
from napalm_inspector.main import bp as main_bp
12+
13+
app.register_blueprint(main_bp)
14+
15+
return app

napalm_inspector/drivers.py

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from builtins import super
2+
from napalm_inspector.exceptions import MissingData
3+
from napalm.ios import IOSDriver
4+
from napalm.nxos_ssh import NXOSSSHDriver
5+
import re
6+
7+
8+
class DummyDevice:
9+
10+
def __init__(self, data):
11+
self.data = data
12+
13+
def send_command(self, command):
14+
label = re.sub(r"[\[\]\*\^\+\s\|]", "_", command)
15+
if label not in self.data:
16+
raise MissingData(command)
17+
18+
return self.data[label]
19+
20+
21+
class OfflineIOSDriver(IOSDriver):
22+
23+
def __init__(self, data):
24+
super().__init__("127.0.0.1", "", "")
25+
self.device = DummyDevice(data)
26+
27+
28+
class OfflineNXOSSSHDriver(NXOSSSHDriver):
29+
30+
def __init__(self, data):
31+
self.device = DummyDevice(data)
32+
33+
34+
test_drivers = {"ios": OfflineIOSDriver, "nxos_ssh": OfflineNXOSSSHDriver}

napalm_inspector/errors/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from flask import Blueprint
2+
3+
bp = Blueprint("errors", __name__)
4+
5+
from napalm_inspector.errors import handlers # noqa

napalm_inspector/errors/handlers.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from flask import render_template
2+
from . import bp
3+
4+
5+
@bp.app_errorhandler(404)
6+
def not_found_error(error):
7+
return render_template("404.html"), 404

napalm_inspector/exceptions.py

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import re
2+
3+
4+
class MissingData(Exception):
5+
6+
def __init__(self, request):
7+
self.request = request
8+
self.request_id = re.sub(r"[\[\]\*\^\+\s\|]", "_", request)

napalm_inspector/main/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from flask import Blueprint
2+
3+
bp = Blueprint("main", __name__)
4+
5+
from napalm_inspector.main import routes # noqa

napalm_inspector/main/routes.py

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from napalm_inspector.exceptions import MissingData
2+
from napalm_inspector.main import bp
3+
from napalm_inspector.drivers import test_drivers
4+
from flask import render_template, request
5+
import json
6+
import traceback
7+
8+
9+
@bp.route("/")
10+
def index():
11+
"""Main page."""
12+
return render_template("index.html")
13+
14+
15+
@bp.route("/test-getters/")
16+
def getters():
17+
drivers = list(test_drivers.keys())
18+
return render_template("test_getter_platforms.html", drivers=drivers)
19+
20+
21+
@bp.route("/test-getters/<platform>/")
22+
def platform(platform):
23+
"""Main page."""
24+
25+
driver = test_drivers[platform]
26+
27+
napalm_getters = [g for g in dir(driver) if g.startswith("get_")]
28+
return render_template("platform.html", platform=platform, getters=napalm_getters)
29+
30+
31+
@bp.route("/test-getters/<platform>/<getter>", methods=["GET", "POST"])
32+
def getter(platform, getter):
33+
"""Getter test."""
34+
tb = None
35+
exception = None
36+
data = None
37+
missing_command = None
38+
missing_command_id = None
39+
input_data = {}
40+
form_data = []
41+
if request.method == "POST":
42+
for entry in request.form:
43+
input_data[entry] = request.form[entry].replace("\r\n", "\n")
44+
command = {}
45+
command["id"] = entry
46+
command["data"] = request.form[entry]
47+
form_data.append(command)
48+
49+
driver = test_drivers[platform]
50+
dev = driver(input_data)
51+
52+
func = getattr(dev, getter)
53+
try:
54+
data = func()
55+
data = json.dumps(data, indent=4, sort_keys=True)
56+
57+
except MissingData as e:
58+
missing_command = e.request
59+
missing_command_id = e.request_id
60+
except Exception as e:
61+
tb = traceback.format_exc()
62+
exception = e
63+
64+
return render_template(
65+
"getter.html",
66+
getter=getter,
67+
data=data,
68+
traceback=tb,
69+
exception=exception,
70+
form_data=form_data,
71+
missing_command=missing_command,
72+
missing_command_id=missing_command_id,
73+
platform=platform,
74+
)
1.12 KB
Binary file not shown.

napalm_inspector/static/logo.png

2.09 KB
Loading

napalm_inspector/static/napalm.css

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
body {
2+
padding-top: 8rem;
3+
}
4+
5+
.napalm-center {
6+
padding: 3rem 1.5rem;
7+
text-align: center;
8+
}
9+
10+

napalm_inspector/templates/404.html

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{% extends "base.html" %}
2+
3+
4+
{% block content %}
5+
<div class="napalm-center">
6+
<h1>404</h1>
7+
<p>Not even close, that page doesn't exist</p>
8+
</div>
9+
10+
{% endblock %}
11+

0 commit comments

Comments
 (0)