diff --git a/py-dashboard/GhostRequest.py b/py-dashboard/GhostRequest.py index a8a10219..5aa483aa 100644 --- a/py-dashboard/GhostRequest.py +++ b/py-dashboard/GhostRequest.py @@ -1,8 +1,10 @@ #!/usr/bin/env python3 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Class holds default settings for json requests to Grafana - +# Class holds default settings for json requests to Ghost - # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +import ast +import os import sys if sys.version_info[0] != 3: @@ -13,25 +15,69 @@ import requests import jwt from datetime import datetime as date +import json +import subprocess +from scp import SCPClient +import paramiko + + +class CSVReader: + def read_csv(self, + file, + sep=','): + csv = open(file).read().split('\n') + rows = list() + for x in csv: + if len(x) > 0: + rows.append(x.split(sep)) + length = list(range(0, len(df[0]))) + columns = dict(zip(df[0], length)) + return rows + + def get_column(df, value): + index = df[0].index(value) + values = [] + for row in df[1:]: + values.append(row[index]) + return values class GhostRequest: def __init__(self, - _ghostjson_host, - _ghostjson_port, + _ghost_json_host, + _ghost_json_port, _api_token=None, - _headers=dict(), _overwrite='false', debug_=False, die_on_error_=False): self.debug = debug_ self.die_on_error = die_on_error_ - self.ghostjson_url = "http://%s:%s/ghost/api/v3" % (_ghostjson_host, _ghostjson_port) + self.ghost_json_host = _ghost_json_host + self.ghost_json_port = _ghost_json_port + self.ghost_json_url = "http://%s:%s/ghost/api/v3" % (_ghost_json_host, _ghost_json_port) self.data = dict() self.data['overwrite'] = _overwrite - self.ghostjson_login = self.ghostjson_url + '/admin/session/' + self.ghost_json_login = self.ghost_json_url + '/admin/session/' self.api_token = _api_token + self.images = list() + self.pdfs = list() + def encode_token(self): + + # Split the key into ID and SECRET + key_id, secret = self.api_token.split(':') + + # Prepare header and payload + iat = int(date.now().timestamp()) + + header = {'alg': 'HS256', 'typ': 'JWT', 'kid': key_id} + payload = { + 'iat': iat, + 'exp': iat + 5 * 60, + 'aud': '/v3/admin/' + } + token = jwt.encode(payload, bytes.fromhex(secret), algorithm='HS256', headers=header) + return token def create_post(self, title=None, @@ -39,15 +85,7 @@ class GhostRequest: tags=None, authors=None, status="published"): - ghostjson_url = self.ghostjson_url + '/admin/posts/' - datastore = dict() - datastore['title'] = title - if tags is not None: - datastore['tags'] = tags - if authors is not None: - datastore['authors'] = authors - datastore['html'] = text - datastore['status'] = status + ghost_json_url = self.ghost_json_url + '/admin/posts/?source=html' post = dict() posts = list() datastore = dict() @@ -59,18 +97,132 @@ class GhostRequest: headers = dict() - # Split the key into ID and SECRET - id, secret = self.api_token.split(':') - - # Prepare header and payload - iat = int(date.now().timestamp()) - - header = {'alg': 'HS256', 'typ': 'JWT', 'kid': id} - payload = { - 'iat': iat, - 'exp': iat + 5 * 60, - 'aud': '/v3/admin/' - } - token = jwt.encode(payload, bytes.fromhex(secret), algorithm='HS256', headers=header) + token = self.encode_token() headers['Authorization'] = 'Ghost {}'.format(token) - requests.post(ghostjson_url, json=post, headers=headers) + response = requests.post(ghost_json_url, json=post, headers=headers) + if self.debug: + print(datastore) + print(ghost_json_url) + print('\n') + print(post) + print('\n') + print(headers) + print(response.headers) + + def upload_image(self, + image): + print(image) + ghost_json_url = self.ghost_json_url + '/admin/images/upload/' + + token = self.encode_token() + bashCommand = "curl -X POST -F 'file=@%s' -H \"Authorization: Ghost %s\" %s" % (image, token, ghost_json_url) + + proc = subprocess.Popen(bashCommand, shell=True, stdout=subprocess.PIPE) + output = proc.stdout.read().decode('utf-8') + print(output) + self.images.append(json.loads(output)['images'][0]['url']) + + def upload_images(self, + folder): + for image in os.listdir(folder): + if 'kpi' in image: + if 'png' in image: + self.upload_image(folder + '/' + image) + print('images %s' % self.images) + + def custom_post(self, + folder, + authors, + title='custom'): + self.upload_images(folder) + head = '''

This is a custom post created via a script

''' + for picture in self.images: + head = head + '' % picture + head = head + '''

This is the end of the example

''' + self.create_post(title=title, + text=head, + tags='custom', + authors=authors) + + def wifi_capacity_to_ghost(self, + authors, + folders, + title='Wifi Capacity', + server_pull=None, + ghost_host=None, + port='22', + user_pull='lanforge', + password_pull='lanforge', + user_push=None, + password_push=None, + customer=None, + testbed=None, + test_run=None): + text = '''The Candela WiFi Capacity test is designed to measure performance of an Access Point when handling + different amounts of WiFi Stations. The test allows the user to increase the number of stations in user + defined steps for each test iteration and measure the per station and the overall throughput for each trial. + Along with throughput other measurements made are client connection times, Fairness, % packet loss, + DHCP times and more. The expected behavior is for the AP to be able to handle several stations (within the + limitations of the AP specs) and make sure all stations get a fair amount of airtime both in the upstream and + downstream. An AP that scales well will not show a significant over-all throughput decrease as more stations + are added. + Realtime Graph shows summary download and upload RX bps of connections created by this test.
''' + + if test_run is None: + test_run = sorted(folders)[0].split('/')[-1] + for folder in folders: + ssh_pull = paramiko.SSHClient() + ssh_pull.set_missing_host_key_policy(paramiko.client.AutoAddPolicy) + ssh_pull.connect(server_pull, + port, + username=user_pull, + password=password_pull, + allow_agent=False, + look_for_keys=False) + scp_pull = SCPClient(ssh_pull.get_transport()) + scp_pull.get(folder, recursive=True) + ssh_push = paramiko.SSHClient() + ssh_push.set_missing_host_key_policy(paramiko.client.AutoAddPolicy) + ssh_push.connect(ghost_host, + port, + username=user_push, + password=password_push, + allow_agent=False, + look_for_keys=False) + scp_push = SCPClient(ssh_push.get_transport()) + local_path = '/home/%s/%s/%s/%s' % (user_push, customer, testbed, test_run) + transport = paramiko.Transport((ghost_host, port)) + transport.connect(None, user_push, password_push) + sftp = paramiko.sftp_client.SFTPClient.from_transport(transport) + print(local_path) + sftp.mkdir(local_path) + target_folder = folder.split('/')[-1] + print(target_folder) + scp_push.put(target_folder, recursive=True, remote_path=local_path) + files = sftp.listdir(local_path + '/' + target_folder) + print('Files: %s' % files) + for file in files: + if 'pdf' in file: + self.pdfs.append(file) + + #df = CSVReader.read_csv(local_path + '/' + target_folder + '/' + 'kpi.csv') + #testbed = CSVReader.get_column(df, 'test-rig')[0] + + print('PDFs %s' % self.pdfs) + scp_pull.close() + scp_push.close() + 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: %s' % (url, url) + + for image in self.images: + if 'kpi-' in image: + if '-print' not in image: + text = text + '' % image + + self.create_post(title=title, + text=text, + tags='custom', + authors=authors) diff --git a/py-scripts/ghost_profile.py b/py-scripts/ghost_profile.py index 996dd82b..824eab1c 100755 --- a/py-scripts/ghost_profile.py +++ b/py-scripts/ghost_profile.py @@ -6,6 +6,14 @@ PURPOSE: modify ghost database from the command line. SETUP: A Ghost installation which the user has admin access to. EXAMPLE: ./ghost_profile.py --article_text_file text.txt --title Test --authors Matthew --ghost_token SECRET_KEY --host 192.168.1.1 +There is a specific class for uploading wifi capacity graphs called wifi_capacity. + +EXAMPLE: ./ghost_profile.py --ghost_token TOKEN --ghost_host 192.168.100.147 +--folders /home/lanforge/html-reports/wifi-capacity-2021-06-04-02-51-07 +--wifi_capacity appl --authors Matthew --title 'wifi capacity 2021 06 04 02 51 07' --server 192.168.93.51 +--user_pull lanforge --password_pull lanforge --customer candela --testbed heather --test_run test-run-6 +--user_push matt --password_push PASSWORD + Matthew Stidham Copyright 2021 Candela Technologies Inc License: Free to distribute and modify. LANforge systems must be licensed. @@ -23,9 +31,9 @@ if 'py-json' not in sys.path: sys.path.append(os.path.join(os.path.abspath('..'), 'py-dashboard')) from GhostRequest import GhostRequest -from LANforge.lfcli_base import LFCliBase -class UseGhost(LFCliBase): + +class UseGhost(): def __init__(self, _ghost_token=None, host="localhost", @@ -34,11 +42,13 @@ class UseGhost(LFCliBase): _exit_on_fail=False, _ghost_host="localhost", _ghost_port=2368, ): - super().__init__(host, port, _debug=_debug_on, _exit_on_fail=_exit_on_fail) self.ghost_host = _ghost_host self.ghost_port = _ghost_port self.ghost_token = _ghost_token - self.GP = GhostRequest(self.ghost_host, str(self.ghost_port), _api_token=self.ghost_token) + self.GP = GhostRequest(self.ghost_host, + str(self.ghost_port), + _api_token=self.ghost_token, + debug_=_debug_on) def create_post(self, title, text, tags, authors): return self.GP.create_post(title=title, text=text, tags=tags, authors=authors) @@ -47,9 +57,46 @@ class UseGhost(LFCliBase): text = open(file).read() return self.GP.create_post(title=title, text=text, tags=tags, authors=authors) + def upload_image(self, image): + return self.GP.upload_image(image) + + def upload_images(self, folder): + return self.GP.upload_images(folder) + + def custom_post(self, folder, authors): + return self.GP.custom_post(folder, authors) + + def wifi_capacity(self, + authors, + folders, + title, + server_pull, + ghost_host, + port, + user_pull, + password_pull, + user_push, + password_push, + customer, + testbed, + test_run): + return self.GP.wifi_capacity_to_ghost(authors, + folders, + title, + server_pull, + ghost_host, + port, + user_pull, + password_pull, + user_push, + password_push, + customer, + testbed, + test_run) + def main(): - parser = LFCliBase.create_basic_argparse( + parser = argparse.ArgumentParser( prog='ghost_profile.py', formatter_class=argparse.RawTextHelpFormatter, epilog='''Manage Ghost Website''', @@ -71,17 +118,60 @@ def main(): optional.add_argument('--article_tags', action='append') optional.add_argument('--authors', action='append') optional.add_argument('--title', default=None) + optional.add_argument('--image', default=None) + optional.add_argument('--folder', default=None) + optional.add_argument('--custom_post', default=None) + optional.add_argument('--wifi_capacity', default=None) + optional.add_argument('--folders', action='append', default=None) + optional.add_argument('--server_pull') + optional.add_argument('--port', default=22) + optional.add_argument('--user_pull', default='lanforge') + optional.add_argument('--password_pull', default='lanforge') + optional.add_argument('--user_push') + optional.add_argument('--password_push') + optional.add_argument('--customer') + optional.add_argument('--testbed') + optional.add_argument('--test_run', default=None) + optional.add_argument('--debug') args = parser.parse_args() Ghost = UseGhost(_ghost_token=args.ghost_token, _ghost_port=args.ghost_port, - _ghost_host=args.ghost_host) + _ghost_host=args.ghost_host, + _debug_on=args.debug) if args.create_post is not None: Ghost.create_post(args.title, args.article_text, args.article_tags, args.authors) if args.article_text_file is not None: Ghost.create_post_from_file(args.title, args.article_text_file, args.article_tags, args.authors) + if args.image is not None: + Ghost.upload_image(args.image) + + if args.custom_post is not None: + if args.folders is not None: + Ghost.custom_post(args.folders, args.authors) + else: + Ghost.custom_post(args.folder, args.authors) + else: + if args.folder is not None: + Ghost.upload_images(args.folder) + + if args.wifi_capacity is not None: + Ghost.wifi_capacity(args.authors, + args.folders, + args.title, + args.server_pull, + args.ghost_host, + args.port, + args.user_pull, + args.password_pull, + args.user_push, + args.password_push, + args.customer, + args.testbed, + args.test_run) + if __name__ == "__main__": main()