Netglass snapshot
This commit is contained in:
parent
688038b845
commit
90b644f921
35
Dockerfile
Normal file
35
Dockerfile
Normal file
@ -0,0 +1,35 @@
|
||||
FROM ubuntu:focal AS build
|
||||
|
||||
ENV TZ=Europe/Berlin
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
|
||||
echo $TZ > /etc/timezone
|
||||
|
||||
RUN apt-get update && apt-get install -qq --no-install-recommends\
|
||||
apt-transport-https git nodejs npm && npm install --global yarn
|
||||
|
||||
WORKDIR /tmp
|
||||
RUN git clone https://github.com/hopglass/hopglass
|
||||
|
||||
WORKDIR /tmp/hopglass
|
||||
RUN yarn install && node_modules/grunt/bin/grunt
|
||||
|
||||
FROM ubuntu:focal
|
||||
COPY --from=build /tmp/hopglass/build /hopglass
|
||||
|
||||
RUN apt-get update && apt-get install -qq --no-install-recommends\
|
||||
nginx python3-venv
|
||||
|
||||
ADD . /app
|
||||
|
||||
RUN cp /app/config.json /hopglass/config.json
|
||||
|
||||
RUN cd /etc/nginx &&\
|
||||
cp /app/nginx.conf sites-available/hopglass;\
|
||||
ln -s ../sites-available/hopglass sites-enabled/hopglass;\
|
||||
rm sites-enabled/default || true
|
||||
|
||||
WORKDIR /app/netglass
|
||||
RUN python3 -m venv flask &&\
|
||||
flask/bin/pip install -U -r requirements.txt
|
||||
|
||||
CMD ["/app/run.sh"]
|
21
README.md
21
README.md
@ -0,0 +1,21 @@
|
||||
# Netbox: NetGlass
|
||||
|
||||
View cable topology in [hopglass](https://github.com/hopglass/hopglass) fashioned graph view.
|
||||
|
||||
## Requirements
|
||||
|
||||
* A docker host
|
||||
* docker-compose
|
||||
|
||||
## Prepare
|
||||
|
||||
Netglass acts as replacement for [hoplass-server](https://github.com/hopglass/hopglass-server) and uses NetBox's API to gather wiring information.
|
||||
|
||||
First go to your NetBox instance and create a read-only Token. Remember that tokens for users from LDAP backends do not work. Create a file `.env` with the contents
|
||||
|
||||
```
|
||||
NETBOX_URL=https://netbox.your.tld
|
||||
NETBOX_TOKEN=70bdtoken89nhuf
|
||||
```
|
||||
|
||||
Run `docker-compose up -d` to build the hopglass instance.
|
45
config.json
Normal file
45
config.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"dataPath": "/data/",
|
||||
"siteName": "NetGlass",
|
||||
"mapSigmaScale": 0.5,
|
||||
"showContact": false,
|
||||
"maxAge": 365,
|
||||
"domainNames": [
|
||||
{"domain": "net", "name": "Testnetz"}
|
||||
],
|
||||
"mapLayers": [
|
||||
{
|
||||
"name": "OpenStreetMap.HOT"
|
||||
}
|
||||
],
|
||||
"_nodeInfos": [
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=1&theme=light&width=600&height=300&var-nodeid={NODE_ID}"
|
||||
},
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=2&theme=light&width=600&height=500&var-nodeid={NODE_ID}"
|
||||
},
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/node-byid?var-nodeid={NODE_ID}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/node-byid?panelId=3&theme=light&width=600&height=200&var-nodeid={NODE_ID}"
|
||||
}
|
||||
],
|
||||
"_globalInfos": [
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/global?var-job=dus",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/global?panelId=1&&theme=light&width=800&height=600&var-job=dus"
|
||||
},
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/global?var-job=dus",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/global?panelId=8&&theme=light&width=800&height=600&var-job=dus"
|
||||
}
|
||||
],
|
||||
"_linkInfos": [
|
||||
{ "href": "https://map.eulenfunk.de/stats/dashboard/db/links?var-source={SOURCE}&var-target={TARGET}",
|
||||
"thumbnail": "https://map.eulenfunk.de/stats/render/dashboard-solo/db/links?panelId=1&&theme=light&width=800&height=600&var-source={SOURCE}&var-target={TARGET}"
|
||||
}
|
||||
],
|
||||
"siteNames": [
|
||||
{ "site": "net", "name": "Location" }
|
||||
],
|
||||
"_hwImg": [
|
||||
]
|
||||
}
|
||||
|
8
docker-compose.yml
Normal file
8
docker-compose.yml
Normal file
@ -0,0 +1,8 @@
|
||||
version: '3'
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
image: netglass:dev
|
||||
environment:
|
||||
- NETBOX_URL
|
||||
- NETBOX_TOKEN
|
111
netglass/netglass.py
Executable file
111
netglass/netglass.py
Executable file
@ -0,0 +1,111 @@
|
||||
#!flask/bin/python3
|
||||
import re
|
||||
import os
|
||||
from flask import Flask, jsonify
|
||||
import pynetbox
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
box = pynetbox.api(
|
||||
os.environ.get('NETBOX_URL'),
|
||||
token=os.environ['NETBOX_TOKEN']
|
||||
)
|
||||
|
||||
netglass = Flask(__name__)
|
||||
|
||||
@netglass.route('/graph.json')
|
||||
def net_graph():
|
||||
links = []
|
||||
nodes = []
|
||||
dcim_port_types = ['dcim.interface','dcim.frontport','dcim.rearport']
|
||||
|
||||
def _isdevice(device):
|
||||
if isinstance(device, pynetbox.models.dcim.Devices):
|
||||
return device
|
||||
|
||||
for wire in box.dcim.cables.all():
|
||||
term_a = wire.termination_a.device if wire.termination_a_type in dcim_port_types else None
|
||||
term_b = wire.termination_b.device if wire.termination_b_type in dcim_port_types else None
|
||||
|
||||
for node in [term_a,term_b]:
|
||||
if not _isdevice(node):
|
||||
continue
|
||||
if not next((n for n in nodes if n['node_id'] == str(node.id)), None):
|
||||
nodes.append({
|
||||
'node_id': str(node.id),
|
||||
'id': str(node.id)
|
||||
})
|
||||
|
||||
link = {
|
||||
'bidirect': True,
|
||||
'source': next((
|
||||
i for i, item in enumerate(nodes)
|
||||
if term_a and item['node_id'] == str(term_a.id)), None),
|
||||
'target': next((
|
||||
i for i, item in enumerate(nodes)
|
||||
if term_b and item['node_id'] == str(term_b.id)), None),
|
||||
'tq': 1,
|
||||
}
|
||||
if link['source'] != None and link['target'] != None:
|
||||
links.append(link)
|
||||
|
||||
return jsonify({'batadv':{
|
||||
'directed': True,
|
||||
'graph': None,
|
||||
'multigraph': True,
|
||||
'links': links,
|
||||
'nodes': nodes,
|
||||
},
|
||||
'version': 1})
|
||||
|
||||
@netglass.route('/nodes.json')
|
||||
def net_nodes():
|
||||
nodes = []
|
||||
for node in [
|
||||
n for n in box.dcim.devices.all()
|
||||
if isinstance(n, pynetbox.models.dcim.Devices)]:
|
||||
lastseen = datetime.now().replace(microsecond=0)
|
||||
addresses = []
|
||||
for primary_ip in [node.primary_ip4,node.primary_ip6]:
|
||||
if primary_ip:
|
||||
addresses.append(re.sub(r'/\d+', '', primary_ip.address))
|
||||
nodes.append({
|
||||
'flags': {'online': True, 'gateway': False},
|
||||
'firstseen': lastseen.isoformat(),
|
||||
'lastseen': lastseen.isoformat(),
|
||||
'nodeinfo': {
|
||||
'hostname': node.display_name,
|
||||
'node_id': str(node.id),
|
||||
'network': { 'mac': node.name, 'addresses': addresses },
|
||||
'mesh_interfaces': [node.name],
|
||||
'mesh': {
|
||||
'bat0': { 'interfaces': { 'other': [node.name] } }
|
||||
},
|
||||
'system': {
|
||||
'site_code': 'net'
|
||||
},
|
||||
'traffic': {
|
||||
'forward': {'packets': 0, 'bytes': 0},
|
||||
'mgmt_rx': {'packets': 0, 'bytes': 0},
|
||||
'mgmt_tx': {'packets': 0, 'bytes': 0},
|
||||
'rx': {'packets': 0, 'bytes': 0},
|
||||
'tx': {'packets': 0, 'bytes': 0, 'dropped': 0}
|
||||
}
|
||||
},
|
||||
'statistics': {
|
||||
'clients': 0,
|
||||
'gateway': '',
|
||||
'memory_usage': 0,
|
||||
'rootfs_usage': 0,
|
||||
'uptime': 0
|
||||
}
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
'nodes': nodes,
|
||||
'timestamp': datetime.now().replace(microsecond=0).isoformat(),
|
||||
'version': 2
|
||||
})
|
||||
|
||||
if __name__ == '__main__':
|
||||
netglass.run(debug=False, port=8080)
|
2
netglass/requirements.txt
Normal file
2
netglass/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
flask
|
||||
pynetbox
|
44
nginx.conf
Normal file
44
nginx.conf
Normal file
@ -0,0 +1,44 @@
|
||||
upstream netglass {
|
||||
server 127.0.0.1:8080;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
|
||||
# SSL configuration
|
||||
#
|
||||
# listen 443 ssl default_server;
|
||||
# listen [::]:443 ssl default_server;
|
||||
#
|
||||
# Note: You should disable gzip for SSL traffic.
|
||||
# See: https://bugs.debian.org/773332
|
||||
#
|
||||
# Read up on ssl_ciphers to ensure a secure configuration.
|
||||
# See: https://bugs.debian.org/765782
|
||||
#
|
||||
# Self signed certs generated by the ssl-cert package
|
||||
# Don't use them in a production server!
|
||||
#
|
||||
# include snippets/snakeoil.conf;
|
||||
|
||||
root /hopglass;
|
||||
|
||||
location /data/ {
|
||||
rewrite /data/(.*) /$1 break;
|
||||
proxy_pass http://netglass;
|
||||
proxy_redirect off;
|
||||
proxy_set_header Host $host;
|
||||
}
|
||||
|
||||
# Add index.php to the list if you are using PHP
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
# First attempt to serve request as file, then
|
||||
# as directory, then fall back to displaying a 404.
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user