Exemplo n.º 1
0
def selftest_function(opts):
    """
    Placeholder for selftest function. An example use would be to test package api connectivity.
    Suggested return values are be unimplemented, success, or failure.
    """
    options = opts.get(SECTION_SCHEDULER, {})

    scheduler = None
    state = None
    reason = None
    try:
        scheduler = ResilientScheduler(options.get("db_url"),
                                       options.get("datastore_dir"),
                                       options.get("thread_max"),
                                       options.get("timezone"))

        job = scheduler.get_scheduler().add_job(myfunc, 'interval', minutes=2)
        job.remove()

        state = "success"
    except Exception as e:
        state = "failure"
        reason = str(e)
    finally:
        if scheduler:
            scheduler.get_scheduler().shutdown()

    return {"state": state, "reason": reason}
    def _create_a_schedule_function(self, event, *args, **kwargs):
        incident_id = kwargs.get("incident_id")  # number
        log.info("incident_id: %s", incident_id)

        try:
            rc = ResultPayload(SECTION_SCHEDULER, **kwargs)

            # Produce a FunctionResult with the results
            scheduler = ResilientScheduler.get_scheduler()
            jobs = scheduler.get_jobs()

            list_jobs = []

            for job in jobs:
                job_json = ResilientScheduler.sanitize_job(job)
                params = list(job_json['args'])

                if incident_id is None or incident_id == 0 or \
                    incident_id == params[0]:
                    list_jobs.append(job_json)

            log.debug(list_jobs)
            if not list_jobs:
                yield StatusMessage("No scheduled jobs")

            result = rc.done(True, list_jobs)
            yield FunctionResult(result)
        except Exception:
            yield FunctionError()
Exemplo n.º 3
0
    def __init__(self, opts):
        """constructor provides access to the configuration options"""
        super(FunctionComponent, self).__init__(opts)

        options = opts.get(SECTION_SCHEDULER, {})

        validate_fields(["datastore_dir", "thread_max", "timezone"], options)

        self.res_scheduler = ResilientScheduler(options.get("datastore_dir"),
                                                options.get("thread_max"),
                                                options.get("timezone"))
    def __init__(self, opts):
        global RESILIENT_CONNECTION
        """constructor provides access to the configuration options"""
        super(FunctionComponent, self).__init__(opts)

        RESILIENT_CONNECTION = opts.get(SECTION_RESILIENT, {})

        options = opts.get(SECTION_SCHEDULER, {})

        validate_app_config(options)

        self.res_scheduler = ResilientScheduler(options.get("db_url"),
                                                options.get("datastore_dir"),
                                                options.get("thread_max"),
                                                options.get("timezone"))
Exemplo n.º 5
0
    def test_success(self, mock_get_incident, mock_get_rules, circuits_app,
                     scheduler_type, scheduler_type_value, scheduler_rule_name,
                     scheduler_rule_parameters, scheduler_label_prefix,
                     incident_id, object_id, row_id, expected_results):
        """ Test calling with sample values for the parameters """
        setup_mock_incident(mock_get_incident)
        setup_mock_actions(mock_get_rules)

        rule_label = u"{}_{}".format(scheduler_label_prefix, yyyymmdd)

        if scheduler_type == "date":
            dt = ResilientScheduler.get_interval("2h", date=True)
            scheduler_type_value = dt.strftime('%Y-%m-%d %H:%M:%S')

        function_params = {
            "scheduler_type": scheduler_type,
            "scheduler_type_value": scheduler_type_value,
            "scheduler_rule_name": scheduler_rule_name,
            "scheduler_rule_parameters": scheduler_rule_parameters,
            "scheduler_label_prefix": rule_label,
            "incident_id": incident_id,
            "object_id": object_id,
            "row_id": row_id
        }
        results = call_create_a_scheduled_rule_function(
            circuits_app, function_params)
        assert results['success']
    def __init__(self, opts):
        """constructor provides access to the configuration options"""
        super(FunctionComponent, self).__init__(opts)

        options = opts.get(SECTION_SCHEDULER, {})
        self.validate_app_config(options)
        self.timezone = options.get("timezone")

        self.scheduler = ResilientScheduler(options.get("datastore_dir"),
                                            options.get("thread_max"),
                                            options.get("timezone"))
        log.info("Scheduler started")
    def find_job_by_label(self, scheduler_label):
        """
        find the job by it's label
        :param scheduler_label:
        :return: job found or None
        """
        scheduler = ResilientScheduler.get_scheduler()
        jobs = scheduler.get_jobs()

        for job in jobs:
            if job.id.lower() == scheduler_label.lower():
                return job

        return None
Exemplo n.º 8
0
    def _remove_a_scheduled_job(self, event, *args, **kwargs):
        try:
            scheduler_label = kwargs.get("scheduler_label")  # text
            log.info(u"scheduler_label: %s", scheduler_label)
            validate_fields(["scheduler_label"], kwargs)

            rc = ResultPayload(SECTION_SCHEDULER, **kwargs)

            scheduler = ResilientScheduler.get_scheduler()

            try:
                scheduler.remove_job(scheduler_label)
                log.info(u"Rule '{}' deleted".format(scheduler_label))

                yield StatusMessage("Scheduled rule removed")
                result = rc.done(True, None)
            except JobLookupError:
                yield StatusMessage("Scheduled rule not found")
                result = rc.done(False, None)

            yield FunctionResult(result)
        except Exception:
            yield FunctionError()
    def _scheduled_rule_resume_function(self, event, *args, **kwargs):
        """Function: Resume a scheduled job"""
        try:
            # Get the function parameters:
            scheduler_label = kwargs.get("scheduler_label")  # text

            log = logging.getLogger(__name__)
            log.info("scheduler_label: %s", scheduler_label)

            rc = ResultPayload(SECTION_SCHEDULER, **kwargs)

            job = self.find_job_by_label(scheduler_label)
            if job is None:
                raise KeyError("Job not found: {}".format(scheduler_label))

            job.resume()
            yield StatusMessage("Job resumed: {}".format(scheduler_label))

            results = rc.done(True, ResilientScheduler.sanitize_job(job))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
Exemplo n.º 10
0
    def _create_a_schedule_function(self, event, *args, **kwargs):
        """Function: Schedule a rule to run on a schedule. This rule will be executed for a given incident, artifact, task, etc."""
        try:
            # Get the function parameters:
            scheduler_type = self.get_select_param(
                kwargs.get("scheduler_type"
                           ))  # select, values: "cron", "interval", "date"
            scheduler_type_value = kwargs.get("scheduler_type_value")  # text
            scheduler_rule_name = kwargs.get("scheduler_rule_name")  # text
            scheduler_rule_parameters = kwargs.get(
                "scheduler_rule_parameters")  # text
            scheduler_label_prefix = kwargs.get(
                "scheduler_label_prefix")  # text

            incident_id = kwargs.get("incident_id")  # number
            object_id = kwargs.get("object_id")  # number
            # row_id is presently unavailable from a pre-proessing script.
            # A future change to resilient is needed to allow this natively. Presently, supplying this information manually is needed
            row_id = kwargs.get("row_id")  # number

            if row_id:
                object_id = event.message["workflow"]["object_type"]['id']

            object_type_id = event.message["workflow"]["object_type"]['id']
            object_type_name = event.message["workflow"]["object_type"]['name']

            scheduler_label_prefix = "{}-{}".format(scheduler_label_prefix,
                                                    incident_id)

            log.info("scheduler_type: %s", scheduler_type)
            log.info("scheduler_type_value: %s", scheduler_type_value)
            log.info("scheduler_rule_name: %s", scheduler_rule_name)
            log.info("scheduler_rule_parameters: %s",
                     scheduler_rule_parameters)
            log.info("scheduler_label_prefix: %s", scheduler_label_prefix)

            log.info("incident_id: %s", incident_id)
            log.info("object_id: %s", object_id)
            log.info("row_id: %s", row_id)

            # get the rule id
            rest_client = self.rest_client()

            # make sure incident isn't closed
            resp = get_incident(rest_client, incident_id)
            if not resp.get("success", True):
                raise FunctionError(
                    "Incident {} not found".format(incident_id))

            if not resp or resp['end_date'] is not None:
                raise FunctionError("Incident is closed")

            # get the rule id
            rule_id, rule_object_type_id = get_rule_by_name(
                rest_client, scheduler_rule_name.strip(' '))
            if not rule_id:
                raise ValueError(u"Rule name not found: %s",
                                 scheduler_rule_name)

            if object_type_id != rule_object_type_id:
                raise ValueError(u"Rule does not match the action object: %s",
                                 object_type_name)

            rc = ResultPayload(SECTION_SCHEDULER, **kwargs)

            rule_params = None
            if scheduler_rule_parameters:
                rule_params = self.validate_rule_parameters(
                    scheduler_rule_parameters)

            incident_data = [
                incident_id, object_id, row_id, scheduler_label_prefix,
                scheduler_rule_name, rule_id, rule_object_type_id, rule_params,
                self.opts[SECTION_RESILIENT]
            ]

            # validate the type and type_value
            trigger = self.res_scheduler.build_trigger(scheduler_type,
                                                       scheduler_type_value)

            # a d d   j o b
            scheduler = ResilientScheduler.get_scheduler()
            scheduled_job = scheduler.add_job(triggered_job,
                                              trigger,
                                              id=scheduler_label_prefix,
                                              args=incident_data,
                                              kwargs=rule_params)

            log.debug(u"Scheduled_job: {}".format(scheduled_job))

            yield StatusMessage("Rule scheduled")

            # convert for results
            job = scheduled_job.__getstate__()
            job['next_run_time'] = self.res_scheduler.get_str_date(
                job['next_run_time'])
            job['trigger'] = None
            # clear args which contain passwords ([resilient])
            job = ResilientScheduler.clean_password(job)

            results = rc.done(True, job)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
Exemplo n.º 11
0
class FunctionComponent(ResilientComponent):
    """Component that implements Resilient function 'create_a_scheduled_job"""
    def __init__(self, opts):
        """constructor provides access to the configuration options"""
        super(FunctionComponent, self).__init__(opts)

        options = opts.get(SECTION_SCHEDULER, {})

        validate_fields(["datastore_dir", "thread_max", "timezone"], options)

        self.res_scheduler = ResilientScheduler(options.get("datastore_dir"),
                                                options.get("thread_max"),
                                                options.get("timezone"))

    @function("create_a_scheduled_rule")
    def _create_a_schedule_function(self, event, *args, **kwargs):
        """Function: Schedule a rule to run on a schedule. This rule will be executed for a given incident, artifact, task, etc."""
        try:
            # Get the function parameters:
            scheduler_type = self.get_select_param(
                kwargs.get("scheduler_type"
                           ))  # select, values: "cron", "interval", "date"
            scheduler_type_value = kwargs.get("scheduler_type_value")  # text
            scheduler_rule_name = kwargs.get("scheduler_rule_name")  # text
            scheduler_rule_parameters = kwargs.get(
                "scheduler_rule_parameters")  # text
            scheduler_label_prefix = kwargs.get(
                "scheduler_label_prefix")  # text

            incident_id = kwargs.get("incident_id")  # number
            object_id = kwargs.get("object_id")  # number
            # row_id is presently unavailable from a pre-proessing script.
            # A future change to resilient is needed to allow this natively. Presently, supplying this information manually is needed
            row_id = kwargs.get("row_id")  # number

            if row_id:
                object_id = event.message["workflow"]["object_type"]['id']

            object_type_id = event.message["workflow"]["object_type"]['id']
            object_type_name = event.message["workflow"]["object_type"]['name']

            scheduler_label_prefix = "{}-{}".format(scheduler_label_prefix,
                                                    incident_id)

            log.info("scheduler_type: %s", scheduler_type)
            log.info("scheduler_type_value: %s", scheduler_type_value)
            log.info("scheduler_rule_name: %s", scheduler_rule_name)
            log.info("scheduler_rule_parameters: %s",
                     scheduler_rule_parameters)
            log.info("scheduler_label_prefix: %s", scheduler_label_prefix)

            log.info("incident_id: %s", incident_id)
            log.info("object_id: %s", object_id)
            log.info("row_id: %s", row_id)

            # get the rule id
            rest_client = self.rest_client()

            # make sure incident isn't closed
            resp = get_incident(rest_client, incident_id)
            if not resp.get("success", True):
                raise FunctionError(
                    "Incident {} not found".format(incident_id))

            if not resp or resp['end_date'] is not None:
                raise FunctionError("Incident is closed")

            # get the rule id
            rule_id, rule_object_type_id = get_rule_by_name(
                rest_client, scheduler_rule_name.strip(' '))
            if not rule_id:
                raise ValueError(u"Rule name not found: %s",
                                 scheduler_rule_name)

            if object_type_id != rule_object_type_id:
                raise ValueError(u"Rule does not match the action object: %s",
                                 object_type_name)

            rc = ResultPayload(SECTION_SCHEDULER, **kwargs)

            rule_params = None
            if scheduler_rule_parameters:
                rule_params = self.validate_rule_parameters(
                    scheduler_rule_parameters)

            incident_data = [
                incident_id, object_id, row_id, scheduler_label_prefix,
                scheduler_rule_name, rule_id, rule_object_type_id, rule_params,
                self.opts[SECTION_RESILIENT]
            ]

            # validate the type and type_value
            trigger = self.res_scheduler.build_trigger(scheduler_type,
                                                       scheduler_type_value)

            # a d d   j o b
            scheduler = ResilientScheduler.get_scheduler()
            scheduled_job = scheduler.add_job(triggered_job,
                                              trigger,
                                              id=scheduler_label_prefix,
                                              args=incident_data,
                                              kwargs=rule_params)

            log.debug(u"Scheduled_job: {}".format(scheduled_job))

            yield StatusMessage("Rule scheduled")

            # convert for results
            job = scheduled_job.__getstate__()
            job['next_run_time'] = self.res_scheduler.get_str_date(
                job['next_run_time'])
            job['trigger'] = None
            # clear args which contain passwords ([resilient])
            job = ResilientScheduler.clean_password(job)

            results = rc.done(True, job)

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()

    def validate_rule_parameters(self, rule_params):
        """
        should be json formatted string
        :param rule_params: name=value;name=value
        :return: json data
        """
        params = {}
        if rule_params:
            for items in rule_params.split(';'):
                # improperly formatted parameters will fail with KeyError
                k, v = items.split('=')
                params[k.strip(' ').lower()] = v.strip(' ')

        return params
Exemplo n.º 12
0
def triggered_job(incident_id, object_id, row_id, scheduler_label, rule_name,
                  rule_id, rule_object_type_id, rule_params, opts, **kwargs):
    """
    This function is called when a scheduled rule is triggered. It is run asynchronous of the create_scheduled_rule process.
    It's role is to build the api call-back to Resilient to run the rule.
    In addition to invoking a rule, a note is added to the incideent to indicate that a scheduled rule was run.
    :param incident_id:
    :param object_id: task_id, note_id, artifact_id, etc.
    :param row_id: used when object_id is a datatable_id
    :param scheduler_label:
    :param rule_name:
    :param rule_id:
    :param rule_object_type_id: internal id referring to incident, task, artifact, etc.
    :param rule_params:
    :param opts: contains [resilient] parameters needed to connect back to Resilient for API calls
    :param kwargs: catch all for additional arguments as necessary
    :return: None
    """
    log.debug(incident_id)
    log.debug(rule_id)
    log.debug(rule_object_type_id)
    log.debug(rule_params)
    log.debug(kwargs)

    # get the rest client
    rest_client = get_resilient_client(opts)
    scheduler = ResilientScheduler.get_scheduler()

    # make sure the incident is still open and not deleted
    try:
        resp = get_incident(rest_client, incident_id)
    except SimpleHTTPException:
        resp = None

    if not resp or resp['end_date'] is not None:
        log.warning(
            u"Incident %s is not found or closed. Removing scheduled rule: %s",
            incident_id, rule_name)
        scheduler.remove_job(scheduler_label)
        return

    # make sure the rule is still enabled
    try:
        get_rule_by_id(rest_client, rule_id)
    except KeyError as err:
        # remove rules which no longer exist
        log.error(u"Rule '%s' not found and schedule will be removed.",
                  rule_name)
        add_comment(
            rest_client, incident_id,
            u"Error running rule '{}': {}".format(scheduler_label, str(err)))
        scheduler.remove_job(scheduler_label)
        return

    # build url for invoking a rule
    rule_type = lookup_object_type(rest_client, rule_object_type_id)
    if rule_type == "tasks":
        url = "/{}/{}".format(rule_type, object_id)
    else:
        url = "/incidents/{}".format(incident_id)

        if rule_type != '':
            url = url + "/{}/{}".format(rule_type, object_id)

    if row_id:
        url = url + "/row_data/{}".format(row_id)

    url = url + "/action_invocations"

    # build the JSON for rule
    payload = {"action_id": rule_id, "properties": rule_params}

    log.info("Executing Rule '{}:{}' for Incident {}".format(
        scheduler_label, rule_name, incident_id))

    # run the rule
    try:
        resp = rest_client.post(url, payload)
        log.debug(resp)
    except SimpleHTTPException as err:
        # is the object removed?
        if "Not Found" in str(err):
            log.error(
                "Object not found and schedule will be removed for rule '%s'",
                rule_id)
            add_comment(
                rest_client, incident_id,
                u"Error running rule '{}': {}".format(scheduler_label,
                                                      str(err)))
            scheduler.remove_job(scheduler_label)
            return

    if rule_type:
        add_comment(
            rest_client, incident_id,
            u"Scheduled job '{}' run on {}: {}".format(rule_name, rule_type,
                                                       object_id))
    else:
        add_comment(rest_client, incident_id,
                    u"Scheduled job '{}' run on incident".format(rule_name))