Exemple #1
0
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 _collect_tasks():
    collect_tasks(tasks)
Exemple #3
0
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()
Exemple #4
0
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()
Exemple #5
0
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()
Exemple #6
0
def run_(
    data_path: Path,
    auth: str,
    password: Optional[str],
    keystore_file: str,
    scenario_file: Path,
    enable_ui: bool,
    password_file: str,
    log_file_name: str,
    environment: EnvironmentConfig,
    delete_snapshots: bool,
    raiden_client: Optional[str],
    smoketest_deployment_data=None,
) -> None:
    """Execute a scenario as defined in scenario definition file.
    (Shared code for `run` and `smoketest` command).

    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).
    """
    log.info("Scenario Player version:", version_info=get_complete_spec())

    password = get_password(password, password_file)
    account = get_account(keystore_file, password)

    log_buffer = None
    if enable_ui:
        log_buffer = attach_urwid_logbuffer()

    # Dynamically import valid Task classes from scenario_player.tasks package.
    collect_tasks(tasks)

    # Start our Services
    report: Dict[str, str] = {}
    success = Event()
    success.clear()
    try:
        # We need to fix the log stream early in case the UI is active
        scenario_runner = ScenarioRunner(
            account=account,
            auth=auth,
            data_path=data_path,
            scenario_file=scenario_file,
            environment=environment,
            success=success,
            smoketest_deployment_data=smoketest_deployment_data,
            delete_snapshots=delete_snapshots,
            raiden_client=raiden_client,
        )
        if enable_ui:
            ui: AbstractContextManager = ScenarioUIManager(
                scenario_runner, log_buffer, log_file_name, success
            )
        else:
            ui = nullcontext()
        log.info("Startup complete")
        with ui:
            scenario_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
        report.update(dict(subject=f"Assertion mismatch in {scenario_file.name}", message=str(ex)))
        exit(exit_code)
    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
        report.update(
            dict(
                subject=f"Invalid scenario {scenario_file.name}",
                message=traceback.format_exc(),
            )
        )
        exit(exit_code)
    except Exception as ex:
        log.exception("Exception while running scenario")
        if hasattr(ex, "exit_code"):
            exit_code = ex.exit_code  # type: ignore  # pylint: disable=no-member
        else:
            exit_code = 10
        report.update(
            dict(
                subject=f"Error running scenario {scenario_file.name}",
                message=traceback.format_exc(),
            )
        )
        exit(exit_code)
    else:
        exit_code = 0
        log.info("Run finished", result="success")
        report.update(dict(subject=f"Scenario successful {scenario_file.name}", message="Success"))
        log.info("Scenario player unwind complete")
        exit(exit_code)
Exemple #7
0
def main(scenario_file, keystore_file, password, rpc_url, 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 = LogBuffer()
    for handler in logging.getLogger('').handlers:
        if isinstance(handler, logging.StreamHandler):
            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)

    runner = ScenarioRunner(account, rpc_url, auth, scenario_file)
    terminal = Terminal()
    # Disable line wrapping
    print(terminal.rmam, end='')
    gevent.spawn(_ui, terminal, runner, log_file_name, log_buffer)
    try:
        assert_errors = runner.run_scenario()
        if assert_errors:
            log.error('Run finished', result='assertion errors')
        else:
            log.info('Run finished', result='success')
        if runner.notification_email:
            if not mailgun_api_key:
                log.error("Can't send notification mail. No API key provided")
                return 1
            log.info('Sending notification mail')
            if assert_errors:
                send_notification_mail(
                    runner.notification_email,
                    f'Unexpected channel balances in {scenario_file.name}',
                    json.dumps(assert_errors),
                    mailgun_api_key,
                )
            else:
                send_notification_mail(
                    runner.notification_email,
                    f'Scenario successful {scenario_file.name}',
                    'Success',
                    mailgun_api_key,
                )
    except Exception:
        if runner.notification_email and mailgun_api_key:
            send_notification_mail(
                runner.notification_email,
                f'Error running scenario {scenario_file.name}',
                traceback.format_exc(),
                mailgun_api_key,
            )
        log.exception('Exception while running scenario')
    finally:
        try:
            if terminal.is_a_tty:
                log.warning('Press Ctrl-C to exit')
                while True:
                    gevent.sleep(1)
        finally:
            # Re-enable line wrapping
            print(terminal.smam, end='')
Exemple #8
0
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)