class ScenarioUIManager(AbstractContextManager): def __init__(self, runner, log_buffer, log_file_name, success): self.ui = ScenarioUI(runner, log_buffer, log_file_name) self.success = success def __enter__(self): self.ui_greenlet = self.ui.run() return self.success def __exit__(self, exc_type, value, traceback): if exc_type is not None: # This will cause some exceptions to be in the log twice, but # that's better than not seeing the exception in the UI at all. log.exception() try: self.ui.set_success(self.success.is_set()) log.warning("Press q to exit") while not self.ui_greenlet.ready(): gevent.sleep(0.1) finally: if self.ui_greenlet is not None and not self.ui_greenlet.dead: self.ui_greenlet.kill(ExitMainLoop) self.ui_greenlet.join()
def main( ctx, scenario_file, keystore_file, password, chains, data_path, auth, mailgun_api_key, ): gevent.get_hub().exception_stream = DummyStream() is_subcommand = ctx.invoked_subcommand is not None if not is_subcommand and scenario_file is None: ctx.fail('No scenario definition file provided') if is_subcommand: log_file_name = ( f'scenario-player-{ctx.invoked_subcommand}_{datetime.now():%Y-%m-%dT%H:%M:%S}.log' ) else: scenario_basename = basename(scenario_file.name) log_file_name = ( f'scenario-player_{scenario_basename}_{datetime.now():%Y-%m-%dT%H:%M:%S}.log' ) click.secho(f'Writing log to {log_file_name}', fg='yellow') configure_logging( {'': 'INFO', 'raiden': 'DEBUG', 'scenario_player': 'DEBUG'}, debug_log_file_name=log_file_name, _first_party_packages=_FIRST_PARTY_PACKAGES | frozenset(['scenario_player']), ) log_buffer = None if sys.stdout.isatty() and not is_subcommand: log_buffer = UrwidLogWalker([]) for handler in logging.getLogger('').handlers: if isinstance(handler, logging.StreamHandler): handler.terminator = None handler.formatter = NonStringifyingProcessorFormatter( UrwidLogRenderer(), foreign_pre_chain=LOGGING_PROCESSORS, ) handler.stream = log_buffer break chain_rpc_urls = defaultdict(list) for chain_name, chain_rpc_url in chains: chain_rpc_urls[chain_name].append(chain_rpc_url) with open(keystore_file, 'r') as keystore: account = Account(json.load(keystore), password, keystore_file) log.info("Using account", account=to_checksum_address(account.address)) if is_subcommand: ctx.obj = dict( account=account, chain_rpc_urls=chain_rpc_urls, data_path=data_path, ) return # Collect tasks collect_tasks(tasks) runner = ScenarioRunner(account, chain_rpc_urls, auth, Path(data_path), scenario_file) ui = ScenarioUI(runner, log_buffer, log_file_name) ui_greenlet = ui.run() success = False try: try: runner.run_scenario() success = True log.info('Run finished', result='success') send_notification_mail( runner.notification_email, f'Scenario successful {scenario_file.name}', 'Success', mailgun_api_key, ) except ScenarioAssertionError as ex: log.error('Run finished', result='assertion errors') send_notification_mail( runner.notification_email, f'Assertion mismatch in {scenario_file.name}', str(ex), mailgun_api_key, ) except ScenarioError: log.exception('Run finished', result='scenario error') send_notification_mail( runner.notification_email, f'Invalid scenario {scenario_file.name}', traceback.format_exc(), mailgun_api_key, ) except Exception: log.exception('Exception while running scenario') send_notification_mail( runner.notification_email, f'Error running scenario {scenario_file.name}', traceback.format_exc(), mailgun_api_key, ) finally: try: if sys.stdout.isatty(): ui.set_success(success) log.warning('Press q to exit') while not ui_greenlet.dead: gevent.sleep(1) finally: if runner.is_managed: runner.node_controller.stop() if not ui_greenlet.dead: ui_greenlet.kill(ExitMainLoop) ui_greenlet.join()
def run(ctx, mailgun_api_key, auth, password, keystore_file, scenario_file, notify_tasks, enable_ui): scenario_file = Path(scenario_file.name).absolute() data_path = ctx.obj["data_path"] chain_rpc_urls = ctx.obj["chain_rpc_urls"] log_file_name = construct_log_file_name("run", data_path, scenario_file) configure_logging_for_subcommand(log_file_name) account = load_account_obj(keystore_file, password) notify_tasks_callable = None if notify_tasks is TaskNotifyType.ROCKETCHAT: if "RC_WEBHOOK_URL" not in os.environ: click.secho( "'--notify-tasks rocket-chat' requires env variable 'RC_WEBHOOK_URL' to be set.", fg="red", ) notify_tasks_callable = post_task_state_to_rc log_buffer = None # If the output is a terminal, beautify our output. if enable_ui: enable_gui_formatting() # Dynamically import valid Task classes from sceanrio_player.tasks package. collect_tasks(tasks) # Start our Services service = construct_flask_app() service_process = ServiceProcess(service) service_process.start() # Run the scenario using the configurations passed. runner = ScenarioRunner(account, chain_rpc_urls, auth, data_path, scenario_file, notify_tasks_callable) ui = None ui_greenlet = None if enable_ui: ui = ScenarioUI(runner, log_buffer, log_file_name) ui_greenlet = ui.run() success = False try: try: runner.run_scenario() except ScenarioAssertionError as ex: log.error("Run finished", result="assertion errors") send_notification_mail( runner.notification_email, f"Assertion mismatch in {scenario_file.name}", str(ex), mailgun_api_key, ) except ScenarioError: log.exception("Run finished", result="scenario error") send_notification_mail( runner.notification_email, f"Invalid scenario {scenario_file.name}", traceback.format_exc(), mailgun_api_key, ) else: success = True log.info("Run finished", result="success") send_notification_mail( runner.notification_email, f"Scenario successful {scenario_file.name}", "Success", mailgun_api_key, ) except Exception: log.exception("Exception while running scenario") send_notification_mail( runner.notification_email, f"Error running scenario {scenario_file.name}", traceback.format_exc(), mailgun_api_key, ) finally: try: if enable_ui and ui: ui.set_success(success) log.warning("Press q to exit") while not ui_greenlet.dead: gevent.sleep(1) service_process.start() except ServiceProcessException: service_process.kill() finally: if runner.is_managed: runner.node_controller.stop() if ui_greenlet is not None and not ui_greenlet.dead: ui_greenlet.kill(ExitMainLoop) ui_greenlet.join()
def main( scenario_file, keystore_file, password, chains, data_path, auth, mailgun_api_key, ): gevent.get_hub().exception_stream = DummyStream() scenario_basename = basename(scenario_file.name) log_file_name = f'scenario-player_{scenario_basename}_{datetime.now():%Y-%m-%dT%H:%M:%S}.log' click.secho(f'Writing log to {log_file_name}', fg='yellow') configure_logging( {'': 'INFO', 'raiden': 'DEBUG', 'scenario_player': 'DEBUG'}, debug_log_file_name=log_file_name, _first_party_packages=frozenset(['raiden', 'scenario_player']), ) log_buffer = None if sys.stdout.isatty(): log_buffer = UrwidLogWalker([]) for handler in logging.getLogger('').handlers: if isinstance(handler, logging.StreamHandler): handler.terminator = None handler.formatter = NonStringifyingProcessorFormatter( UrwidLogRenderer(), foreign_pre_chain=LOGGING_PROCESSORS, ) handler.stream = log_buffer break with open(keystore_file, 'r') as keystore: account = Account(json.load(keystore), password, keystore_file) log.info("Using account", account=to_checksum_address(account.address)) # Collect tasks collect_tasks(tasks) chain_rpc_urls = defaultdict(list) for chain_name, chain_rpc_url in chains: chain_rpc_urls[chain_name].append(chain_rpc_url) runner = ScenarioRunner(account, chain_rpc_urls, auth, Path(data_path), scenario_file) ui = ScenarioUI(runner, log_buffer, log_file_name) ui_greenlet = ui.run() success = False try: try: runner.run_scenario() success = True log.info('Run finished', result='success') send_notification_mail( runner.notification_email, f'Scenario successful {scenario_file.name}', 'Success', mailgun_api_key, ) except ScenarioAssertionError as ex: log.error('Run finished', result='assertion errors') send_notification_mail( runner.notification_email, f'Assertion mismatch in {scenario_file.name}', str(ex), mailgun_api_key, ) except ScenarioError as ex: log.error('Run finished', result='scenario error') send_notification_mail( runner.notification_email, f'Invalid scenario {scenario_file.name}', traceback.format_exc(), mailgun_api_key, ) except Exception: log.exception('Exception while running scenario') send_notification_mail( runner.notification_email, f'Error running scenario {scenario_file.name}', traceback.format_exc(), mailgun_api_key, ) finally: try: if sys.stdout.isatty(): ui.set_success(success) log.warning('Press q to exit') while not ui_greenlet.dead: gevent.sleep(1) finally: if not ui_greenlet.dead: ui_greenlet.kill(ExitMainLoop) ui_greenlet.join()
def run(ctx, mailgun_api_key, auth, password, keystore_file, scenario_file): scenario_file = Path(scenario_file.name).absolute() data_path = ctx.obj['data_path'] chain_rpc_urls = ctx.obj['chain_rpc_urls'] log_file_name = construct_log_file_name('run', data_path, scenario_file) configure_logging_for_subcommand(log_file_name) account = load_account_obj(keystore_file, password) log_buffer = None # If the output is a terminal, beautify our output. if sys.stdout.isatty(): log_buffer = UrwidLogWalker([]) for handler in logging.getLogger("").handlers: if isinstance(handler, logging.StreamHandler): handler.terminator = ConcatenableNone() handler.formatter = NonStringifyingProcessorFormatter( UrwidLogRenderer(), foreign_pre_chain=LOGGING_PROCESSORS ) handler.stream = log_buffer break # Dynamically import valid Task classes from sceanrio_player.tasks package. collect_tasks(tasks) # Run the scenario using the configurations passed. runner = ScenarioRunner(account, chain_rpc_urls, auth, data_path, scenario_file) ui = ScenarioUI(runner, log_buffer, log_file_name) ui_greenlet = ui.run() success = False try: try: runner.run_scenario() except ScenarioAssertionError as ex: log.error("Run finished", result="assertion errors") send_notification_mail( runner.notification_email, f"Assertion mismatch in {scenario_file.name}", str(ex), mailgun_api_key, ) except ScenarioError: log.exception("Run finished", result="scenario error") send_notification_mail( runner.notification_email, f"Invalid scenario {scenario_file.name}", traceback.format_exc(), mailgun_api_key, ) else: success = True log.info("Run finished", result="success") send_notification_mail( runner.notification_email, f"Scenario successful {scenario_file.name}", "Success", mailgun_api_key, ) except Exception: log.exception("Exception while running scenario") send_notification_mail( runner.notification_email, f"Error running scenario {scenario_file.name}", traceback.format_exc(), mailgun_api_key, ) finally: try: if sys.stdout.isatty(): ui.set_success(success) log.warning("Press q to exit") while not ui_greenlet.dead: gevent.sleep(1) finally: if runner.is_managed: runner.node_controller.stop() if not ui_greenlet.dead: ui_greenlet.kill(ExitMainLoop) ui_greenlet.join()
def __init__(self, runner, log_buffer, log_file_name, success): self.ui = ScenarioUI(runner, log_buffer, log_file_name) self.success = success
def run( ctx, chain, data_path, mailgun_api_key, auth, password, keystore_file, scenario_file, notify_tasks, enable_ui, password_file, ): """Execute a scenario as defined in scenario definition file. Calls :func:`exit` when done, with the following status codes: Exit code 1x There was a problem when starting up the SP, nodes, deploying tokens or setting up services. This points at an issue in the SP and of of its components. Exit code 2x There was an error when parsing or evaluating the given scenario definition file. This may be a syntax- or logic-related issue. Exit code 3x There was an assertion error while executing the scenario. This points to an error in a `raiden` component (the client, services or contracts). """ data_path = Path(data_path) scenario_file = Path(scenario_file.name).absolute() log_file_name = construct_log_file_name("run", data_path, scenario_file) configure_logging_for_subcommand(log_file_name) log.info("Scenario Player version:", version_info=get_complete_spec()) password = get_password(password, password_file) account = get_account(keystore_file, password) notify_tasks_callable = None if notify_tasks is TaskNotifyType.ROCKETCHAT: if "RC_WEBHOOK_URL" not in os.environ: click.secho( "'--notify-tasks rocket-chat' requires env variable 'RC_WEBHOOK_URL' to be set.", fg="red", ) notify_tasks_callable = post_task_state_to_rc log_buffer = None # If the output is a terminal, beautify our output. if enable_ui: log_buffer = attach_urwid_logbuffer() # Dynamically import valid Task classes from sceanrio_player.tasks package. collect_tasks(tasks) # Start our Services service_process = ServiceProcess() service_process.start() # Run the scenario using the configurations passed. try: runner = ScenarioRunner(account, auth, chain, data_path, scenario_file, notify_tasks_callable) except Exception as e: # log anything that goes wrong during init of the runner and isn't handled. log.exception("Error during startup", exception=e) raise ui = None ui_greenlet = None if enable_ui: ui = ScenarioUI(runner, log_buffer, log_file_name) ui_greenlet = ui.run() success = False exit_code = 1 subject = None message = None try: runner.run_scenario() except ScenarioAssertionError as ex: log.error("Run finished", result="assertion errors") if hasattr(ex, "exit_code"): exit_code = ex.exit_code else: exit_code = 30 subject = f"Assertion mismatch in {scenario_file.name}" message = str(ex) except ScenarioError as ex: log.error("Run finished", result="scenario error", message=str(ex)) if hasattr(ex, "exit_code"): exit_code = ex.exit_code else: exit_code = 20 subject = f"Invalid scenario {scenario_file.name}" message = traceback.format_exc() except Exception as ex: log.exception("Exception while running scenario") if hasattr(ex, "exit_code"): exit_code = ex.exit_code else: exit_code = 10 subject = f"Error running scenario {scenario_file.name}" message = traceback.format_exc() else: success = True exit_code = 0 log.info("Run finished", result="success") subject = f"Scenario successful {scenario_file.name}" message = "Success" finally: send_notification_mail( runner.definition.settings.notify, subject or "Logic error in main.py", message or "Message should not be empty.", mailgun_api_key, ) try: if enable_ui and ui: ui.set_success(success) log.warning("Press q to exit") while not ui_greenlet.dead: gevent.sleep(1) service_process.stop() except ServiceProcessException: service_process.kill() finally: runner.node_controller.stop() if ui_greenlet is not None and not ui_greenlet.dead: ui_greenlet.kill(ExitMainLoop) ui_greenlet.join() exit(exit_code)