From 098948c98f21c785b636826d59c33f98451bd577 Mon Sep 17 00:00:00 2001 From: notplants Date: Fri, 28 Apr 2023 17:34:41 +0530 Subject: [PATCH] computer-to-computer test --- .gitignore | 3 +- cowmesh_pi_iperf_test.py | 129 ++++++++++++++++++ ...rf_test.py => cowmesh_router_iperf_test.py | 9 +- moonlight_analytics.py | 63 +++++++-- nightly_test.py | 9 +- 5 files changed, 198 insertions(+), 15 deletions(-) create mode 100644 cowmesh_pi_iperf_test.py rename cowmesh_iperf_test.py => cowmesh_router_iperf_test.py (92%) diff --git a/.gitignore b/.gitignore index 1f0bfab..d1fcd90 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ download.png test.png .idea secrets.json -__pycache__ \ No newline at end of file +__pycache__ +push.sh \ No newline at end of file diff --git a/cowmesh_pi_iperf_test.py b/cowmesh_pi_iperf_test.py new file mode 100644 index 0000000..2e25108 --- /dev/null +++ b/cowmesh_pi_iperf_test.py @@ -0,0 +1,129 @@ +""" +similar to cowmesh_iperf_test but instead of running iperf router-to-router, +it runs iperf between computers which are connected to the network +(pi & nuc etc.) +""" +import datetime +import os +import re +import time +import asyncio, asyncssh, sys +import paramiko +import subprocess +import json + +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 +] + +results = {} + + +class CowmeshPiIperfTester: + + def __init__(self, log=None, debug=False, time=10): + if log: + self.log = log + self.debug = debug + self.time = time + + async def log(self, msg): + print(msg) + + async def debug_log(self, msg): + if self.debug: + await self.log(msg) + + async def test_between_two_nodes(self, node_a, node_b): + await self.log("++ running test from {} to {}".format(node_a, node_b)) + user_a = SECRETS["HOST_INFO"][node_a]["user"] + password_a = SECRETS["HOST_INFO"][node_a]["password"] + + myconn = paramiko.SSHClient() + myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + + ip_a = SECRETS["HOST_INFO"][node_a]["ip"] + myconn.connect(ip_a, username=user_a, password=password_a) + + ip_b = SECRETS["HOST_INFO"][node_b]["ip"] + + remote_cmd = 'iperf -c {ip_b} -p 5001 -t {time}'.format(ip_b=ip_b, time=self.time) + (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() + + match = re.search("(\S+) Mbits", output) + if match: + to_return = match.group(1) + else: + to_return = None + + return to_return + + async def start_iperf_servers(self): + for node in nodes: + 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() + + async def run_test(self): + + await self.start_iperf_servers() + + for node_a in nodes: + for node_b in nodes: + if node_a == node_b: + await self.debug_log("skip self") + continue + + r = await self.test_between_two_nodes(node_a, node_b) + result_key = "{} -> {}".format(node_a, node_b) + results[result_key] = r + + async def output_results(self): + results_str = "" + now = datetime.datetime.now() + date = now.date() + 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) + for test_name, result in results.items(): + results_str += "{}: {} mbps\n".format(test_name, result) + await self.log(results_str) + + +if __name__ == "__main__": + try: + tester = CowmeshPiIperfTester() + + 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)) \ No newline at end of file diff --git a/cowmesh_iperf_test.py b/cowmesh_router_iperf_test.py similarity index 92% rename from cowmesh_iperf_test.py rename to cowmesh_router_iperf_test.py index f52ddd3..80f11e3 100644 --- a/cowmesh_iperf_test.py +++ b/cowmesh_router_iperf_test.py @@ -38,12 +38,13 @@ host_to_ip = { results = {} -class CowmeshIperfTester: +class CowmeshRouterIperfTester: - def __init__(self, log=None, debug=False): + def __init__(self, log=None, debug=False, seconds=10): if log: self.log = log self.debug = debug + self.time = seconds async def log(self, msg): print(msg) @@ -64,7 +65,7 @@ class CowmeshIperfTester: ip = host_to_ip[node_b] - remote_cmd = 'iperf -c {ip} -p 5001'.format(ip=ip) + remote_cmd = 'iperf -c {ip} -p 5001 -t {seconds}'.format(ip=ip, seconds=self.time) (stdin, stdout, stderr) = myconn.exec_command(remote_cmd) output = str(stdout.read()) await self.debug_log("output: {}".format(output)) @@ -124,7 +125,7 @@ class CowmeshIperfTester: if __name__ == "__main__": try: - tester = CowmeshIperfTester() + tester = CowmeshRouterIperfTester() async def main_fun(): await tester.run_test() diff --git a/moonlight_analytics.py b/moonlight_analytics.py index 18811cd..922dd1c 100644 --- a/moonlight_analytics.py +++ b/moonlight_analytics.py @@ -6,7 +6,8 @@ from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, Messa import os import json -from cowmesh_iperf_test import CowmeshIperfTester +from cowmesh_router_iperf_test import CowmeshRouterIperfTester +from cowmesh_pi_iperf_test import CowmeshPiIperfTester PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json") @@ -33,11 +34,38 @@ async def caps(update: Update, context: ContextTypes.DEFAULT_TYPE): await context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps, message_thread_id=update.message.message_thread_id) -async def iperf(update: Update, context: ContextTypes.DEFAULT_TYPE): +async def router_iperf(update: Update, context: ContextTypes.DEFAULT_TYPE): + + time = context.args[0] if context.args else None + if not time: + 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) - await log("++ starting iperf test") - tester = CowmeshIperfTester(log=log) + + 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, seconds=time) + await tester.run_test() + await tester.output_results() + + +async def pi_iperf(update: Update, context: ContextTypes.DEFAULT_TYPE): + + time = context.args[0] if context.args else None + if not time: + 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"]): + 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() @@ -77,7 +105,7 @@ async def help_fun(update: Update, context: ContextTypes.DEFAULT_TYPE): await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id) -async def nightly_iperf(): +async def nightly_router_iperf(time=10): token = SECRETS["TELEGRAM_TOKEN"] application = ApplicationBuilder().token(token).build() chat_id = SECRETS["TELEGRAM_LOG_CHAT_ID"] @@ -87,8 +115,24 @@ async def nightly_iperf(): async def log(msg): await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id) - await log("☾☾ starting nightly iperf test") - tester = CowmeshIperfTester(log=log) + await log("☾☾ starting nightly router-to-router iperf test with {} seconds per test") + tester = CowmeshRouterIperfTester(log=log, time=time) + await tester.run_test() + await tester.output_results() + + +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): + await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id) + + 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() @@ -109,9 +153,12 @@ def init_bot_listener(): help_handler = CommandHandler('help', help_fun) application.add_handler(help_handler) - iperf_handler = CommandHandler('iperf', iperf) + iperf_handler = CommandHandler('iperf', router_iperf) application.add_handler(iperf_handler) + pi_iperf_handler = CommandHandler('pi_iperf', pi_iperf) + application.add_handler(pi_iperf_handler) + unknown_handler = MessageHandler(filters.COMMAND, unknown) application.add_handler(unknown_handler) diff --git a/nightly_test.py b/nightly_test.py index 7b16083..a87919e 100644 --- a/nightly_test.py +++ b/nightly_test.py @@ -1,7 +1,12 @@ import argparse -from moonlight_analytics import nightly_iperf +from moonlight_analytics import nightly_router_iperf, nightly_pi_iperf import asyncio +import sys if __name__ == '__main__': - asyncio.get_event_loop().run_until_complete(nightly_iperf()) \ No newline at end of file + time = sys.argv[2] if len(sys.argv) > 2 else 10 + if sys.argv[1] == "router": + asyncio.get_event_loop().run_until_complete(nightly_router_iperf(time=time)) + elif sys.argv[1] == "pi": + asyncio.get_event_loop().run_until_complete(nightly_pi_iperf(time=time)) \ No newline at end of file