mirror of
https://github.com/Telecominfraproject/wlan-lanforge-scripts.git
synced 2025-10-31 18:58:01 +00:00
Improving wifi capacity to ghost function
Signed-off-by: Matthew Stidham <stidmatt@gmail.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
#!/usr/bin/env python3
|
#!/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
|
import sys
|
||||||
|
|
||||||
if sys.version_info[0] != 3:
|
if sys.version_info[0] != 3:
|
||||||
@@ -13,25 +15,69 @@ import requests
|
|||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
from datetime import datetime as date
|
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:
|
class GhostRequest:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
_ghostjson_host,
|
_ghost_json_host,
|
||||||
_ghostjson_port,
|
_ghost_json_port,
|
||||||
_api_token=None,
|
_api_token=None,
|
||||||
_headers=dict(),
|
|
||||||
_overwrite='false',
|
_overwrite='false',
|
||||||
debug_=False,
|
debug_=False,
|
||||||
die_on_error_=False):
|
die_on_error_=False):
|
||||||
self.debug = debug_
|
self.debug = debug_
|
||||||
self.die_on_error = die_on_error_
|
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 = dict()
|
||||||
self.data['overwrite'] = _overwrite
|
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.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,
|
def create_post(self,
|
||||||
title=None,
|
title=None,
|
||||||
@@ -39,15 +85,7 @@ class GhostRequest:
|
|||||||
tags=None,
|
tags=None,
|
||||||
authors=None,
|
authors=None,
|
||||||
status="published"):
|
status="published"):
|
||||||
ghostjson_url = self.ghostjson_url + '/admin/posts/'
|
ghost_json_url = self.ghost_json_url + '/admin/posts/?source=html'
|
||||||
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
|
|
||||||
post = dict()
|
post = dict()
|
||||||
posts = list()
|
posts = list()
|
||||||
datastore = dict()
|
datastore = dict()
|
||||||
@@ -59,18 +97,132 @@ class GhostRequest:
|
|||||||
|
|
||||||
headers = dict()
|
headers = dict()
|
||||||
|
|
||||||
# Split the key into ID and SECRET
|
token = self.encode_token()
|
||||||
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)
|
|
||||||
headers['Authorization'] = 'Ghost {}'.format(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 = '''<p>This is a custom post created via a script</p>'''
|
||||||
|
for picture in self.images:
|
||||||
|
head = head + '<img src="%s"></img>' % picture
|
||||||
|
head = head + '''<p>This is the end of the example</p>'''
|
||||||
|
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.<br />'''
|
||||||
|
|
||||||
|
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: <a href="%s">%s</a>' % (url, url)
|
||||||
|
|
||||||
|
for image in self.images:
|
||||||
|
if 'kpi-' in image:
|
||||||
|
if '-print' not in image:
|
||||||
|
text = text + '<img src="%s"></img>' % image
|
||||||
|
|
||||||
|
self.create_post(title=title,
|
||||||
|
text=text,
|
||||||
|
tags='custom',
|
||||||
|
authors=authors)
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ PURPOSE: modify ghost database from the command line.
|
|||||||
SETUP: A Ghost installation which the user has admin access to.
|
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
|
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
|
Matthew Stidham
|
||||||
Copyright 2021 Candela Technologies Inc
|
Copyright 2021 Candela Technologies Inc
|
||||||
License: Free to distribute and modify. LANforge systems must be licensed.
|
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'))
|
sys.path.append(os.path.join(os.path.abspath('..'), 'py-dashboard'))
|
||||||
|
|
||||||
from GhostRequest import GhostRequest
|
from GhostRequest import GhostRequest
|
||||||
from LANforge.lfcli_base import LFCliBase
|
|
||||||
|
|
||||||
class UseGhost(LFCliBase):
|
|
||||||
|
class UseGhost():
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
_ghost_token=None,
|
_ghost_token=None,
|
||||||
host="localhost",
|
host="localhost",
|
||||||
@@ -34,11 +42,13 @@ class UseGhost(LFCliBase):
|
|||||||
_exit_on_fail=False,
|
_exit_on_fail=False,
|
||||||
_ghost_host="localhost",
|
_ghost_host="localhost",
|
||||||
_ghost_port=2368, ):
|
_ghost_port=2368, ):
|
||||||
super().__init__(host, port, _debug=_debug_on, _exit_on_fail=_exit_on_fail)
|
|
||||||
self.ghost_host = _ghost_host
|
self.ghost_host = _ghost_host
|
||||||
self.ghost_port = _ghost_port
|
self.ghost_port = _ghost_port
|
||||||
self.ghost_token = _ghost_token
|
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):
|
def create_post(self, title, text, tags, authors):
|
||||||
return self.GP.create_post(title=title, text=text, tags=tags, authors=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()
|
text = open(file).read()
|
||||||
return self.GP.create_post(title=title, text=text, tags=tags, authors=authors)
|
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():
|
def main():
|
||||||
parser = LFCliBase.create_basic_argparse(
|
parser = argparse.ArgumentParser(
|
||||||
prog='ghost_profile.py',
|
prog='ghost_profile.py',
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
epilog='''Manage Ghost Website''',
|
epilog='''Manage Ghost Website''',
|
||||||
@@ -71,17 +118,60 @@ def main():
|
|||||||
optional.add_argument('--article_tags', action='append')
|
optional.add_argument('--article_tags', action='append')
|
||||||
optional.add_argument('--authors', action='append')
|
optional.add_argument('--authors', action='append')
|
||||||
optional.add_argument('--title', default=None)
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
Ghost = UseGhost(_ghost_token=args.ghost_token,
|
Ghost = UseGhost(_ghost_token=args.ghost_token,
|
||||||
_ghost_port=args.ghost_port,
|
_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:
|
if args.create_post is not None:
|
||||||
Ghost.create_post(args.title, args.article_text, args.article_tags, args.authors)
|
Ghost.create_post(args.title, args.article_text, args.article_tags, args.authors)
|
||||||
if args.article_text_file is not None:
|
if args.article_text_file is not None:
|
||||||
Ghost.create_post_from_file(args.title, args.article_text_file, args.article_tags, args.authors)
|
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__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user