mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2024-11-25 01:30:17 -06:00
221 lines
9.6 KiB
Python
221 lines
9.6 KiB
Python
import requests
|
|
import os
|
|
import csv
|
|
from ispConfig import uispSite, uispStrategy
|
|
from integrationCommon import isIpv4Permitted, fixSubnet
|
|
|
|
def uispRequest(target):
|
|
# Sends an HTTP request to UISP and returns the
|
|
# result in JSON. You only need to specify the
|
|
# tail end of the URL, e.g. "sites"
|
|
from ispConfig import UISPbaseURL, uispAuthToken
|
|
url = UISPbaseURL + "/nms/api/v2.1/" + target
|
|
headers = {'accept': 'application/json', 'x-auth-token': uispAuthToken}
|
|
r = requests.get(url, headers=headers, timeout=10)
|
|
return r.json()
|
|
|
|
def buildFlatGraph():
|
|
# Builds a high-performance (but lacking in site or AP bandwidth control)
|
|
# network.
|
|
from integrationCommon import NetworkGraph, NetworkNode, NodeType
|
|
from ispConfig import generatedPNUploadMbps, generatedPNDownloadMbps
|
|
|
|
# Load network sites
|
|
print("Loading Data from UISP")
|
|
sites = uispRequest("sites")
|
|
devices = uispRequest("devices?withInterfaces=true&authorized=true")
|
|
|
|
# Build a basic network adding every client to the tree
|
|
print("Building Flat Topology")
|
|
net = NetworkGraph()
|
|
|
|
for site in sites:
|
|
type = site['identification']['type']
|
|
if type == "endpoint":
|
|
id = site['identification']['id']
|
|
address = site['description']['address']
|
|
name = site['identification']['name']
|
|
type = site['identification']['type']
|
|
download = generatedPNDownloadMbps
|
|
upload = generatedPNUploadMbps
|
|
if (site['qos']['downloadSpeed']) and (site['qos']['uploadSpeed']):
|
|
download = int(round(site['qos']['downloadSpeed']/1000000))
|
|
upload = int(round(site['qos']['uploadSpeed']/1000000))
|
|
|
|
node = NetworkNode(id=id, displayName=name, type=NodeType.client, download=download, upload=upload, address=address)
|
|
net.addRawNode(node)
|
|
for device in devices:
|
|
if device['identification']['site'] is not None and device['identification']['site']['id'] == id:
|
|
# The device is at this site, so add it
|
|
ipv4 = []
|
|
ipv6 = []
|
|
|
|
for interface in device["interfaces"]:
|
|
for ip in interface["addresses"]:
|
|
ip = ip["cidr"]
|
|
if isIpv4Permitted(ip):
|
|
ip = fixSubnet(ip)
|
|
if ip not in ipv4:
|
|
ipv4.append(ip)
|
|
|
|
# TODO: Figure out Mikrotik IPv6?
|
|
mac = device['identification']['mac']
|
|
|
|
net.addRawNode(NetworkNode(id=device['identification']['id'], displayName=device['identification']
|
|
['name'], parentId=id, type=NodeType.device, ipv4=ipv4, ipv6=ipv6, mac=mac))
|
|
|
|
# Finish up
|
|
net.prepareTree()
|
|
net.plotNetworkGraph(False)
|
|
if net.doesNetworkJsonExist():
|
|
print("network.json already exists. Leaving in-place.")
|
|
else:
|
|
net.createNetworkJson()
|
|
net.createShapedDevices()
|
|
|
|
def buildFullGraph():
|
|
# Attempts to build a full network graph, incorporating as much of the UISP
|
|
# hierarchy as possible.
|
|
from integrationCommon import NetworkGraph, NetworkNode, NodeType
|
|
from ispConfig import generatedPNUploadMbps, generatedPNDownloadMbps
|
|
|
|
# Load network sites
|
|
print("Loading Data from UISP")
|
|
sites = uispRequest("sites")
|
|
devices = uispRequest("devices?withInterfaces=true&authorized=true")
|
|
dataLinks = uispRequest("data-links?siteLinksOnly=true")
|
|
|
|
# Do we already have a integrationUISPbandwidths.csv file?
|
|
siteBandwidth = {}
|
|
if os.path.isfile("integrationUISPbandwidths.csv"):
|
|
with open('integrationUISPbandwidths.csv') as csv_file:
|
|
csv_reader = csv.reader(csv_file, delimiter=',')
|
|
next(csv_reader)
|
|
for row in csv_reader:
|
|
name, download, upload = row
|
|
download = int(download)
|
|
upload = int(upload)
|
|
siteBandwidth[name] = {"download": download, "upload": upload}
|
|
|
|
# Find AP capacities from UISP
|
|
for device in devices:
|
|
if device['identification']['role'] == "ap":
|
|
name = device['identification']['name']
|
|
if not name in siteBandwidth and device['overview']['downlinkCapacity'] and device['overview']['uplinkCapacity']:
|
|
download = int(device['overview']
|
|
['downlinkCapacity'] / 1000000)
|
|
upload = int(device['overview']['uplinkCapacity'] / 1000000)
|
|
siteBandwidth[device['identification']['name']] = {
|
|
"download": download, "upload": upload}
|
|
|
|
print("Building Topology")
|
|
net = NetworkGraph()
|
|
# Add all sites and client sites
|
|
for site in sites:
|
|
id = site['identification']['id']
|
|
name = site['identification']['name']
|
|
type = site['identification']['type']
|
|
download = generatedPNDownloadMbps
|
|
upload = generatedPNUploadMbps
|
|
address = ""
|
|
if site['identification']['parent'] is None:
|
|
parent = ""
|
|
else:
|
|
parent = site['identification']['parent']['id']
|
|
match type:
|
|
case "site":
|
|
nodeType = NodeType.site
|
|
if name in siteBandwidth:
|
|
# Use the CSV bandwidth values
|
|
download = siteBandwidth[name]["download"]
|
|
upload = siteBandwidth[name]["upload"]
|
|
else:
|
|
# Add them just in case
|
|
siteBandwidth[name] = {
|
|
"download": download, "upload": upload}
|
|
case default:
|
|
nodeType = NodeType.client
|
|
address = site['description']['address']
|
|
if (site['qos']['downloadSpeed']) and (site['qos']['uploadSpeed']):
|
|
download = int(round(site['qos']['downloadSpeed']/1000000))
|
|
upload = int(round(site['qos']['uploadSpeed']/1000000))
|
|
|
|
node = NetworkNode(id=id, displayName=name, type=nodeType,
|
|
parentId=parent, download=download, upload=upload, address=address)
|
|
# If this is the uispSite node, it becomes the root. Otherwise, add it to the
|
|
# node soup.
|
|
if name == uispSite:
|
|
net.replaceRootNode(node)
|
|
else:
|
|
net.addRawNode(node)
|
|
|
|
for device in devices:
|
|
if device['identification']['site'] is not None and device['identification']['site']['id'] == id:
|
|
# The device is at this site, so add it
|
|
ipv4 = []
|
|
ipv6 = []
|
|
|
|
for interface in device["interfaces"]:
|
|
for ip in interface["addresses"]:
|
|
ip = ip["cidr"]
|
|
if isIpv4Permitted(ip):
|
|
ip = fixSubnet(ip)
|
|
if ip not in ipv4:
|
|
ipv4.append(ip)
|
|
|
|
# TODO: Figure out Mikrotik IPv6?
|
|
mac = device['identification']['mac']
|
|
|
|
net.addRawNode(NetworkNode(id=device['identification']['id'], displayName=device['identification']
|
|
['name'], parentId=id, type=NodeType.device, ipv4=ipv4, ipv6=ipv6, mac=mac))
|
|
|
|
# Now iterate access points, and look for connections to sites
|
|
for node in net.nodes:
|
|
if node.type == NodeType.device:
|
|
for dl in dataLinks:
|
|
if dl['from']['device'] is not None and dl['from']['device']['identification']['id'] == node.id:
|
|
if dl['to']['site'] is not None and dl['from']['site']['identification']['id'] != dl['to']['site']['identification']['id']:
|
|
target = net.findNodeIndexById(
|
|
dl['to']['site']['identification']['id'])
|
|
if target > -1:
|
|
# We found the site
|
|
if net.nodes[target].type == NodeType.client or net.nodes[target].type == NodeType.clientWithChildren:
|
|
net.nodes[target].parentId = node.id
|
|
node.type = NodeType.ap
|
|
if node.displayName in siteBandwidth:
|
|
# Use the bandwidth numbers from the CSV file
|
|
node.uploadMbps = siteBandwidth[node.displayName]["upload"]
|
|
node.downloadMbps = siteBandwidth[node.displayName]["download"]
|
|
else:
|
|
# Add some defaults in case they want to change them
|
|
siteBandwidth[node.displayName] = {
|
|
"download": generatedPNDownloadMbps, "upload": generatedPNUploadMbps}
|
|
|
|
net.prepareTree()
|
|
net.plotNetworkGraph(False)
|
|
if net.doesNetworkJsonExist():
|
|
print("network.json already exists. Leaving in-place.")
|
|
else:
|
|
net.createNetworkJson()
|
|
net.createShapedDevices()
|
|
|
|
# Save integrationUISPbandwidths.csv
|
|
# (the newLine fixes generating extra blank lines)
|
|
with open('integrationUISPbandwidths.csv', 'w', newline='') as csvfile:
|
|
wr = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
|
|
wr.writerow(['ParentNode', 'Download Mbps', 'Upload Mbps'])
|
|
for device in siteBandwidth:
|
|
entry = (
|
|
device, siteBandwidth[device]["download"], siteBandwidth[device]["upload"])
|
|
wr.writerow(entry)
|
|
|
|
|
|
def importFromUISP():
|
|
match uispStrategy:
|
|
case "full": buildFullGraph()
|
|
case default: buildFlatGraph()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
importFromUISP()
|