Compare commits

...

2 Commits

Author SHA1 Message Date
notplants a138b92f3a tests 2023-05-01 21:56:45 +05:30
notplants 1fb2a1d1c7 speedtests 2023-04-28 20:25:31 +05:30
9 changed files with 545 additions and 217 deletions

22
cowmesh_constants.py Normal file
View File

@ -0,0 +1,22 @@
NODES = [
"jaaga",
"redcottage",
"new-gazebo2",
"kotemanetp",
"guard",
"ddhills",
"bambino",
"thimmanayaka"
]
HOST_TO_IP = {
"jaaga": "10.56.121.19",
"redcottage": "10.56.58.194",
"redcottage2": "10.56.114.42",
"new-gazebo2": "10.56.114.42",
"new-gazebo": "10.56.113.2",
"guard": "10.56.121.73",
"kotemanetp": "10.56.40.113",
"thimmanayaka": "10.56.39.34",
"bambino": "10.56.0.102"
}

17
cowmesh_helpers.py Normal file
View File

@ -0,0 +1,17 @@
import paramiko
async def cleanup_iperf_server(node, ip, username, password, log):
await log("++ stopping iperf server on {}".format(node))
myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(ip, username=username, password=password)
remote_cmd = 'pgrep iperf | xargs kill'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
await log("{}".format(stdout.read()))
await log("{}".format(type(myconn)))
await log("Options available to deal with the connections are many like\n{}".format(dir(myconn)))
myconn.close()

View File

@ -11,6 +11,7 @@ import asyncio, asyncssh, sys
import paramiko import paramiko
import subprocess import subprocess
import json import json
from cowmesh_helpers import cleanup_iperf_server
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json") SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
@ -25,8 +26,6 @@ nodes = [
"writer", # pi in new-gazebo "writer", # pi in new-gazebo
] ]
results = {}
class CowmeshPiIperfTester: class CowmeshPiIperfTester:
@ -35,6 +34,7 @@ class CowmeshPiIperfTester:
self.log = log self.log = log
self.debug = debug self.debug = debug
self.time = time self.time = time
self.results = {}
async def log(self, msg): async def log(self, msg):
print(msg) print(msg)
@ -73,21 +73,35 @@ class CowmeshPiIperfTester:
async def start_iperf_servers(self): async def start_iperf_servers(self):
for node in nodes: for node in nodes:
print("++ starting iperf server on {}".format(node)) try:
print("++ starting iperf server on {}".format(node))
user = SECRETS["HOST_INFO"][node]["user"]
password = SECRETS["HOST_INFO"][node]["password"]
myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(node, username=user, password=password)
remote_cmd = 'iperf -s &'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
await self.debug_log("{}".format(stdout.read()))
await self.debug_log("{}".format(type(myconn)))
await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn)))
myconn.close()
except:
try:
self.log("++ error starting iperf server on {}".format(node))
except:
continue
async def cleanup_iperf_servers(self):
await self.log("++ shutting down iperf servers")
for node in nodes:
user = SECRETS["HOST_INFO"][node]["user"] user = SECRETS["HOST_INFO"][node]["user"]
password = SECRETS["HOST_INFO"][node]["password"] password = SECRETS["HOST_INFO"][node]["password"]
ip = SECRETS["HOST_INFO"][node]["ip"]
myconn = paramiko.SSHClient() await cleanup_iperf_server(node=node, ip=ip, username=user, password=password, log=self.log)
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(node, username=user, password=password)
remote_cmd = 'iperf -s &'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
await self.debug_log("{}".format(stdout.read()))
await self.debug_log("{}".format(type(myconn)))
await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn)))
myconn.close()
async def run_test(self): async def run_test(self):
@ -99,9 +113,17 @@ class CowmeshPiIperfTester:
await self.debug_log("skip self") await self.debug_log("skip self")
continue continue
r = await self.test_between_two_nodes(node_a, node_b)
result_key = "{} -> {}".format(node_a, node_b) result_key = "{} -> {}".format(node_a, node_b)
results[result_key] = r try:
r = await self.test_between_two_nodes(node_a, node_b)
self.results[result_key] = r
except Exception as e:
self.results[result_key] = "error: {}".format(e)
# try:
# await self.cleanup_iperf_servers()
# except:
# await self.log("error shutting down iperf servers")
async def output_results(self): async def output_results(self):
results_str = "" results_str = ""
@ -109,7 +131,7 @@ class CowmeshPiIperfTester:
date = now.date() date = now.date()
time = now.time() time = now.time()
results_str += "**** computer-to-computer iperf results on {date:%m-%d-%Y} at {time:%H:%M}:\n\n".format(date=date, time=time) results_str += "**** computer-to-computer iperf results on {date:%m-%d-%Y} at {time:%H:%M}:\n\n".format(date=date, time=time)
for test_name, result in results.items(): for test_name, result in self.results.items():
results_str += "{}: {} mbps\n".format(test_name, result) results_str += "{}: {} mbps\n".format(test_name, result)
await self.log(results_str) await self.log(results_str)

97
cowmesh_pi_speedtest.py Normal file
View File

@ -0,0 +1,97 @@
"""
run speedtest-cli on every computer in mesh
"""
import datetime
import os
import re
import time
import asyncio, asyncssh, sys
import paramiko
import subprocess
import json
from cowmesh_helpers import cleanup_iperf_server
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
with open(SECRETS_PATH, 'r') as f:
SECRETS = json.loads(f.read())
base_node = "janastunuc" # nuc in jaaga
nodes = [
"janastunuc", # nuc in jaaga
"solipi", # pi in guard
"writer", # pi in new-gazebo
]
class CowmeshPiSpeedtestTester:
def __init__(self, log=None, debug=False):
if log:
self.log = log
self.debug = debug
self.results = {}
async def log(self, msg):
print(msg)
async def debug_log(self, msg):
if self.debug:
await self.log(msg)
async def speedtest_node(self, node):
await self.log("++ running speedtest on {}".format(node))
user = SECRETS["HOST_INFO"][node]["user"]
password = SECRETS["HOST_INFO"][node]["password"]
myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ip = SECRETS["HOST_INFO"][node]["ip"]
myconn.connect(ip, username=user, password=password)
remote_cmd = 'speedtest-cli --simple'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
output = str(stdout.read())
await self.debug_log("output: {}".format(output))
await self.debug_log("errors: {}".format(stderr.read()))
myconn.close()
return output
async def run_test(self):
for node in nodes:
r = await self.speedtest_node(node)
result_key = "{}".format(node)
self.results[result_key] = r
async def output_results(self):
results_str = ""
now = datetime.datetime.now()
date = now.date()
time = now.time()
results_str += "**** computer speedtests on {date:%m-%d-%Y} at {time:%H:%M}:\n\n".format(date=date, time=time)
for test_name, result in self.results.items():
result = str(result)
result = result.replace("b'", "")
result = result.replace("'", "")
result = result.replace("\\n", " | ")
results_str += "{}: {}\n".format(test_name, result)
await self.log(results_str)
if __name__ == "__main__":
try:
tester = CowmeshPiSpeedtestTester()
async def main_fun():
await tester.run_test()
await tester.output_results()
asyncio.get_event_loop().run_until_complete(main_fun())
except (OSError, asyncssh.Error) as exc:
sys.exit('SSH connection failed: ' + str(exc))

View File

@ -11,40 +11,24 @@ import asyncio, asyncssh, sys
import paramiko import paramiko
import subprocess import subprocess
import json import json
from cowmesh_constants import NODES, HOST_TO_IP
from cowmesh_helpers import cleanup_iperf_server
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json") SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
with open(SECRETS_PATH, 'r') as f: with open(SECRETS_PATH, 'r') as f:
SECRETS = json.loads(f.read()) SECRETS = json.loads(f.read())
nodes = [
"jaaga",
"redcottage",
"new-gazebo2",
"kotemanetp",
"guard"
]
host_to_ip = {
"jaaga": "10.56.121.19",
"redcottage": "10.56.58.194",
"redcottage2": "10.56.114.42",
"new-gazebo2": "10.56.114.42",
"new-gazebo": "10.56.113.2",
"guard": "10.56.121.73",
"kotemanetp": "10.56.40.113"
}
results = {}
class CowmeshRouterIperfTester: class CowmeshRouterIperfTester:
def __init__(self, log=None, debug=False, seconds=10): def __init__(self, log=None, debug=False, time=10):
if log: if log:
self.log = log self.log = log
self.debug = debug self.debug = debug
self.time = seconds self.time = time
self.results = {}
async def log(self, msg): async def log(self, msg):
print(msg) print(msg)
@ -63,7 +47,7 @@ class CowmeshRouterIperfTester:
myconn.connect(node_a, username =u_name, password=pswd) myconn.connect(node_a, username =u_name, password=pswd)
ip = host_to_ip[node_b] ip = HOST_TO_IP[node_b]
remote_cmd = 'iperf -c {ip} -p 5001 -t {seconds}'.format(ip=ip, seconds=self.time) remote_cmd = 'iperf -c {ip} -p 5001 -t {seconds}'.format(ip=ip, seconds=self.time)
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd) (stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
@ -76,41 +60,73 @@ class CowmeshRouterIperfTester:
if match: if match:
to_return = match.group(1) to_return = match.group(1)
else: else:
to_return = None match = re.search("(\S+) Kbits", output)
if match:
to_return = match.group(1)
to_return = float(to_return) / 1000.0
else:
to_return = None
return to_return return to_return
async def start_iperf_servers(self): async def start_iperf_servers(self):
for node in nodes: for node in NODES:
print("++ starting iperf server on {}".format(node)) try:
u_name = 'root' print("++ starting iperf server on {}".format(node))
pswd = SECRETS["ROUTER_PASSWORD"] u_name = 'root'
pswd = SECRETS["ROUTER_PASSWORD"]
myconn = paramiko.SSHClient() myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy()) myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(node, username=u_name, password=pswd) myconn.connect(node, username=u_name, password=pswd)
remote_cmd = 'iperf -s &' remote_cmd = 'iperf -s &'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd) (stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
await self.debug_log("{}".format(stdout.read())) await self.debug_log("{}".format(stdout.read()))
await self.debug_log("{}".format(type(myconn))) await self.debug_log("{}".format(type(myconn)))
await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn))) await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn)))
myconn.close() myconn.close()
except:
try:
await self.log("++ error starting iperf server on {}".format(node))
except:
continue
async def cleanup_iperf_servers(self):
await self.log("shutting down iperf servers")
for node in NODES:
user = "root"
password = SECRETS["ROUTER_PASSWORD"]
ip = HOST_TO_IP[node]
await cleanup_iperf_server(node=node, ip=ip, username=user, password=password, log=self.log)
async def run_test(self): async def run_test(self):
await self.start_iperf_servers() try:
await self.start_iperf_servers()
except:
pass
for node_a in nodes: for node_a in NODES:
for node_b in nodes: for node_b in NODES:
if node_a == node_b: if node_a == node_b:
await self.debug_log("skip self") await self.debug_log("skip self")
continue continue
r = await self.test_between_two_nodes(node_a, node_b) try:
result_key = "{} -> {}".format(node_a, node_b) r = await self.test_between_two_nodes(node_a, node_b)
results[result_key] = r result_key = "{} -> {}".format(node_a, node_b)
self.results[result_key] = r
except Exception as e:
try:
await self.log("++ error running test between {} and {}: {}".format(node_a, node_b, e))
except:
continue
# try:
# await self.cleanup_iperf_servers()
# except:
# await self.log("error shutting down iperf servers")
async def output_results(self): async def output_results(self):
results_str = "" results_str = ""
@ -118,7 +134,7 @@ class CowmeshRouterIperfTester:
date = now.date() date = now.date()
time = now.time() time = now.time()
results_str += "**** iperf results on {date:%m-%d-%Y} at {time:%H:%M}:\n\n".format(date=date, time=time) results_str += "**** iperf results on {date:%m-%d-%Y} at {time:%H:%M}:\n\n".format(date=date, time=time)
for test_name, result in results.items(): for test_name, result in self.results.items():
results_str += "{}: {} mbps\n".format(test_name, result) results_str += "{}: {} mbps\n".format(test_name, result)
await self.log(results_str) await self.log(results_str)

View File

@ -7,29 +7,24 @@ import os
import time import time
import asyncio, asyncssh, sys import asyncio, asyncssh, sys
import subprocess import subprocess
import json
import paramiko
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
test_img_path = os.path.join(PROJECT_PATH, "test.png") test_img_path = os.path.join(PROJECT_PATH, "test.png")
SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
with open(SECRETS_PATH, 'r') as f:
SECRETS = json.loads(f.read())
base_node = "janastunuc" # nuc in jaaga
nodes = [
"janastunuc", # nuc in jaaga
"solipi", # pi in guard
"writer", # pi in new-gazebo
]
node_dict = {
"jagga-nuc": {
"ip": "10.56.10.247",
"user": "cow",
"node_path": "/datadrive/data/cowmesh-network-test"
},
"redcottage-pi": {
"ip": "10.56.148.122",
"user": "admin",
"node_path": "/home/admin/cowmesh-network-test"
},
"newgazebo-pi": {
"ip": "10.56.11.111",
"user": "pi",
"node_path": "/home/pi/cowmesh-network-test"
},
}
# url for downloading test.png from the internet # url for downloading test.png from the internet
internet_url = "https://canalswans.commoninternet.net/test.png" internet_url = "https://canalswans.commoninternet.net/test.png"
@ -44,12 +39,13 @@ if PREPARE_TEST:
os.system(internet_scp_cmd) os.system(internet_scp_cmd)
# first put the image on every node without testing the time (so that the test is prepared to run) # first put the image on every node without testing the time (so that the test is prepared to run)
for name, from_node_vals in node_dict.items(): for name, from_node_vals in SECRETS["HOST_INFO"].items():
print("PREPARING NODE {}".format(name)) print("PREPARING NODE {}".format(name))
ip = from_node_vals["ip"] ip = from_node_vals["ip"]
dir_path = from_node_vals["node_path"] dir_path = from_node_vals["node_path"]
file_path = os.path.join(dir_path, "test.png") file_path = os.path.join(dir_path, "test.png")
user = from_node_vals["user"] user = from_node_vals["user"]
password = from_node_vals["password"]
mkdir_cmd = "ssh {user}@{ip} 'mkdir -p {dir_path}'".format(user=user, ip=ip, dir_path=dir_path) mkdir_cmd = "ssh {user}@{ip} 'mkdir -p {dir_path}'".format(user=user, ip=ip, dir_path=dir_path)
os.system(mkdir_cmd) os.system(mkdir_cmd)
scp_cmd = "scp {test_img_path} {user}@{ip}:{file_path}".format( scp_cmd = "scp {test_img_path} {user}@{ip}:{file_path}".format(
@ -60,16 +56,43 @@ if PREPARE_TEST:
) )
os.system(scp_cmd) os.system(scp_cmd)
myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(ip, username=user, password=password)
remote_cmd = 'mkdir -p {dir_path}'.format(dir_path=dir_path)
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
output = str(stdout.read())
print("output: {}".format(output))
print(("errors: {}".format(stderr.read())))
scp_cmd = "scp {test_img_path} {user}@{ip}:{file_path}".format(
test_img_path=test_img_path,
ip=ip,
user=user,
file_path=file_path
)
(stdin, stdout, stderr) = myconn.exec_command(scp_cmd)
output = str(stdout.read())
print("output: {}".format(output))
print(("errors: {}".format(stderr.read())))
myconn.close()
results = {} results = {}
async def run_test(): async def run_test():
# run the test on each node # run the test on each node
for from_name, from_node_vals in node_dict.items(): node_dict = SECRETS["HOST_INFO"]
for node in nodes:
from_name = node
from_node_vals = node_dict[node]
from_ip = from_node_vals["ip"] from_ip = from_node_vals["ip"]
from_dir_path = from_node_vals["node_path"] from_dir_path = from_node_vals["node_path"]
from_file_path = os.path.join(from_dir_path, "test.png") from_file_path = os.path.join(from_dir_path, "test.png")
from_user = from_node_vals["user"] from_user = from_node_vals["user"]
for to_name, to_node_vals in node_dict.items(): from_password = from_node_vals["password"]
for to_name in nodes:
to_node_vals = node_dict[to_name]
if from_name == to_name: if from_name == to_name:
print("skip self") print("skip self")
continue continue
@ -80,35 +103,40 @@ async def run_test():
to_ip = to_node_vals["ip"] to_ip = to_node_vals["ip"]
to_dir_path = to_node_vals["node_path"] to_dir_path = to_node_vals["node_path"]
to_file_path = os.path.join(to_dir_path, "download.png") to_file_path = os.path.join(to_dir_path, "download.png")
to_password = to_node_vals["password"]
async with asyncssh.connect(from_ip, username=from_user) as conn: scp_cmd = "scp -i {key_path} {from_file_path} {to_user}@{to_ip}:{to_file_path}".format(
key_path="$HOME/.ssh/janastu",
to_user=to_user,
to_ip=to_ip,
to_file_path=to_file_path,
from_file_path=from_file_path
)
scp_cmd = "scp -i {key_path} {from_file_path} {to_user}@{to_ip}:{to_file_path}".format( start = time.time()
key_path="$HOME/.ssh/janastu",
to_user=to_user,
to_ip=to_ip,
to_file_path=to_file_path,
from_file_path=from_file_path
)
print(scp_cmd) myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(from_ip, username=from_user, password=from_password)
print(scp_cmd)
(stdin, stdout, stderr) = myconn.exec_command(scp_cmd)
exit_status = stdout.channel.recv_exit_status()
output = str(stdout.read())
error = str(stderr.read())
print("output: {}".format(output))
print(("errors: {}".format(stderr.read())))
start = time.time() result_key = "{} -> {}".format(from_name, to_name)
result = await conn.run(scp_cmd) if exit_status == 0:
print("success: {}".format(output))
if result.exit_status == 0: end = time.time()
print(result.stdout, end='') elapsed = (end - start)
end = time.time() print("{}: {} seconds".format(result_key, elapsed))
elapsed = (end - start) results[result_key] = elapsed
result_key = "{}->{}".format(from_name, to_name) else:
print("{}: {} seconds".format(result_key, elapsed)) print("error: {}".format(error))
results[result_key] = elapsed results[result_key] = "error: {}".format(error)
else: return
print(result.stderr, end='', file=sys.stderr)
print('Program exited with status %d' % result.exit_status,
file=sys.stderr)
results[result_key] = "error: {}".format(result.stderr)
return
# scp_with_time_cmd = "set -e; /usr/bin/time -f '%e' {}".format(scp_cmd) # scp_with_time_cmd = "set -e; /usr/bin/time -f '%e' {}".format(scp_cmd)
# print("running: {}".format(scp_with_time_cmd)) # print("running: {}".format(scp_with_time_cmd))
@ -117,6 +145,7 @@ async def run_test():
def run_laptop_test(): def run_laptop_test():
from_name = "laptop" from_name = "laptop"
# also measure transfers from laptop # also measure transfers from laptop
node_dict = SECRETS["HOST_INFO"]
for to_name, to_node_vals in node_dict.items(): for to_name, to_node_vals in node_dict.items():
print("** running test.png transfer test from laptop to {}".format(to_name)) print("** running test.png transfer test from laptop to {}".format(to_name))
@ -154,8 +183,8 @@ def run_laptop_test():
try: try:
asyncio.get_event_loop().run_until_complete(run_test()) # asyncio.get_event_loop().run_until_complete(run_test())
# run_laptop_test() run_laptop_test()
print("** final results **") print("** final results **")
file_size = 13476 file_size = 13476

0
get_device_info.y.py Normal file
View File

View File

@ -1,16 +1,19 @@
import asyncio import asyncio
import logging import logging
from datetime import date, datetime
from telegram import Update from telegram import Update
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters
import os import os
import json import json
from cowmesh_pi_speedtest import CowmeshPiSpeedtestTester
from cowmesh_router_iperf_test import CowmeshRouterIperfTester from cowmesh_router_iperf_test import CowmeshRouterIperfTester
from cowmesh_pi_iperf_test import CowmeshPiIperfTester from cowmesh_pi_iperf_test import CowmeshPiIperfTester
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json") SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
LOG_DIR_PATH = "/datadrive/apps/moonlight_analytics/results"
with open(SECRETS_PATH, 'r') as f: with open(SECRETS_PATH, 'r') as f:
SECRETS = json.loads(f.read()) SECRETS = json.loads(f.read())
@ -19,151 +22,270 @@ logging.basicConfig(
level=logging.INFO level=logging.INFO
) )
class MoonlightTester:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="This is the moonlight analytics bot for mesh network diagnostics.\n\nType /help to see available commands.", message_thread_id=update.message.message_thread_id) await context.bot.send_message(chat_id=update.effective_chat.id, text="This is the moonlight analytics bot for mesh network diagnostics.\n\nType /help to see available commands.", message_thread_id=update.message.message_thread_id)
async def caps(update: Update, context: ContextTypes.DEFAULT_TYPE): async def caps(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
""" """
this is just a function to test that the bot is working as expected this is just a function to test that the bot is working as expected
""" """
text_caps = ' '.join(context.args).upper() text_caps = ' '.join(context.args).upper()
print("chat_id: {}".format(update.effective_chat.id)) print("chat_id: {}".format(update.effective_chat.id))
print("message_thread_id: {}".format(update.message.message_thread_id)) print("message_thread_id: {}".format(update.message.message_thread_id))
await context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps, message_thread_id=update.message.message_thread_id) await context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps, message_thread_id=update.message.message_thread_id)
async def router_iperf(update: Update, context: ContextTypes.DEFAULT_TYPE): async def router_iperf(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
time = context.args[0] if context.args else None time = context.args[0] if context.args else None
if not time: if not time:
time = 10 time = 10
async def log(msg):
await context.bot.send_message(chat_id=update.effective_chat.id, text=msg, message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]): log_name = "moonlight-{:%m-%d-%Y}-{:%H-%M}-router-iperf.txt".format(date.today(), datetime.now())
await log("++ can only start iperf test from Moonlight Bot group") log_location = os.path.join(LOG_DIR_PATH, log_name)
return
await log("++ starting router iperf test with {} seconds per test".format(time)) async def offline_log(msg):
tester = CowmeshRouterIperfTester(log=log, seconds=time) with open(log_location, 'a') as log_file:
await tester.run_test() log_file.write(msg + "\n")
await tester.output_results()
async def log(msg):
await offline_log(msg)
await context.bot.send_message(chat_id=update.effective_chat.id, text=msg,
message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]):
await log("++ can only start iperf test from Moonlight Bot group")
return
await log("++ starting router iperf test with {} seconds per test".format(time))
tester = CowmeshRouterIperfTester(log=log, time=time)
await tester.run_test()
await tester.output_results()
# send log file
document = open(log_location, 'rb')
await context.bot.send_document(update.effective_chat.id, document,
message_thread_id=update.message.message_thread_id)
async def pi_iperf(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
time = context.args[0] if context.args else None
if not time:
time = 10
log_name = "moonlight-{:%m-%d-%Y}-{:%H-%M}-pi-iperf.txt".format(date.today(), datetime.now())
log_location = os.path.join(LOG_DIR_PATH, log_name)
async def offline_log(msg):
with open(log_location, 'a') as log_file:
log_file.write(msg + "\n")
async def log(msg):
await offline_log(msg)
await context.bot.send_message(chat_id=update.effective_chat.id, text=msg, message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]):
await log("++ can only start iperf test from Moonlight Bot group")
return
await log("++ starting pi iperf test with {} seconds per test".format(time))
tester = CowmeshPiIperfTester(log=log, time=time)
await tester.run_test()
await tester.output_results()
# send log file
document = open(log_location, 'rb')
await context.bot.send_document(update.effective_chat.id, document, message_thread_id=update.message.message_thread_id)
async def pi_iperf(update: Update, context: ContextTypes.DEFAULT_TYPE): async def speedtest(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
time = context.args[0] if context.args else None log_name = "moonlight-{:%m-%d-%Y}-{:%H-%M}-pi-speedtest.txt".format(date.today(), datetime.now())
if not time: log_location = os.path.join(LOG_DIR_PATH, log_name)
time = 10
async def log(msg):
await context.bot.send_message(chat_id=update.effective_chat.id, text=msg, message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]): async def offline_log(msg):
await log("++ can only start iperf test from Moonlight Bot group") with open(log_location, 'a') as log_file:
return log_file.write(msg + "\n")
await log("++ starting pi iperf test with {} seconds per test".format(time)) async def log(msg):
tester = CowmeshPiIperfTester(log=log, time=time) await offline_log(msg)
await tester.run_test() await context.bot.send_message(chat_id=update.effective_chat.id, text=msg,
await tester.output_results() message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]):
await log("++ can only start test from Moonlight Bot group")
return
await log("++ starting pi speedtest-cli speedtest")
tester = CowmeshPiSpeedtestTester(log=log)
await tester.run_test()
await tester.output_results()
# send log file
document = open(log_location, 'rb')
await context.bot.send_document(update.effective_chat.id, document,
message_thread_id=update.message.message_thread_id)
async def unknown(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
await context.bot.send_message(chat_id=update.effective_chat.id, text="Sorry, I didn't understand that, please run /help for a list of available commands.", message_thread_id=update.message.message_thread_id)
async def unknown(update: Update, context: ContextTypes.DEFAULT_TYPE): def about_message(self):
await context.bot.send_message(chat_id=update.effective_chat.id, text="Sorry, I didn't understand that, please run /help for a list of available commands.", message_thread_id=update.message.message_thread_id) msg = "This is a bot designed to help measure the performance of a mesh network through active testing. " \
"Every night the bot runs a network test using iperf to measure the connectivity between all the nodes in the mesh, " \
"and logs the result to this channel. " \
"Members of this channel can also initiate a new network iperf test at any time by sending a message to this channel, " \
"with the command /iperf . " \
"Telegram users outside of this channel cannot initiate a test, to help keep the network secure from being " \
"overrun by malicious users. " \
"The network test runs at night because that is when the fewest people are using the network, and so is more likely to " \
"give consistent results with less random variability. " \
"Please be mindful of initiating too many iperf tests during the day, as it uses a lot of network resources " \
"to run the test and could interfere with the internet connections of people using the network. "
return msg
def about_message(): def help_message(self):
msg = "This is a bot designed to help measure the performance of a mesh network through active testing. " \ msg = "This bot runs an iperf test every night and logs the results here. You can also initiate a new test using the command /iperf " \
"Every night the bot runs a network test using iperf to measure the connectivity between all the nodes in the mesh, " \ "or read a longer message explaining how this bot works by typing the command /readme."
"and logs the result to this channel. " \ return msg
"Members of this channel can also initiate a new network iperf test at any time by sending a message to this channel, " \
"with the command /iperf . " \
"Telegram users outside of this channel cannot initiate a test, to help keep the network secure from being " \
"overrun by malicious users. " \
"The network test runs at night because that is when the fewest people are using the network, and so is more likely to " \
"give consistent results with less random variability. " \
"Please be mindful of initiating too many iperf tests during the day, as it uses a lot of network resources " \
"to run the test and could interfere with the internet connections of people using the network. "
return msg
def help_message(): async def about(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
msg = "This bot runs an iperf test every night and logs the results here. You can also initiate a new test using the command /iperf " \ text = self.about_message()
"or read a longer message explaining how this bot works by typing the command /readme." await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id)
return msg
async def about(update: Update, context: ContextTypes.DEFAULT_TYPE): async def help_fun(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
text = about_message() text = self.help_message()
await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id) await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id)
async def send_log(self, bot, chat_id, message_thread_id, log_location):
# send log file
document = open(log_location, 'rb')
bot.send_document(chat_id, document, message_thread_id=message_thread_id)
async def nightly_router_iperf(self, time=10):
token = SECRETS["TELEGRAM_TOKEN"]
application = ApplicationBuilder().token(token).build()
chat_id = SECRETS["TELEGRAM_LOG_CHAT_ID"]
message_thread_id = SECRETS.get("TELEGRAM_LOG_MESSAGE_THREAD_ID")
bot = application.bot
log_name = "moonlight-{:%M-%d-%Y}-{:%H:%m}-router-iperf.txt".format(datetime.today(), datetime.now())
log_location = os.path.join(LOG_DIR_PATH, log_name)
async def offline_log(msg):
with open(log_location, 'a') as log_file:
log_file.write(msg)
async def log(msg):
await offline_log(msg)
try:
await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id)
except:
pass
await log("☾☾ starting nightly router-to-router iperf test with {time} seconds per test".format(time=time))
tester = CowmeshRouterIperfTester(log=log, time=time)
await tester.run_test()
await tester.output_results()
await self.send_log(bot=bot, log_location=log_location, chat_id=chat_id, message_thread_id=message_thread_id)
async def help_fun(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = help_message() async def nightly_pi_iperf(self, time=10):
await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id) token = SECRETS["TELEGRAM_TOKEN"]
application = ApplicationBuilder().token(token).build()
chat_id = SECRETS["TELEGRAM_LOG_CHAT_ID"]
message_thread_id = SECRETS.get("TELEGRAM_LOG_MESSAGE_THREAD_ID")
bot = application.bot
async def nightly_router_iperf(time=10): log_name = "moonlight-{:%M-%d-%Y}-{:%H:%m}-pi-iperf.txt".format(datetime.today(), datetime.now())
token = SECRETS["TELEGRAM_TOKEN"] log_location = os.path.join(LOG_DIR_PATH, log_name)
application = ApplicationBuilder().token(token).build()
chat_id = SECRETS["TELEGRAM_LOG_CHAT_ID"]
message_thread_id = SECRETS.get("TELEGRAM_LOG_MESSAGE_THREAD_ID")
bot = application.bot
async def log(msg): async def offline_log(msg):
await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id) with open(log_location, 'a') as log_file:
log_file.write(msg)
await log("☾☾ starting nightly router-to-router iperf test with {} seconds per test") async def log(msg):
tester = CowmeshRouterIperfTester(log=log, time=time) await offline_log(msg)
await tester.run_test() try:
await tester.output_results() await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id)
except:
pass
await log("☾☾ starting nightly computer-to-computer iperf test with {} seconds per test".format(time))
tester = CowmeshPiIperfTester(log=log, time=time)
await tester.run_test()
await tester.output_results()
await self.send_log(bot=bot, log_location=log_location, chat_id=chat_id, message_thread_id=message_thread_id)
async def nightly_pi_iperf(time=10):
token = SECRETS["TELEGRAM_TOKEN"]
application = ApplicationBuilder().token(token).build()
chat_id = SECRETS["TELEGRAM_LOG_CHAT_ID"]
message_thread_id = SECRETS.get("TELEGRAM_LOG_MESSAGE_THREAD_ID")
bot = application.bot
async def log(msg): async def nightly_pi_speedtest(self):
await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id) token = SECRETS["TELEGRAM_TOKEN"]
application = ApplicationBuilder().token(token).build()
chat_id = SECRETS["TELEGRAM_LOG_CHAT_ID"]
message_thread_id = SECRETS.get("TELEGRAM_LOG_MESSAGE_THREAD_ID")
bot = application.bot
await log("☾☾ starting nightly computer-to-computer iperf test with {} seconds per test".format(time)) log_name = "moonlight-{:%M-%d-%Y}-{:%H:%m}-pi-iperf.txt".format(datetime.today(), datetime.now())
tester = CowmeshPiIperfTester(log=log, time=time) log_location = os.path.join(LOG_DIR_PATH, log_name)
await tester.run_test()
await tester.output_results() async def offline_log(msg):
with open(log_location, 'a') as log_file:
log_file.write(msg)
async def log(msg):
await offline_log(msg)
try:
await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id)
except:
pass
await log("☾☾ starting nightly speedtest-cli speedtest")
tester = CowmeshPiSpeedtestTester(log=log)
await tester.run_test()
await tester.output_results()
await self.send_log(bot=bot, log_location=log_location, chat_id=chat_id, message_thread_id=message_thread_id)
def init_bot_listener():
token = SECRETS["TELEGRAM_TOKEN"]
application = ApplicationBuilder().token(token).build()
start_handler = CommandHandler('start', start) def init_bot_listener(self):
application.add_handler(start_handler) token = SECRETS["TELEGRAM_TOKEN"]
application = ApplicationBuilder().token(token).build()
caps_handler = CommandHandler('caps', caps) start_handler = CommandHandler('start', self.start)
application.add_handler(caps_handler) application.add_handler(start_handler)
about_handler = CommandHandler('readme', about) caps_handler = CommandHandler('caps', self.caps)
application.add_handler(about_handler) application.add_handler(caps_handler)
help_handler = CommandHandler('help', help_fun) about_handler = CommandHandler('readme', self.about)
application.add_handler(help_handler) application.add_handler(about_handler)
iperf_handler = CommandHandler('iperf', router_iperf) help_handler = CommandHandler('help', self.help_fun)
application.add_handler(iperf_handler) application.add_handler(help_handler)
pi_iperf_handler = CommandHandler('pi_iperf', pi_iperf) iperf_handler = CommandHandler('iperf', self.router_iperf)
application.add_handler(pi_iperf_handler) application.add_handler(iperf_handler)
unknown_handler = MessageHandler(filters.COMMAND, unknown) pi_iperf_handler = CommandHandler('pi_iperf', self.pi_iperf)
application.add_handler(unknown_handler) application.add_handler(pi_iperf_handler)
application.run_polling() speedtest_handler = CommandHandler('speedtest', self.speedtest)
application.add_handler(speedtest_handler)
unknown_handler = MessageHandler(filters.COMMAND, self.unknown)
application.add_handler(unknown_handler)
application.run_polling()
if __name__ == '__main__': if __name__ == '__main__':
init_bot_listener() tester = MoonlightTester()
tester.init_bot_listener()

View File

@ -1,12 +1,15 @@
import argparse import argparse
from moonlight_analytics import nightly_router_iperf, nightly_pi_iperf from moonlight_analytics import MoonlightTester
import asyncio import asyncio
import sys import sys
if __name__ == '__main__': if __name__ == '__main__':
tester = MoonlightTester()
time = sys.argv[2] if len(sys.argv) > 2 else 10 time = sys.argv[2] if len(sys.argv) > 2 else 10
if sys.argv[1] == "router": if sys.argv[1] == "router":
asyncio.get_event_loop().run_until_complete(nightly_router_iperf(time=time)) asyncio.get_event_loop().run_until_complete(tester.nightly_router_iperf(time=time))
elif sys.argv[1] == "pi": elif sys.argv[1] == "pi":
asyncio.get_event_loop().run_until_complete(nightly_pi_iperf(time=time)) asyncio.get_event_loop().run_until_complete(tester.nightly_pi_iperf(time=time))
elif sys.argv[1] == "speedtest":
asyncio.get_event_loop().run_until_complete(tester.nightly_pi_speedtest())