Include embedded dashboard in ghost page

Signed-off-by: Matthew Stidham <stidmatt@gmail.com>
This commit is contained in:
Matthew Stidham
2021-06-15 15:56:17 -07:00
parent 76a1b7f09b
commit 5b1c188ac2
4 changed files with 165 additions and 81 deletions

View File

@@ -19,22 +19,25 @@ import json
import subprocess import subprocess
from scp import SCPClient from scp import SCPClient
import paramiko import paramiko
from GrafanaRequest import GrafanaRequest
class CSVReader: class CSVReader:
def read_csv(self, def read_csv(self,
file, file,
sep=','): sep=','):
csv = open(file).read().split('\n') df = open(file).read().split('\n')
rows = list() rows = list()
for x in csv: for x in df:
if len(x) > 0: if len(x) > 0:
rows.append(x.split(sep)) rows.append(x.split(sep))
length = list(range(0, len(df[0]))) length = list(range(0, len(df[0])))
columns = dict(zip(df[0], length)) columns = dict(zip(df[0], length))
return rows return rows
def get_column(df, value): def get_column(self,
df,
value):
index = df[0].index(value) index = df[0].index(value)
values = [] values = []
for row in df[1:]: for row in df[1:]:
@@ -147,7 +150,7 @@ class GhostRequest:
def wifi_capacity_to_ghost(self, def wifi_capacity_to_ghost(self,
authors, authors,
folders, folders,
title='Wifi Capacity', title=None,
server_pull=None, server_pull=None,
ghost_host=None, ghost_host=None,
port='22', port='22',
@@ -156,21 +159,19 @@ class GhostRequest:
user_push=None, user_push=None,
password_push=None, password_push=None,
customer=None, customer=None,
testbed=None, testbed='Unknown Testbed',
test_run=None): test_run=None,
text = '''The Candela WiFi Capacity test is designed to measure performance of an Access Point when handling target_folders=list(),
different amounts of WiFi Stations. The test allows the user to increase the number of stations in user grafana_dashboard=None,
defined steps for each test iteration and measure the per station and the overall throughput for each trial. grafana_token=None,
Along with throughput other measurements made are client connection times, Fairness, % packet loss, grafana_host=None,
DHCP times and more. The expected behavior is for the AP to be able to handle several stations (within the grafana_port=3000):
limitations of the AP specs) and make sure all stations get a fair amount of airtime both in the upstream and text = ''
downstream. An AP that scales well will not show a significant over-all throughput decrease as more stations csvreader = CSVReader()
are added.
Realtime Graph shows summary download and upload RX bps of connections created by this test.<br />'''
if test_run is None: if test_run is None:
test_run = sorted(folders)[0].split('/')[-1] test_run = sorted(folders)[0].split('/')[-1].strip('/')
for folder in folders: for folder in folders:
print(folder)
ssh_pull = paramiko.SSHClient() ssh_pull = paramiko.SSHClient()
ssh_pull.set_missing_host_key_policy(paramiko.client.AutoAddPolicy) ssh_pull.set_missing_host_key_policy(paramiko.client.AutoAddPolicy)
ssh_pull.connect(server_pull, ssh_pull.connect(server_pull,
@@ -181,6 +182,24 @@ class GhostRequest:
look_for_keys=False) look_for_keys=False)
scp_pull = SCPClient(ssh_pull.get_transport()) scp_pull = SCPClient(ssh_pull.get_transport())
scp_pull.get(folder, recursive=True) scp_pull.get(folder, recursive=True)
target_folder = str(folder).rstrip('/').split('/')[-1]
target_folders.append(target_folder)
print(target_folder)
try:
target_file = '%s/kpi.csv' % target_folder
print('target file %s' % target_file)
df = csvreader.read_csv(file=target_file, sep='\t')
csv_testbed = csvreader.get_column(df, 'test-rig')[0]
print(csv_testbed)
except:
pass
if len(csv_testbed) > 2:
testbed = csv_testbed
text = text + 'Testbed: %s<br />' % testbed
if testbed == 'Unknown Testbed':
raise UserWarning('Please define your testbed')
print('testbed %s' % testbed)
ssh_push = paramiko.SSHClient() ssh_push = paramiko.SSHClient()
ssh_push.set_missing_host_key_policy(paramiko.client.AutoAddPolicy) ssh_push.set_missing_host_key_policy(paramiko.client.AutoAddPolicy)
ssh_push.connect(ghost_host, ssh_push.connect(ghost_host,
@@ -195,32 +214,44 @@ class GhostRequest:
transport.connect(None, user_push, password_push) transport.connect(None, user_push, password_push)
sftp = paramiko.sftp_client.SFTPClient.from_transport(transport) sftp = paramiko.sftp_client.SFTPClient.from_transport(transport)
print(local_path) print(local_path)
try:
sftp.mkdir(local_path) sftp.mkdir(local_path)
target_folder = folder.split('/')[-1] except:
print(target_folder) print('folder %s already exists' % local_path)
scp_push.put(target_folder, recursive=True, remote_path=local_path) scp_push.put(target_folder, recursive=True, remote_path=local_path)
files = sftp.listdir(local_path + '/' + target_folder) files = sftp.listdir(local_path + '/' + target_folder)
print('Files: %s' % files) # print('Files: %s' % files)
for file in files: for file in files:
if 'pdf' in file: if 'pdf' in file:
self.pdfs.append(file) url = 'http://%s/%s/%s/%s/%s/%s' % (
ghost_host, customer.strip('/'), testbed, test_run, target_folder, file)
#df = CSVReader.read_csv(local_path + '/' + target_folder + '/' + 'kpi.csv') text = text + 'PDF of results: <a href="%s">%s</a><br />' % (url, file)
#testbed = CSVReader.get_column(df, 'test-rig')[0] print(url)
print('PDFs %s' % self.pdfs)
scp_pull.close() scp_pull.close()
scp_push.close() scp_push.close()
self.upload_images(target_folder) self.upload_images(target_folder)
for pdf in self.pdfs:
url = 'http://%s/%s/%s/%s/%s/%s' % (ghost_host, customer, testbed, test_run, target_folder, pdf)
text = text + 'PDF of results: <a href="%s">%s</a>' % (url, url)
for image in self.images: for image in self.images:
if 'kpi-' in image: if 'kpi-' in image:
if '-print' not in image: if '-print' not in image:
text = text + '<img src="%s"></img>' % image text = text + '<img src="%s"></img>' % image
self.images = []
if grafana_token is not None:
GR = GrafanaRequest(grafana_token,
grafana_host,
grafanajson_port=grafana_port
)
GR.create_snapshot(title=grafana_dashboard)
snapshot = GR.list_snapshots()[-1]
text = text + '<iframe src="%s" width="100%s" height=500></iframe>' % (snapshot['externalUrl'], '%')
now = date.now()
if title is None:
title = "%s %s %s %s:%s report" % (now.day, now.month, now.year, now.hour, now.minute)
if grafana_dashboard is not None:
pass
self.create_post(title=title, self.create_post(title=title,
text=text, text=text,

View File

@@ -16,10 +16,10 @@ import json
class GrafanaRequest: class GrafanaRequest:
def __init__(self, def __init__(self,
_grafana_token,
_grafanajson_host, _grafanajson_host,
_grafanajson_port, grafanajson_port=3000,
_folderID=0, _folderID=0,
_api_token=None,
_headers=dict(), _headers=dict(),
_overwrite='false', _overwrite='false',
debug_=False, debug_=False,
@@ -27,9 +27,12 @@ class GrafanaRequest:
self.debug = debug_ self.debug = debug_
self.die_on_error = die_on_error_ self.die_on_error = die_on_error_
self.headers = _headers self.headers = _headers
self.headers['Authorization'] = 'Bearer ' + _api_token self.headers['Authorization'] = 'Bearer ' + _grafana_token
self.headers['Content-Type'] = 'application/json' self.headers['Content-Type'] = 'application/json'
self.grafanajson_url = "http://%s:%s" % (_grafanajson_host, _grafanajson_port) self.grafanajson_host = _grafanajson_host
self.grafanajson_port = grafanajson_port
self.grafanajson_token = _grafana_token
self.grafanajson_url = "http://%s:%s" % (_grafanajson_host, grafanajson_port)
self.data = dict() self.data = dict()
self.data['overwrite'] = _overwrite self.data['overwrite'] = _overwrite
@@ -40,13 +43,14 @@ class GrafanaRequest:
pass pass
def list_dashboards(self): def list_dashboards(self):
url = self.grafanajson_url + '/api/search?folderIds=0&query=&starred=false' url = self.grafanajson_url + '/api/search'
return requests.get(url).text print(url)
return json.loads(requests.get(url,headers=self.headers).text)
def create_dashboard(self, def create_dashboard(self,
dashboard_name=None, dashboard_name=None,
): ):
self.grafanajson_url = self.grafanajson_url + "/api/dashboards/db" grafanajson_url = self.grafanajson_url + "/api/dashboards/db"
datastore = dict() datastore = dict()
dashboard = dict() dashboard = dict()
dashboard['id'] = None dashboard['id'] = None
@@ -58,37 +62,59 @@ class GrafanaRequest:
datastore['dashboard'] = dashboard datastore['dashboard'] = dashboard
datastore['overwrite'] = False datastore['overwrite'] = False
data = json.dumps(datastore, indent=4) data = json.dumps(datastore, indent=4)
return requests.post(self.grafanajson_url, headers=self.headers, data=data, verify=False) return requests.post(grafanajson_url, headers=self.headers, data=data, verify=False)
def delete_dashboard(self, def delete_dashboard(self,
dashboard_uid=None): dashboard_uid=None):
self.grafanajson_url = self.grafanajson_url + "/api/dashboards/uid/" + dashboard_uid grafanajson_url = self.grafanajson_url + "/api/dashboards/uid/" + dashboard_uid
return requests.post(self.grafanajson_url, headers=self.headers, verify=False) return requests.post(grafanajson_url, headers=self.headers, verify=False)
def create_dashboard_from_data(self, def create_dashboard_from_data(self,
json_file=None): json_file=None):
self.grafanajson_url = self.grafanajson_url + '/api/dashboards/db' grafanajson_url = self.grafanajson_url + '/api/dashboards/db'
datastore = dict() datastore = dict()
dashboard = dict(json.loads(open(json_file).read())) dashboard = dict(json.loads(open(json_file).read()))
datastore['dashboard'] = dashboard datastore['dashboard'] = dashboard
datastore['overwrite'] = False datastore['overwrite'] = False
data = json.dumps(datastore, indent=4) data = json.dumps(datastore, indent=4)
#return print(data) #return print(data)
return requests.post(self.grafanajson_url, headers=self.headers, data=data, verify=False) return requests.post(grafanajson_url, headers=self.headers, data=data, verify=False)
def create_dashboard_from_dict(self, def create_dashboard_from_dict(self,
dictionary=None): dictionary=None):
self.grafanajson_url = self.grafanajson_url + '/api/dashboards/db' grafanajson_url = self.grafanajson_url + '/api/dashboards/db'
datastore = dict() datastore = dict()
dashboard = dict(json.loads(dictionary)) dashboard = dict(json.loads(dictionary))
datastore['dashboard'] = dashboard datastore['dashboard'] = dashboard
datastore['overwrite'] = False datastore['overwrite'] = False
data = json.dumps(datastore, indent=4) data = json.dumps(datastore, indent=4)
#return print(data) #return print(data)
return requests.post(self.grafanajson_url, headers=self.headers, data=data, verify=False) return requests.post(grafanajson_url, headers=self.headers, data=data, verify=False)
def create_custom_dashboard(self, def create_custom_dashboard(self,
datastore=None): datastore=None):
data = json.dumps(datastore, indent=4) data = json.dumps(datastore, indent=4)
return requests.post(self.grafanajson_url, headers=self.headers, data=data, verify=False) return requests.post(self.grafanajson_url, headers=self.headers, data=data, verify=False)
def create_snapshot(self, title):
grafanajson_url = self.grafanajson_url + '/api/snapshots'
data=self.get_dashboard(title)
data['expires'] = 3600
data['external'] = True
print(data)
return requests.post(grafanajson_url, headers=self.headers, json=data, verify=False).text
def list_snapshots(self):
grafanajson_url = self.grafanajson_url + '/api/dashboard/snapshots'
print(grafanajson_url)
return json.loads(requests.get(grafanajson_url, headers=self.headers, verify=False).text)
def get_dashboard(self, target):
dashboards = self.list_dashboards()
for dashboard in dashboards:
if dashboard['title'] == target:
uid = dashboard['uid']
grafanajson_url = self.grafanajson_url + '/api/dashboards/uid/' + uid
print(grafanajson_url)
return json.loads(requests.get(grafanajson_url, headers=self.headers, verify=False).text)

View File

@@ -33,7 +33,7 @@ if 'py-json' not in sys.path:
from GhostRequest import GhostRequest from GhostRequest import GhostRequest
class UseGhost(): class UseGhost:
def __init__(self, def __init__(self,
_ghost_token=None, _ghost_token=None,
host="localhost", host="localhost",
@@ -79,7 +79,12 @@ class UseGhost():
password_push, password_push,
customer, customer,
testbed, testbed,
test_run): test_run,
grafana_dashboard,
grafana_token,
grafana_host,
grafana_port):
target_folders = list()
return self.GP.wifi_capacity_to_ghost(authors, return self.GP.wifi_capacity_to_ghost(authors,
folders, folders,
title, title,
@@ -92,7 +97,12 @@ class UseGhost():
password_push, password_push,
customer, customer,
testbed, testbed,
test_run) test_run,
target_folders,
grafana_dashboard,
grafana_token,
grafana_host,
grafana_port)
def main(): def main():
@@ -132,6 +142,10 @@ def main():
optional.add_argument('--customer') optional.add_argument('--customer')
optional.add_argument('--testbed') optional.add_argument('--testbed')
optional.add_argument('--test_run', default=None) optional.add_argument('--test_run', default=None)
optional.add_argument('--grafana_dashboard')
optional.add_argument('--grafana_token', default=None)
optional.add_argument('--grafana_host', default=None)
optional.add_argument('--grafana_port', default=3000)
optional.add_argument('--debug') optional.add_argument('--debug')
args = parser.parse_args() args = parser.parse_args()
@@ -170,7 +184,11 @@ def main():
args.password_push, args.password_push,
args.customer, args.customer,
args.testbed, args.testbed,
args.test_run) args.test_run,
args.grafana_dashboard,
args.grafana_token,
args.grafana_host,
args.grafana_port)
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -24,36 +24,37 @@ import string
import random import random
class UseGrafana(LFCliBase): #!/usr/bin/env python3
def __init__(self,
_grafana_token,
host="localhost",
_grafana_host="localhost",
port=8080,
_debug_on=False,
_exit_on_fail=False,
_grafana_port=3000):
super().__init__(host, port, _debug=_debug_on, _exit_on_fail=_exit_on_fail)
self.grafana_token = _grafana_token
self.grafana_port = _grafana_port
self.grafana_host = _grafana_host
self.GR = GrafanaRequest(self.grafana_host, str(self.grafana_port), _folderID=0, _api_token=self.grafana_token)
def create_dashboard(self, # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
dashboard_name): # Class holds default settings for json requests to Grafana -
return self.GR.create_dashboard(dashboard_name) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
import sys
def delete_dashboard(self, if sys.version_info[0] != 3:
dashboard_uid): print("This script requires Python 3")
return self.GR.delete_dashboard(dashboard_uid) exit()
def list_dashboards(self): import requests
return self.GR.list_dashboards()
def create_dashboard_from_data(self, import json
json_file):
return self.GR.create_dashboard_from_data(json_file=json_file)
#!/usr/bin/env python3
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Class holds default settings for json requests to Grafana -
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
import sys
if sys.version_info[0] != 3:
print("This script requires Python 3")
exit()
import requests
import json
class UseGrafana(GrafanaRequest):
def groupby(self, params, grouptype): def groupby(self, params, grouptype):
dic = dict() dic = dict()
dic['params'] = list() dic['params'] = list()
@@ -301,7 +302,6 @@ class UseGrafana(LFCliBase):
return dict(zip(graph_group, units)) return dict(zip(graph_group, units))
def main(): def main():
parser = LFCliBase.create_basic_argparse( parser = LFCliBase.create_basic_argparse(
prog='grafana_profile.py', prog='grafana_profile.py',
@@ -353,11 +353,13 @@ def main():
optional.add_argument('--from_date', help='Date you want to start your Grafana dashboard from', default='now-1y') optional.add_argument('--from_date', help='Date you want to start your Grafana dashboard from', default='now-1y')
optional.add_argument('--graph_height', help='Custom height for the graph on grafana dashboard', default=8) optional.add_argument('--graph_height', help='Custom height for the graph on grafana dashboard', default=8)
optional.add_argument('--graph_width', help='Custom width for the graph on grafana dashboard', default=12) optional.add_argument('--graph_width', help='Custom width for the graph on grafana dashboard', default=12)
optional.add_argument('--create_snapshot', action='store_true')
optional.add_argument('--list_snapshots', action='store_true')
args = parser.parse_args() args = parser.parse_args()
Grafana = UseGrafana(args.grafana_token, Grafana = UseGrafana(args.grafana_token,
args.grafana_port, args.grafana_host,
args.grafana_host grafanajson_port=args.grafana_port
) )
if args.dashboard_name is not None: if args.dashboard_name is not None:
Grafana.create_dashboard(args.dashboard_name) Grafana.create_dashboard(args.dashboard_name)
@@ -386,6 +388,13 @@ def main():
graph_height=args.graph_height, graph_height=args.graph_height,
graph__width=args.graph_width) graph__width=args.graph_width)
if args.create_snapshot:
Grafana.create_snapshot(args.title)
if args.list_snapshots:
Grafana.list_snapshots()
if __name__ == "__main__": if __name__ == "__main__":
main() main()