From 018d3ddc0863565925e0c6f8d82122213a9244f7 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 17 Sep 2019 09:17:29 +0300 Subject: [PATCH] Fixed bugs regarding waiting for monkeys to die, readability improvements --- .../blackbox/analyzers/analyzer_log.py | 17 ++++++++++ .../analyzers/communication_analyzer.py | 26 ++++----------- .../island_client/monkey_island_client.py | 2 +- .../blackbox/log_handlers/log_parser.py | 32 +++++++++++++++++++ .../blackbox/log_handlers/logs_downloader.py | 22 +++++++++++++ .../blackbox/log_handlers/monkey_log.py | 2 ++ .../{test_logs.py => test_logs_handler.py} | 25 ++++++++++++--- envs/monkey_zoo/blackbox/test_blackbox.py | 4 +-- envs/monkey_zoo/blackbox/tests/basic_test.py | 31 +++++++++++++----- 9 files changed, 125 insertions(+), 36 deletions(-) create mode 100644 envs/monkey_zoo/blackbox/analyzers/analyzer_log.py create mode 100644 envs/monkey_zoo/blackbox/log_handlers/log_parser.py create mode 100644 envs/monkey_zoo/blackbox/log_handlers/logs_downloader.py rename envs/monkey_zoo/blackbox/log_handlers/{test_logs.py => test_logs_handler.py} (52%) diff --git a/envs/monkey_zoo/blackbox/analyzers/analyzer_log.py b/envs/monkey_zoo/blackbox/analyzers/analyzer_log.py new file mode 100644 index 000000000..f97418813 --- /dev/null +++ b/envs/monkey_zoo/blackbox/analyzers/analyzer_log.py @@ -0,0 +1,17 @@ +LOG_INIT_MESSAGE = "Analysis didn't run." + + +class AnalyzerLog(object): + + def __init__(self, analyzer_name): + self.contents = LOG_INIT_MESSAGE + self.name = analyzer_name + + def clear(self): + self.contents = "" + + def add_entry(self, message): + self.contents = "{}\n{}".format(self.contents, message) + + def get_contents(self): + return "{}: {}\n".format(self.name, self.contents) diff --git a/envs/monkey_zoo/blackbox/analyzers/communication_analyzer.py b/envs/monkey_zoo/blackbox/analyzers/communication_analyzer.py index cc460696b..491b534b8 100644 --- a/envs/monkey_zoo/blackbox/analyzers/communication_analyzer.py +++ b/envs/monkey_zoo/blackbox/analyzers/communication_analyzer.py @@ -1,4 +1,4 @@ -LOG_INIT_MESSAGE = "Analysis didn't run." +from envs.monkey_zoo.blackbox.analyzers.analyzer_log import AnalyzerLog class CommunicationAnalyzer(object): @@ -10,29 +10,15 @@ class CommunicationAnalyzer(object): def analyze_test_results(self): self.log.clear() + all_monkeys_communicated = True for machine_ip in self.machine_ips: if not self.did_monkey_communicate_back(machine_ip): self.log.add_entry("Monkey from {} didn't communicate back".format(machine_ip)) - return False - self.log.add_entry("Monkey from {} communicated back".format(machine_ip)) - return True + all_monkeys_communicated = False + else: + self.log.add_entry("Monkey from {} communicated back".format(machine_ip)) + return all_monkeys_communicated def did_monkey_communicate_back(self, machine_ip): query = {'ip_addresses': {'$elemMatch': {'$eq': machine_ip}}} return len(self.island_client.find_monkeys_in_db(query)) > 0 - - -class AnalyzerLog(object): - - def __init__(self, analyzer_name): - self.contents = LOG_INIT_MESSAGE - self.name = analyzer_name - - def clear(self): - self.contents = "" - - def add_entry(self, message): - self.contents = "{}\n{}".format(self.contents, message) - - def get_contents(self): - return "{}: {}\n".format(self.name, self.contents) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index bc2e30b44..a06617b08 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -82,5 +82,5 @@ class MonkeyIslandClient(object): return json.loads(response.content)['results'] def is_all_monkeys_dead(self): - query = {'dead': 'false'} + query = {'dead': False} return len(self.find_monkeys_in_db(query)) == 0 diff --git a/envs/monkey_zoo/blackbox/log_handlers/log_parser.py b/envs/monkey_zoo/blackbox/log_handlers/log_parser.py new file mode 100644 index 000000000..9f3c34f57 --- /dev/null +++ b/envs/monkey_zoo/blackbox/log_handlers/log_parser.py @@ -0,0 +1,32 @@ +import re + + +class LogParser(object): + + def __init__(self, log_path): + self.log_path = log_path + self.log_contents = self.read_log() + + def read_log(self): + with open(self.log_path, 'r') as log: + return log.read() + + def print_errors(self): + print("Errors:") + for error_line in LogParser.get_errors(self.log_contents): + print(error_line) + + @staticmethod + def get_errors(log_contents): + searcher = re.compile(r"^.*:ERROR].*$", re.MULTILINE) + return searcher.findall(log_contents) + + def print_warnings(self): + print("Warnings:") + for warning_line in LogParser.get_warnings(self.log_contents): + print(warning_line) + + @staticmethod + def get_warnings(log_contents): + searcher = re.compile(r"^.*:WARNING].*$", re.MULTILINE) + return searcher.findall(log_contents) diff --git a/envs/monkey_zoo/blackbox/log_handlers/logs_downloader.py b/envs/monkey_zoo/blackbox/log_handlers/logs_downloader.py new file mode 100644 index 000000000..446960147 --- /dev/null +++ b/envs/monkey_zoo/blackbox/log_handlers/logs_downloader.py @@ -0,0 +1,22 @@ +from envs.monkey_zoo.blackbox.log_handlers.monkey_log import MonkeyLog + + +class LogsDownloader(object): + + def __init__(self, island_client, log_dir_path): + self.island_client = island_client + self.log_dir_path = log_dir_path + self.monkey_log_paths = [] + + def download_monkey_logs(self): + print("Downloading each monkey log.") + all_monkeys = self.island_client.find_monkeys_in_db(None) + for monkey in all_monkeys: + downloaded_log_path = self._download_monkey_log(monkey) + if downloaded_log_path: + self.monkey_log_paths.append(downloaded_log_path) + + def _download_monkey_log(self, monkey): + log_handler = MonkeyLog(monkey, self.log_dir_path) + download_successful = log_handler.download_log(self.island_client) + return log_handler.get_log_path_for_monkey(monkey) if download_successful else None diff --git a/envs/monkey_zoo/blackbox/log_handlers/monkey_log.py b/envs/monkey_zoo/blackbox/log_handlers/monkey_log.py index b106b6668..bcc304535 100644 --- a/envs/monkey_zoo/blackbox/log_handlers/monkey_log.py +++ b/envs/monkey_zoo/blackbox/log_handlers/monkey_log.py @@ -12,8 +12,10 @@ class MonkeyLog(object): log = island_client.find_log_in_db({'monkey_id': ObjectId(self.monkey['id'])}) if not log: print("Log for monkey {} not found".format(self.monkey['ip_addresses'][0])) + return False else: self.write_log_to_file(log) + return True def write_log_to_file(self, log): with open(self.get_log_path_for_monkey(self.monkey), 'w') as log_file: diff --git a/envs/monkey_zoo/blackbox/log_handlers/test_logs.py b/envs/monkey_zoo/blackbox/log_handlers/test_logs_handler.py similarity index 52% rename from envs/monkey_zoo/blackbox/log_handlers/test_logs.py rename to envs/monkey_zoo/blackbox/log_handlers/test_logs_handler.py index 47d0bad62..e2c87a320 100644 --- a/envs/monkey_zoo/blackbox/log_handlers/test_logs.py +++ b/envs/monkey_zoo/blackbox/log_handlers/test_logs_handler.py @@ -1,7 +1,8 @@ import os import shutil -from envs.monkey_zoo.blackbox.log_handlers.monkey_log import MonkeyLog +from envs.monkey_zoo.blackbox.log_handlers.log_parser import LogParser +from envs.monkey_zoo.blackbox.log_handlers.logs_downloader import LogsDownloader LOG_DIR_NAME = 'logs' @@ -12,12 +13,18 @@ class TestLogsHandler(object): self.island_client = island_client self.log_dir_path = os.path.join(TestLogsHandler.get_log_dir_path(), self.test_name) + def parse_test_logs(self): + log_paths = self.download_logs() + if not log_paths: + print("No logs were downloaded, maybe no monkeys were ran?") + return + TestLogsHandler.parse_logs(log_paths) + def download_logs(self): self.try_create_log_dir_for_test() - print("Downloading logs") - all_monkeys = self.island_client.find_monkeys_in_db(None) - for monkey in all_monkeys: - MonkeyLog(monkey, self.log_dir_path).download_log(self.island_client) + downloader = LogsDownloader(self.island_client, self.log_dir_path) + downloader.download_monkey_logs() + return downloader.monkey_log_paths def try_create_log_dir_for_test(self): try: @@ -33,3 +40,11 @@ class TestLogsHandler(object): def delete_log_folder_contents(): shutil.rmtree(TestLogsHandler.get_log_dir_path(), ignore_errors=True) os.mkdir(TestLogsHandler.get_log_dir_path()) + + @staticmethod + def parse_logs(log_paths): + for log_path in log_paths: + print("Info from log at {}".format(log_path)) + log_parser = LogParser(log_path) + log_parser.print_errors() + log_parser.print_warnings() diff --git a/envs/monkey_zoo/blackbox/test_blackbox.py b/envs/monkey_zoo/blackbox/test_blackbox.py index dcf345345..2d80472ba 100644 --- a/envs/monkey_zoo/blackbox/test_blackbox.py +++ b/envs/monkey_zoo/blackbox/test_blackbox.py @@ -6,7 +6,7 @@ from envs.monkey_zoo.blackbox.analyzers.communication_analyzer import Communicat from envs.monkey_zoo.blackbox.island_client.island_config_parser import IslandConfigParser from envs.monkey_zoo.blackbox.utils import gcp_machine_handlers from envs.monkey_zoo.blackbox.tests.basic_test import BasicTest -from envs.monkey_zoo.blackbox.log_handlers.test_logs import TestLogsHandler +from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import TestLogsHandler DEFAULT_TIMEOUT_SECONDS = 4*60 MACHINE_BOOTUP_WAIT_SECONDS = 30 @@ -53,7 +53,7 @@ class TestMonkeyBlackbox(object): analyzer = CommunicationAnalyzer(island_client, config_parser.get_ips_of_targets()) BasicTest(test_name, island_client, - config_parser.config_raw, + config_parser, [analyzer], timeout_in_seconds).run() diff --git a/envs/monkey_zoo/blackbox/tests/basic_test.py b/envs/monkey_zoo/blackbox/tests/basic_test.py index ccc5c6770..2b544a9f1 100644 --- a/envs/monkey_zoo/blackbox/tests/basic_test.py +++ b/envs/monkey_zoo/blackbox/tests/basic_test.py @@ -1,35 +1,42 @@ from time import sleep from envs.monkey_zoo.blackbox.utils.test_timer import TestTimer -from envs.monkey_zoo.blackbox.log_handlers.test_logs import TestLogsHandler +from envs.monkey_zoo.blackbox.log_handlers.test_logs_handler import TestLogsHandler MAX_TIME_FOR_MONKEYS_TO_DIE = 5*60 WAIT_TIME_BETWEEN_REQUESTS = 10 +TIME_FOR_MONKEY_PROCESS_TO_FINISH = 20 class BasicTest(object): - def __init__(self, name, island_client, island_config, analyzers, timeout): + def __init__(self, name, island_client, config_parser, analyzers, timeout): self.name = name self.island_client = island_client - self.island_config = island_config + self.config_parser = config_parser self.analyzers = analyzers self.timeout = timeout def run(self): - self.island_client.import_config(self.island_config) + self.island_client.import_config(self.config_parser.config_raw) + self.print_test_starting_info() try: self.island_client.run_monkey_local() self.test_until_timeout() - except AssertionError: - print("Test {} failed. Downloading logs of all monkeys.".format(self.name)) - TestLogsHandler(self.name, self.island_client).download_logs() - raise finally: self.island_client.kill_all_monkeys() self.wait_until_monkeys_die() + self.wait_for_monkey_process_to_finish() + self.parse_logs() self.island_client.reset_env() + def print_test_starting_info(self): + print("Started {} test".format(self.name)) + print("Machines participating in test:") + for target_ip in self.config_parser.get_ips_of_targets(): + print(" "+target_ip) + print("") + def test_until_timeout(self): timer = TestTimer(self.timeout) while not timer.timed_out(): @@ -68,3 +75,11 @@ class BasicTest(object): if time_passed > MAX_TIME_FOR_MONKEYS_TO_DIE: print("Some monkeys didn't die after the test, passing") assert False + + def parse_logs(self): + print("\nParsing test logs:") + TestLogsHandler(self.name, self.island_client).parse_test_logs() + + @staticmethod + def wait_for_monkey_process_to_finish(): + sleep(TIME_FOR_MONKEY_PROCESS_TO_FINISH)