예제 #1
0
def stop(ctx, service, editable):
    """Stop a running service daemon."""
    logger.debug("running command %s (%s)", ctx.command.name, ctx.params,
                 extra={"command": ctx.command.name, "params": ctx.params})

    home = ctx.obj["HOME"]
    service_path = plugin_utils.get_plugin_path(home, SERVICES, service, editable)

    logger.debug("loading {}".format(service))
    service = register_service(service_path)

    try:
        with open(os.path.join(service_path, ARGS_JSON)) as f:
            service_args = json.loads(f.read())
    except IOError as exc:
        logger.debug(str(exc), exc_info=True)
        raise click.ClickException("Cannot load service args, are you sure server is running?")

    # get our service class instance
    service_module = get_service_module(service_path)
    service_obj = service_module.service_class(alert_types=service.alert_types, service_args=service_args)

    # prepare runner
    runner = myRunner(service_obj,
                      pidfile=service_path + ".pid",
                      stdout=open(os.path.join(service_path, "stdout.log"), "ab"),
                      stderr=open(os.path.join(service_path, "stderr.log"), "ab"))

    click.secho("[*] Stopping {}".format(service.name))
    try:
        runner._stop()
    except daemon.runner.DaemonRunnerStopFailureError as exc:
        logger.debug(str(exc), exc_info=True)
        raise click.ClickException("Unable to stop service, are you sure it is running?")
예제 #2
0
def uninstall(ctx, yes, services):
    """Uninstall a service."""
    logger.debug("running command %s (%s)",
                 ctx.command.name,
                 ctx.params,
                 extra={
                     "command": ctx.command.name,
                     "params": ctx.params
                 })

    home = ctx.obj["HOME"]

    for service in services:
        service_path = plugin_utils.get_plugin_path(home, SERVICES, service)
        plugin_utils.uninstall_plugin(service_path, yes)
예제 #3
0
def uninstall(ctx, yes, integrations):
    """Uninstall a integration."""
    logger.debug("running command %s (%s)",
                 ctx.command.name,
                 ctx.params,
                 extra={
                     "command": ctx.command.name,
                     "params": ctx.params
                 })

    home = ctx.obj["HOME"]

    for integration in integrations:
        integration_path = plugin_utils.get_plugin_path(
            home, INTEGRATIONS, integration)
        plugin_utils.uninstall_plugin(integration_path, yes)
예제 #4
0
def test(ctx, integrations, editable):
    """Execute the integration's internal test method to verify it's working as intended."""
    logger.debug("running command %s (%s)",
                 ctx.command.name,
                 ctx.params,
                 extra={
                     "command": ctx.command.name,
                     "params": ctx.params
                 })

    home = ctx.obj["HOME"]

    for integration in integrations:
        integration_path = plugin_utils.get_plugin_path(
            home, INTEGRATIONS, integration, editable)

        logger.debug("loading {} ({})".format(integration, integration_path))
        integration = register_integration(integration_path)
        integration_module = get_integration_module(integration_path)

        if not integration.test_connection_enabled:
            raise click.ClickException(
                "Sorry, {} integration does not support testing.".format(
                    integration.name))

        try:
            with open(os.path.join(integration_path, ARGS_JSON)) as f:
                integration_args = json.loads(f.read())
        except IOError:
            raise click.ClickException(
                "Cannot load integration args, please configure it first.")
        logger.debug("testing integration {} with args {}".format(
            integration, integration_args))
        click.secho("[*] Testing {} with args {}".format(
            integration.name, integration_args))
        integration_obj = integration_module.IntegrationActionsClass(
            integration_args)

        success, response = integration_obj.test_connection(integration_args)
        if success:
            click.secho("Integration test: {}, Extra details: {}".format(
                "OK" if success else "FAIL", response))
        else:
            raise IntegrationTestFailed(response)
예제 #5
0
def configure(ctx, integration, args, show_args, editable):
    """Configure an integration with default parameters.

    You can still provide one-off integration arguments to :func:`honeycomb.commands.service.run` if required.
    """
    home = ctx.obj["HOME"]
    integration_path = plugin_utils.get_plugin_path(home, defs.INTEGRATIONS,
                                                    integration, editable)

    logger.debug("running command %s (%s)",
                 ctx.command.name,
                 ctx.params,
                 extra={
                     "command": ctx.command.name,
                     "params": ctx.params
                 })

    logger.debug("loading {} ({})".format(integration, integration_path))
    integration = register_integration(integration_path)

    if show_args:
        return plugin_utils.print_plugin_args(integration_path)

    # get our integration class instance
    integration_args = plugin_utils.parse_plugin_args(
        args, config_utils.get_config_parameters(integration_path))

    args_file = os.path.join(integration_path, defs.ARGS_JSON)
    with open(args_file, "w") as f:
        data = json.dumps(integration_args)
        logger.debug("writing %s to %s", data, args_file)
        f.write(json.dumps(integration_args))

    click.secho(
        "[*] {0} has been configured, make sure to test it with `honeycomb integration test {0}`"
        .format(integration.name))
예제 #6
0
def test(ctx, services, force, editable):
    """Execute the service's internal test method to verify it's working as intended.

    If there's no such method, honeycomb will attempt to connect to the port listed in config.json
    """
    logger.debug("running command %s (%s)", ctx.command.name, ctx.params,
                 extra={"command": ctx.command.name, "params": ctx.params})

    home = ctx.obj["HOME"]

    for service in services:
        service_path = plugin_utils.get_plugin_path(home, SERVICES, service, editable)

        logger.debug("loading {} ({})".format(service, service_path))
        service = register_service(service_path)
        service_module = get_service_module(service_path)

        if not force:
            if os.path.exists(service_path):
                pidfile = service_path + ".pid"
                if os.path.exists(pidfile):
                    try:
                        with open(pidfile) as fh:
                            pid = int(fh.read().strip())
                        os.kill(pid, 0)
                        logger.debug("service is running (pid: {})".format(pid))
                    except OSError:
                        logger.debug("service is not running (stale pidfile, pid: {})".format(pid), exc_info=True)
                        raise click.ClickException("Unable to test {} because it is not running".format(service.name))
                else:
                    logger.debug("service is not running (no pidfile)")
                    raise click.ClickException("Unable to test {} because it is not running".format(service.name))

        try:
            with open(os.path.join(service_path, ARGS_JSON)) as f:
                service_args = json.loads(f.read())
        except IOError as exc:
            logger.debug(str(exc), exc_info=True)
            raise click.ClickException("Cannot load service args, are you sure server is running?")
        logger.debug("loading service {} with args {}".format(service, service_args))
        service_obj = service_module.service_class(alert_types=service.alert_types, service_args=service_args)
        logger.debug("loaded service {}".format(service_obj))

        if hasattr(service_obj, "test"):
            click.secho("[+] Executing internal test method for service..")
            logger.debug("executing internal test method for service")
            event_types = service_obj.test()
            for event_type in event_types:
                try:
                    wait_until(search_json_log, filepath=os.path.join(home, DEBUG_LOG_FILE),
                               total_timeout=10, key=EVENT_TYPE, value=event_type)
                except TimeoutException:
                    raise click.ClickException("failed to test alert: {}".format(event_type))

                click.secho("{} alert tested successfully".format(event_type))

        elif hasattr(service, "ports") and len(service.ports) > 0:
            click.secho("[+] No internal test method found, only testing ports are open")
            logger.debug("no internal test method found, testing ports: {}".format(service.ports))
            for port in service.ports:
                socktype = socket.SOCK_DGRAM if port["protocol"] == "udp" else socket.SOCK_STREAM
                s = socket.socket(socket.AF_INET, socktype)
                try:
                    s.connect(("127.0.0.1", port["port"]))
                    s.shutdown(2)
                except Exception as exc:
                    logger.debug(str(exc), exc_info=True)
                    raise click.ClickException("Unable to connect to service port {}".format(port["port"]))
예제 #7
0
def show(ctx, integration, remote):
    """Show detailed information about a package."""
    logger.debug("running command %s (%s)", ctx.command.name, ctx.params,
                 extra={"command": ctx.command.name, "params": ctx.params})

    home = ctx.obj["HOME"]
    integration_path = plugin_utils.get_plugin_path(home, defs.INTEGRATIONS, integration)

    def collect_local_info(integration, integration_path):
        logger.debug("loading {} from {}".format(integration, integration_path))
        integration = register_integration(integration_path)
        try:
            with open(os.path.join(integration_path, "requirements.txt"), "r") as fh:
                info["requirements"] = " ".join(fh.readlines())
        except IOError:
            pass
        info["name"] = integration.name
        info["label"] = integration.label
        info["location"] = integration_path

        return info

    def collect_remote_info(integration):
        rsession = requests.Session()
        rsession.mount("https://", HTTPAdapter(max_retries=3))

        try:
            r = rsession.get(defs.GITHUB_RAW_URL.format(plugin_type=defs.INTEGRATIONS,
                                                        plugin=integration, filename="config.json"))
            integration_config = r.json()
            info["name"] = integration_config[DISPLAY_NAME]
            info["label"] = integration_config[defs.DESCRIPTION]
            info["location"] = defs.GITHUB_URL.format(plugin_type=defs.INTEGRATIONS, plugin=info["name"])
        except requests.exceptions.HTTPError as exc:
            logger.debug(str(exc), exc_info=True)
            raise click.ClickException("Cannot find package {}".format(integration))
        except requests.exceptions.ConnectionError as exc:
            logger.debug(str(exc), exc_info=True)
            raise click.ClickException("Unable to reach remote repository {}".format(integration))

        try:
            r = rsession.get(defs.GITHUB_RAW_URL.format(plugin_type=defs.INTEGRATIONS,
                             plugin=info["name"], filename="requirements.txt"))
            r.raise_for_status()
            info["requirements"] = " ".join(r.text.split("\n"))
        except requests.exceptions.HTTPError as exc:
            logger.debug(str(exc), exc_info=True)
            info["requirements"] = None
        except requests.exceptions.ConnectionError as exc:
            logger.debug(str(exc), exc_info=True)
            raise click.ClickException("Unable to reach remote repository {}".format(integration))

        return info

    info = {"commit_revision": "N/A", "commit_date": "N/A", "requirements": "None"}

    if os.path.exists(integration_path):
        info["installed"] = True
        if remote:
            click.secho("[*] Fetching info from online repository")
            info.update(collect_remote_info(integration))
        else:
            info.update(collect_local_info(integration, integration_path))
    else:
        logger.debug("cannot find {} locally".format(integration))
        if not remote:
            click.secho("[*] Cannot find integration locally, checking online repository")
        info["installed"] = False
        info.update(collect_remote_info(integration))
    logger.debug(info)
    click.secho(PKG_INFO_TEMPLATE.format(**info))
예제 #8
0
def run(ctx, service, args, show_args, daemon, editable, integration):
    """Load and run a specific service."""
    home = ctx.obj["HOME"]
    service_path = plugin_utils.get_plugin_path(home, SERVICES, service,
                                                editable)
    service_log_path = os.path.join(service_path, LOGS_DIR)

    logger.debug("running command %s (%s)",
                 ctx.command.name,
                 ctx.params,
                 extra={
                     "command": ctx.command.name,
                     "params": ctx.params
                 })

    logger.debug("loading {} ({})".format(service, service_path))
    service = register_service(service_path)

    if show_args:
        return plugin_utils.print_plugin_args(service_path)

    # get our service class instance
    service_module = get_service_module(service_path)
    service_args = plugin_utils.parse_plugin_args(
        args, config_utils.get_config_parameters(service_path))
    service_obj = service_module.service_class(alert_types=service.alert_types,
                                               service_args=service_args)

    if not os.path.exists(service_log_path):
        os.mkdir(service_log_path)

    # prepare runner
    if daemon:
        runner = myRunner(
            service_obj,
            pidfile=service_path + ".pid",
            stdout=open(os.path.join(service_log_path, STDOUTLOG), "ab"),
            stderr=open(os.path.join(service_log_path, STDERRLOG), "ab"))

        files_preserve = []
        for handler in logging.getLogger().handlers:
            if hasattr(handler, "stream"):
                if hasattr(handler.stream, "fileno"):
                    files_preserve.append(handler.stream.fileno())
            if hasattr(handler, "socket"):
                files_preserve.append(handler.socket.fileno())

        runner.daemon_context.files_preserve = files_preserve
        runner.daemon_context.signal_map.update({
            signal.SIGTERM:
            service_obj._on_server_shutdown,
            signal.SIGINT:
            service_obj._on_server_shutdown,
        })
        logger.debug("daemon_context",
                     extra={"daemon_context": vars(runner.daemon_context)})

    for integration_name in integration:
        integration_path = plugin_utils.get_plugin_path(
            home, INTEGRATIONS, integration_name, editable)
        configure_integration(integration_path)

    click.secho("[+] Launching {} {}".format(
        service.name, "in daemon mode" if daemon else ""))
    try:
        # save service_args for external reference (see test)
        with open(os.path.join(service_path, ARGS_JSON), "w") as f:
            f.write(json.dumps(service_args))
        runner._start() if daemon else service_obj.run()
    except KeyboardInterrupt:
        service_obj._on_server_shutdown()

    click.secho("[*] {} has stopped".format(service.name))