Beispiel #1
0
    def setUp(self):
        super(TestReader, self).setUp()

        mongo = MongoStore.get_default()
        collection = mongo.get_collection("default_testpbehavior")
        pb_coll = MongoCollection(collection)

        self.logger = Logger.get('alertsreader', '/tmp/null')
        conf = Configuration.load(PBehaviorManager.CONF_PATH, Ini)
        self.pbehavior_manager = PBehaviorManager(config=conf,
                                                  logger=self.logger,
                                                  pb_collection=pb_coll)

        self.reader = AlertsReader(config=conf,
                                   logger=self.logger,
                                   storage=self.manager.alerts_storage,
                                   pbehavior_manager=self.pbehavior_manager)

        self.reader._alarm_fields = {
            'properties': {
                'connector': {
                    'stored_name': 'v.ctr'
                },
                'component': {
                    'stored_name': 'v.cpt'
                },
                'entity_id': {
                    'stored_name': 'd'
                }
            }
        }
Beispiel #2
0
    def setUp(self):
        super(TestReader, self).setUp()
        self.pb_storage = Middleware.get_middleware_by_uri(
            PBehaviorManager.PB_STORAGE_URI
        )

        self.logger = Logger.get('alertsreader', '/tmp/null')
        conf = Configuration.load(PBehaviorManager.CONF_PATH, Ini)
        self.pbehavior_manager = PBehaviorManager(config=conf,
                                                  logger=self.logger,
                                                  pb_storage=self.pb_storage)

        self.reader = AlertsReader(config=conf,
                                   logger=self.logger,
                                   storage=self.manager.alerts_storage,
                                   pbehavior_manager=self.pbehavior_manager)

        self.reader._alarm_fields = {
            'properties': {
                'connector': {'stored_name': 'v.ctr'},
                'component': {'stored_name': 'v.cpt'},
                'entity_id': {'stored_name': 'd'}
            }
        }
Beispiel #3
0
from __future__ import unicode_literals

from canopsis.alarms.adapters import AlarmAdapter
from canopsis.alarms.services import AlarmService
from canopsis.alerts.manager import Alerts
from canopsis.alerts.reader import AlertsReader
from canopsis.task.core import register_task
from canopsis.watcher.manager import Watcher
from canopsis.common.mongo_store import MongoStore

# import this module so tasks are registered in canopsis.tasks.core
import canopsis.alerts.tasks as __alerts_tasks

work_alerts_manager = Alerts(*Alerts.provide_default_basics())
beat_alerts_manager = Alerts(*Alerts.provide_default_basics())
alertsreader_manager = AlertsReader(*AlertsReader.provide_default_basics())

mongo_store = MongoStore.get_default()


@register_task
def event_processing(engine, event, alertsmgr=None, **kwargs):
    """
    AMQP Event processing.
    """
    if alertsmgr is None:
        alertsmgr = work_alerts_manager

    encoded_event = {}

    for key, value in event.items():
Beispiel #4
0
def exports(ws):

    ws.application.router.add_filter('id_filter', id_filter)

    context_manager = ContextGraph(ws.logger)
    am = Alerts(*Alerts.provide_default_basics())
    ar = AlertsReader(*AlertsReader.provide_default_basics())
    ma_rule_manager = MetaAlarmRuleManager(
        *MetaAlarmRuleManager.provide_default_basics())
    pbm = PBehaviorManager(*PBehaviorManager.provide_default_basics())

    @route(ws.application.get,
           name='alerts/get-alarms',
           payload=[
               'authkey', 'tstart', 'tstop', 'opened', 'resolved', 'lookups',
               'filter', 'search', 'sort_key', 'sort_dir', 'skip', 'limit',
               'with_steps', 'natural_search', 'active_columns',
               'hide_resources', 'with_consequences', 'with_causes',
               'correlation'
           ])
    def get_alarms(authkey=None,
                   tstart=None,
                   tstop=None,
                   opened=True,
                   resolved=False,
                   lookups=[],
                   filter={},
                   search='',
                   sort_key='opened',
                   sort_dir='DESC',
                   skip=0,
                   limit=None,
                   with_steps=False,
                   natural_search=False,
                   active_columns=None,
                   hide_resources=False,
                   with_consequences=False,
                   with_causes=False,
                   correlation=False):
        """
        Return filtered, sorted and paginated alarms.

        :param tstart: Beginning timestamp of requested period
        :param tstop: End timestamp of requested period
        :type tstart: int or None
        :type tstop: int or None

        :param bool opened: If True, consider alarms that are currently opened
        :param bool resolved: If True, consider alarms that have been resolved

        :param list lookups: List of extra columns to compute for each
          returned alarm. Extra columns are "pbehaviors".

        :param dict filter: Mongo filter. Keys are UI column names.
        :param str search: Search expression in custom DSL

        :param str sort_key: Name of the column to sort
        :param str sort_dir: Either "ASC" or "DESC"

        :param int skip: Number of alarms to skip (pagination)
        :param int limit: Maximum number of alarms to return

        :param list active_columns: list of active columns on the brick
        listalarm .

        :param bool hide_resources: hide_resources if component has an alarm

        :returns: List of sorted alarms + pagination informations
        :rtype: dict
        """
        if isinstance(search, int):
            search = str(search)

        try:
            alarms = ar.get(tstart=tstart,
                            tstop=tstop,
                            opened=opened,
                            resolved=resolved,
                            lookups=lookups,
                            filter_=filter,
                            search=search.strip(),
                            sort_key=sort_key,
                            sort_dir=sort_dir,
                            skip=skip,
                            limit=limit,
                            with_steps=with_steps,
                            natural_search=natural_search,
                            active_columns=active_columns,
                            hide_resources=hide_resources,
                            with_consequences=with_consequences,
                            correlation=correlation)
        except OperationFailure as of_err:
            message = 'Operation failure on get-alarms: {}'.format(of_err)
            raise WebServiceError(message)

        alarms_ids, consequences_children = [], []
        alarm_children = {'alarms': [], 'total': 0}
        for alarm in alarms['alarms']:
            if with_consequences:
                consequences_children.extend(
                    alarm.get('consequences', {}).get('data', []))
            elif with_causes and alarm.get('v') and alarm['v'].get('parents'):
                consequences_children.extend(alarm['v']['parents'])
            tmp_id = alarm.get('d')
            if tmp_id:
                alarms_ids.append(tmp_id)
        entities = context_manager.get_entities_by_id(alarms_ids,
                                                      with_links=False)

        entity_dict = {}
        for entity in entities:
            entity_dict[entity.get('_id')] = entity

        if consequences_children:
            alarm_children = ar.get(
                tstart=tstart,
                tstop=tstop,
                opened=True,
                resolved=True,
                lookups=lookups,
                filter_={'d': {
                    '$in': consequences_children
                }},
                sort_key=sort_key,
                sort_dir=sort_dir,
                skip=skip,
                limit=None,
                natural_search=natural_search,
                active_columns=active_columns,
                hide_resources=hide_resources,
                correlation=correlation,
                consequences_children=True)

        list_alarm = []
        rule_ids = set()
        if 'rules' in alarms:
            for alarm_rules in alarms['rules'].values():
                for v in alarm_rules:
                    rule_ids.add(v)
            named_rules = ma_rule_manager.read_rules_with_names(list(rule_ids))
            for d, alarm_rules in alarms['rules'].items():
                alarm_named_rules = []
                for v in alarm_rules:
                    alarm_named_rules.append({
                        'id': v,
                        'name': named_rules.get(v, "")
                    })
                alarms['rules'][d] = alarm_named_rules
        else:
            alarms['rules'] = dict()

        children_ent_ids = set()
        for alarm in alarms['alarms']:
            rules = alarms['rules'].get(alarm['d'], []) if 'd' in alarm and 'v' in alarm and \
                alarm['v'].get('parents') else None
            if rules:
                if with_causes:
                    alarm['causes'] = {
                        'total': len(alarm_children['alarms']),
                        'data': alarm_children['alarms'],
                    }
                    for al_child in alarm_children['alarms']:
                        children_ent_ids.add(al_child['d'])
                else:
                    alarm['causes'] = {
                        'total': len(rules),
                        'rules': rules,
                    }

            if alarm.get('v') is None:
                alarm['v'] = dict()
            if alarm.get('v').get('meta'):
                del alarm['v']['meta']

            if isinstance(alarm.get('rule'),
                          basestring) and alarm['rule'] != "":
                alarm['rule'] = {
                    'id': alarm['rule'],
                    'name': named_rules.get(alarm['rule'], alarm['rule'])
                }

            now = int(time())

            alarm_end = alarm.get('v', {}).get('resolved')
            if not alarm_end:
                alarm_end = now
            alarm["v"]['duration'] = (
                alarm_end - alarm.get('v', {}).get('creation_date', alarm_end))

            state_time = alarm.get('v', {}).get('state', {}).get('t', now)
            alarm["v"]['current_state_duration'] = now - state_time
            tmp_entity_id = alarm['d']

            if alarm['d'] in entity_dict:
                alarm[
                    'links'] = context_manager.enrich_links_to_entity_with_alarm(
                        entity_dict[alarm['d']], alarm)

                # TODO: 'infos' is already present in entity.
                # Remove this one if unused.
                if tmp_entity_id in entity_dict:
                    data = entity_dict[alarm['d']]['infos']
                    if alarm.get('infos'):
                        alarm['infos'].update(data)
                    else:
                        alarm['infos'] = data

            alarm = compat_go_crop_states(alarm)

            if with_consequences and isinstance(
                    alarm.get('consequences'),
                    dict) and alarm_children['total'] > 0:
                map(
                    lambda al_ch: al_ch.update(
                        {'causes': {
                            'rules': [alarm['rule']],
                            'total': 1
                        }}), alarm_children['alarms'])
                alarm['consequences']['data'] = alarm_children['alarms']
                alarm['consequences']['total'] = alarm_children['total']
                for al_child in alarm_children['alarms']:
                    children_ent_ids.add(al_child['d'])

            list_alarm.append(alarm)

        if children_ent_ids:
            children_entities = context_manager.get_entities_by_id(
                list(children_ent_ids), with_links=False)
            for entity in children_entities:
                entity_dict[entity.get('_id')] = entity

            for alarm in alarms['alarms']:
                for cat in ('causes', 'consequences'):
                    if cat in alarm and alarm[cat].get('data'):
                        for child in alarm[cat]['data']:
                            if child['d'] in entity_dict:
                                child[
                                    'links'] = context_manager.enrich_links_to_entity_with_alarm(
                                        entity_dict[child['d']], child)

        del alarms['rules']
        alarms['alarms'] = list_alarm

        return alarms

    @route(ws.application.get,
           name='alerts/get-counters',
           payload=[
               'tstart', 'tstop', 'opened', 'resolved', 'lookups', 'filter',
               'search', 'sort_key', 'sort_dir', 'skip', 'limit', 'with_steps',
               'natural_search', 'active_columns', 'hide_resources'
           ])
    def get_counters(tstart=None,
                     tstop=None,
                     opened=True,
                     resolved=False,
                     lookups=[],
                     filter={},
                     search='',
                     sort_key='opened',
                     sort_dir='DESC',
                     skip=0,
                     limit=None,
                     with_steps=False,
                     natural_search=False,
                     active_columns=None,
                     hide_resources=False):

        if isinstance(search, int):
            search = str(search)

        try:
            alarms = ar.get(tstart=tstart,
                            tstop=tstop,
                            opened=opened,
                            resolved=resolved,
                            lookups=lookups,
                            filter_=filter,
                            search=search.strip(),
                            sort_key=sort_key,
                            sort_dir=sort_dir,
                            skip=skip,
                            limit=limit,
                            with_steps=with_steps,
                            natural_search=natural_search,
                            active_columns=active_columns,
                            hide_resources=hide_resources,
                            add_pbh_filter=False)
        except OperationFailure as of_err:
            message = 'Operation failure on get-alarms: {}'.format(of_err)
            raise WebServiceError(message)

        counters = {
            "total": len(alarms['alarms']),
            "total_active": 0,
            "snooze": 0,
            "ack": 0,
            "ticket": 0,
            "pbehavior_active": 0
        }

        alarms_ids = []
        for alarm in alarms['alarms']:
            tmp_id = alarm.get('d')
            if tmp_id:
                alarms_ids.append(tmp_id)
        entities = context_manager.get_entities_by_id(alarms_ids,
                                                      with_links=True)
        entity_id = []
        for entity in entities:
            _id = entity.get('_id')
            if _id:
                entity_id.append(_id)

        active_pbh = pbm.get_active_pbehaviors_on_entities(entity_id)
        enabled_pbh_entity_dict = set()
        for pbh in active_pbh:
            if pbh[PBehavior.ENABLED]:
                for eid in pbh.get(PBehavior.EIDS, []):
                    if eid in entity_id:
                        enabled_pbh_entity_dict.add(eid)

        pbehavior_active_snooze = 0

        for alarm in alarms['alarms']:
            v = alarm.get('v')
            snoozed = False
            if isinstance(v, dict):
                if v.get('ack', {}).get('_t') == 'ack':
                    counters['ack'] += 1
                snoozed = v.get('snooze', {}).get('_t') == 'snooze'
                if snoozed:
                    counters['snooze'] += 1
                if v.get('ticket',
                         {}).get('_t') in ['declareticket', 'assocticket']:
                    counters['ticket'] += 1
            d = alarm.get('d')
            if d in enabled_pbh_entity_dict:
                counters['pbehavior_active'] += 1
                if snoozed:
                    pbehavior_active_snooze += 1

        counters['total_active'] = counters['total'] - counters['pbehavior_active'] - counters['snooze'] + \
            pbehavior_active_snooze
        return counters

    @route(ws.application.get,
           name='alerts/search/validate',
           payload=['expression'])
    def validate_search(expression):
        """
        Tell if a search expression is valid from a grammatical propespective.

        :param str expression: Search expression

        :returns: True if valid, False otherwise
        :rtype: bool
        """

        try:
            ar.interpret_search(expression)

        except Exception:
            return False

        else:
            return True

    @route(
        ws.application.get,
        name='alerts/count',
        payload=['start', 'stop', 'limit', 'select'],
    )
    def count_by_period(
        start,
        stop,
        limit=100,
        select=None,
    ):
        """
        Count alarms that have been opened during (stop - start) period.

        :param start: Beginning timestamp of period
        :type start: int

        :param stop: End timestamp of period
        :type stop: int

        :param limit: Counts cannot exceed this value
        :type limit: int

        :param query: Custom mongodb filter for alarms
        :type query: dict

        :return: List in which each item contains a time interval and the
                 related count
        :rtype: list
        """

        return ar.count_alarms_by_period(
            start,
            stop,
            limit=limit,
            query=select,
        )

    @route(
        ws.application.get,
        name='alerts/get-current-alarm',
        payload=['entity_id'],
    )
    def get_current_alarm(entity_id):
        """
        Get current unresolved alarm for a entity.

        :param str entity_id: Entity ID of the alarm

        :returns: Alarm as dict if something is opened, else None
        """

        return am.get_current_alarm(entity_id)

    @ws.application.get('/api/v2/alerts/filters/<entity_id:id_filter>')
    def get_filter(entity_id):
        """
        Get all filters linked with an alarm.

        :param str entity_id: Entity ID of the alarm-filter

        :returns: a list of <AlarmFilter>
        """
        filters = am.alarm_filters.get_filter(entity_id)
        if filters is None:
            return gen_json_error({'description': 'nothing to return'},
                                  HTTP_ERROR)

        return gen_json([l.serialize() for l in filters])

    @ws.application.post('/api/v2/alerts/filters')
    def create_filter():
        """
        Create a new alarm filter.

        :returns: an <AlarmFilter>
        """
        # element is a full AlarmFilter (dict) to insert
        element = request.json

        if element is None:
            return gen_json_error({'description': 'nothing to insert'},
                                  HTTP_ERROR)

        new = am.alarm_filters.create_filter(element=element)
        new.save()

        return gen_json(new.serialize())

    @ws.application.put('/api/v2/alerts/filters/<entity_id:id_filter>')
    def update_filter(entity_id):
        """
        Update an existing alam filter.

        :param entity_id: Entity ID of the alarm-filter
        :type entity_id: str
        :returns: <AlarmFilter>
        :rtype: dict
        """
        dico = request.json

        if dico is None or not isinstance(dico, dict) or len(dico) <= 0:
            return gen_json_error({'description': 'wrong update dict'},
                                  HTTP_ERROR)

        af = am.alarm_filters.update_filter(filter_id=entity_id, values=dico)
        if not isinstance(af, AlarmFilter):
            return gen_json_error({'description': 'failed to update filter'},
                                  HTTP_ERROR)

        return gen_json(af.serialize())

    @ws.application.delete('/api/v2/alerts/filters/<entity_id:id_filter>')
    def delete_id(entity_id):
        """
        Delete a filter, based on his id.

        :param entity_id: Entity ID of the alarm-filter
        :type entity_id: str

        :rtype: dict
        """
        ws.logger.info('Delete alarm-filter : {}'.format(entity_id))

        return gen_json(am.alarm_filters.delete_filter(entity_id))

    @ws.application.delete('/api/v2/alerts/<mfilter>')
    def delete_filter(mfilter):
        """
        :param str mfilter: mongo filter
        :rtype: dict
        """
        return gen_json(ar.alarm_storage._backend.remove(json.loads(mfilter)))

    @ws.application.post('/api/v2/alerts/done')
    def done_action():
        """
        Trigger done action.

        For json payload, see doc/docs/fr/guide_developpeur/apis/v2/alerts.md

        :rtype: dict
        """
        dico = request.json

        if dico is None or not isinstance(dico, dict) or len(dico) <= 0:
            return gen_json_error({'description': 'wrong done dict'},
                                  HTTP_ERROR)

        author = dico.get(am.AUTHOR)
        event = forger(event_type=Check.EVENT_TYPE,
                       author=author,
                       connector=dico.get('connector'),
                       connector_name=dico.get('connector_name'),
                       component=dico.get('component'),
                       output=dico.get('comment'))
        if dico.get('source_type', None) == 'resource':
            event['resource'] = dico['resource']
            event['source_type'] = 'resource'
        ws.logger.debug('Received done action: {}'.format(event))

        entity_id = am.context_manager.get_id(event)
        retour = am.execute_task('alerts.useraction.done',
                                 event=event,
                                 author=author,
                                 entity_id=entity_id)
        return gen_json(retour)
Beispiel #5
0
from __future__ import unicode_literals

from canopsis.alarms.adapters import AlarmAdapter
from canopsis.alarms.services import AlarmService
from canopsis.alerts.manager import Alerts
from canopsis.alerts.reader import AlertsReader
from canopsis.task.core import register_task
from canopsis.watcher.manager import Watcher
from canopsis.common.mongo_store import MongoStore

# import this module so tasks are registered in canopsis.tasks.core
import canopsis.alerts.tasks as __alerts_tasks

work_alerts_manager = Alerts(*Alerts.provide_default_basics())
beat_alerts_manager = Alerts(*Alerts.provide_default_basics())
alertsreader_manager = AlertsReader(*AlertsReader.provide_default_basics())

mongo_store = MongoStore.get_default()

@register_task
def event_processing(engine, event, alertsmgr=None, **kwargs):
    """
    AMQP Event processing.
    """
    if alertsmgr is None:
        alertsmgr = work_alerts_manager

    encoded_event = {}

    for key, value in event.items():
        try:
Beispiel #6
0
def exports(ws):

    ws.application.router.add_filter('id_filter', id_filter)

    context_manager = ContextGraph(ws.logger)
    am = Alerts(*Alerts.provide_default_basics())
    ar = AlertsReader(*AlertsReader.provide_default_basics())

    @route(
        ws.application.get,
        name='alerts/get-alarms',
        payload=[
            'tstart',
            'tstop',
            'opened',
            'resolved',
            'lookups',
            'filter',
            'search',
            'sort_key',
            'sort_dir',
            'skip',
            'limit',
            'with_steps',
            'natural_search',
            'active_columns',
            'hide_resources'
        ]
    )
    def get_alarms(
            tstart=None,
            tstop=None,
            opened=True,
            resolved=False,
            lookups=[],
            filter={},
            search='',
            sort_key='opened',
            sort_dir='DESC',
            skip=0,
            limit=50,
            with_steps=False,
            natural_search=False,
            active_columns=None,
            hide_resources=False
    ):
        """
        Return filtered, sorted and paginated alarms.

        :param tstart: Beginning timestamp of requested period
        :param tstop: End timestamp of requested period
        :type tstart: int or None
        :type tstop: int or None

        :param bool opened: If True, consider alarms that are currently opened
        :param bool resolved: If True, consider alarms that have been resolved

        :param list lookups: List of extra columns to compute for each
          returned alarm. Extra columns are "pbehaviors".

        :param dict filter: Mongo filter. Keys are UI column names.
        :param str search: Search expression in custom DSL

        :param str sort_key: Name of the column to sort
        :param str sort_dir: Either "ASC" or "DESC"

        :param int skip: Number of alarms to skip (pagination)
        :param int limit: Maximum number of alarms to return

        :param list active_columns: list of active columns on the brick
        listalarm .

        :param bool hide_resources: hide_resources if component has an alarm

        :returns: List of sorted alarms + pagination informations
        :rtype: dict
        """
        if isinstance(search, int):
            search = str(search)

        try:
            alarms = ar.get(
                tstart=tstart,
                tstop=tstop,
                opened=opened,
                resolved=resolved,
                lookups=lookups,
                filter_=filter,
                search=search.strip(),
                sort_key=sort_key,
                sort_dir=sort_dir,
                skip=skip,
                limit=limit,
                with_steps=with_steps,
                natural_search=natural_search,
                active_columns=active_columns,
                hide_resources=hide_resources
            )
        except OperationFailure as of_err:
            message = 'Operation failure on get-alarms: {}'.format(of_err)
            raise WebServiceError(message)

        alarms_ids = []
        for alarm in alarms['alarms']:
            tmp_id = alarm.get('d')
            if tmp_id:
                alarms_ids.append(tmp_id)
        entities = context_manager.get_entities_by_id(alarms_ids, with_links=True)
        entity_dict = {}
        for entity in entities:
            entity_dict[entity.get('_id')] = entity

        list_alarm = []
        for alarm in alarms['alarms']:
            now = int(time())
            alarm["v"]['duration'] = now - alarm.get('v', {}).get('creation_date', now)
            state_time = alarm.get('v', {}).get('state', {}).get('t', now)
            alarm["v"]['current_state_duration'] = now - state_time
            tmp_entity_id = alarm['d']

            if alarm['d'] in entity_dict:
                alarm['links'] = entity_dict[alarm['d']]['links']

                # TODO: 'infos' is already present in entity.
                # Remove this one if unused.
                if tmp_entity_id in entity_dict:
                    data = entity_dict[alarm['d']]['infos']
                    if alarm.get('infos'):
                        alarm['infos'].update(data)
                    else:
                        alarm['infos'] = data

            alarm = compat_go_crop_states(alarm)

            list_alarm.append(alarm)

        alarms['alarms'] = list_alarm

        return alarms

    @route(
        ws.application.get,
        name='alerts/search/validate',
        payload=['expression']
    )
    def validate_search(expression):
        """
        Tell if a search expression is valid from a grammatical propespective.

        :param str expression: Search expression

        :returns: True if valid, False otherwise
        :rtype: bool
        """

        try:
            ar.interpret_search(expression)

        except Exception:
            return False

        else:
            return True

    @route(
        ws.application.get,
        name='alerts/count',
        payload=['start', 'stop', 'limit', 'select'],
    )
    def count_by_period(
            start,
            stop,
            limit=100,
            select=None,
    ):
        """
        Count alarms that have been opened during (stop - start) period.

        :param start: Beginning timestamp of period
        :type start: int

        :param stop: End timestamp of period
        :type stop: int

        :param limit: Counts cannot exceed this value
        :type limit: int

        :param query: Custom mongodb filter for alarms
        :type query: dict

        :return: List in which each item contains a time interval and the
                 related count
        :rtype: list
        """

        return ar.count_alarms_by_period(
            start,
            stop,
            limit=limit,
            query=select,
        )

    @route(
        ws.application.get,
        name='alerts/get-current-alarm',
        payload=['entity_id'],
    )
    def get_current_alarm(entity_id):
        """
        Get current unresolved alarm for a entity.

        :param str entity_id: Entity ID of the alarm

        :returns: Alarm as dict if something is opened, else None
        """

        return am.get_current_alarm(entity_id)

    @ws.application.get(
        '/api/v2/alerts/filters/<entity_id:id_filter>'
    )
    def get_filter(entity_id):
        """
        Get all filters linked with an alarm.

        :param str entity_id: Entity ID of the alarm-filter

        :returns: a list of <AlarmFilter>
        """
        filters = am.alarm_filters.get_filter(entity_id)
        if filters is None:
            return gen_json_error({'description': 'nothing to return'},
                                  HTTP_ERROR)

        return gen_json([l.serialize() for l in filters])

    @ws.application.post(
        '/api/v2/alerts/filters'
    )
    def create_filter():
        """
        Create a new alarm filter.

        :returns: an <AlarmFilter>
        """
        # element is a full AlarmFilter (dict) to insert
        element = request.json

        if element is None:
            return gen_json_error(
                {'description': 'nothing to insert'}, HTTP_ERROR)

        new = am.alarm_filters.create_filter(element=element)
        new.save()

        return gen_json(new.serialize())

    @ws.application.put(
        '/api/v2/alerts/filters/<entity_id:id_filter>'
    )
    def update_filter(entity_id):
        """
        Update an existing alam filter.

        :param entity_id: Entity ID of the alarm-filter
        :type entity_id: str
        :returns: <AlarmFilter>
        :rtype: dict
        """
        dico = request.json

        if dico is None or not isinstance(dico, dict) or len(dico) <= 0:
            return gen_json_error(
                {'description': 'wrong update dict'}, HTTP_ERROR)

        af = am.alarm_filters.update_filter(filter_id=entity_id, values=dico)
        if not isinstance(af, AlarmFilter):
            return gen_json_error({'description': 'failed to update filter'},
                                  HTTP_ERROR)

        return gen_json(af.serialize())

    @ws.application.delete(
        '/api/v2/alerts/filters/<entity_id:id_filter>'
    )
    def delete_id(entity_id):
        """
        Delete a filter, based on his id.

        :param entity_id: Entity ID of the alarm-filter
        :type entity_id: str

        :rtype: dict
        """
        ws.logger.info('Delete alarm-filter : {}'.format(entity_id))

        return gen_json(am.alarm_filters.delete_filter(entity_id))

    @ws.application.delete(
        '/api/v2/alerts/<mfilter>'
    )
    def delete_filter(mfilter):
        """
        :param str mfilter: mongo filter
        :rtype: dict
        """
        return gen_json(ar.alarm_storage._backend.remove(json.loads(mfilter)))

    @ws.application.post(
        '/api/v2/alerts/done'
    )
    def done_action():
        """
        Trigger done action.

        For json payload, see doc/docs/fr/guide_developpeur/apis/v2/alerts.md

        :rtype: dict
        """
        dico = request.json

        if dico is None or not isinstance(dico, dict) or len(dico) <= 0:
            return gen_json_error(
                {'description': 'wrong done dict'}, HTTP_ERROR)

        author = dico.get(am.AUTHOR)
        event = forger(
            event_type=Check.EVENT_TYPE,
            author=author,
            connector=dico.get('connector'),
            connector_name=dico.get('connector_name'),
            component=dico.get('component'),
            output=dico.get('comment')
        )
        if dico.get('source_type', None) == 'resource':
            event['resource'] = dico['resource']
            event['source_type'] = 'resource'
        ws.logger.debug('Received done action: {}'.format(event))

        entity_id = am.context_manager.get_id(event)
        retour = am.execute_task(
            'alerts.useraction.done',
            event=event,
            author=author,
            entity_id=entity_id
        )
        return gen_json(retour)
Beispiel #7
0
def exports(ws):
    alr = AlertsReader(*AlertsReader.provide_default_basics())
    manager = ContextGraph(ws.logger)

    DEFAULT_ACTIVE_COLUMNS = ["name", "type"]

    @route(ws.application.get)
    def context(_type, names=None, context=None, extended=None):
        if names:
            names = [n.strip() for n in names.split(',')]
        """
        result = manager.get(
            _type=_type, names=names, context=context, extended=extended)
        """
        # this is a test before adapter refactoring
        result = manager.get_entities_by_id(names)
        return result

    @route(ws.application.get, name='context/ids')
    @route(ws.application.post,
           payload=['ids', 'limit', 'start', 'sort', 'with_count'],
           name='context/ids')
    def context_by_id(ids=None, limit=0, start=0, sort=None, with_count=False):
        """
        result = manager.get(
            ids=ids,
            limit=limit,
            skip=start,
            sort=sort,
            with_count=with_count
        )
        """
        result = manager.get_entities_by_id(ids)

        return result

    @route(ws.application.post,
           payload=[
               'limit', 'start', 'sort', '_filter', 'search', 'active_columns'
           ])
    def context(context=None,
                _filter=None,
                search='',
                extended=False,
                limit=0,
                start=0,
                sort=None,
                active_columns=None):
        query = {}
        if _filter is not None:
            query.update(_filter)

        final_filter = {'$and': [query]}
        # try grammar search
        try:
            _, bnf_search_filter = alr.interpret_search(search)
        except ValueError as e:
            ws.logger.exception(e)
            bnf_search_filter = None

        if request.json:
            active_columns = request.json.get('active_columns', [])
        if not active_columns:
            active_columns = DEFAULT_ACTIVE_COLUMNS

        if bnf_search_filter is not None:
            final_filter['$and'].append(bnf_search_filter)
        else:
            escaped_search = re.escape(str(search).decode('utf-8'))
            column_filter = {'$or': []}
            for column in active_columns:
                column_filter['$or'].append({
                    column: {
                        '$regex': u'.*{}.*'.format(escaped_search),
                        '$options': 'i'
                    }
                })
            final_filter['$and'].append(column_filter)
        data, count = manager.get_entities(query=final_filter,
                                           limit=limit,
                                           start=start,
                                           sort=sort,
                                           with_count=True)

        return data, count

    @route(ws.application.put,
           payload=['_type', 'entity', 'context', 'extended_id'])
    def context(_type, entity, context=None, extended_id=None):
        """
        manager.put(
            _type=_type,
            entity=entity,
            context=context,
            extended_id=extended_id
        )
        """
        manager.update_entity(entity=entity)
        return entity

    @route(ws.application.delete,
           payload=['context', 'ids', '_type', 'extended'])
    def context(ids=None, _type=None, context=None, extended=False):
        """
        manager.remove(
            ids=ids,
            _type=_type,
            context=context,
            extended=extended
        )"""
        manager.delete_entity(ids)
Beispiel #8
0
def exports(ws):

    ws.application.router.add_filter('id_filter', id_filter)

    context_manager = ContextGraph(ws.logger)
    am = Alerts(*Alerts.provide_default_basics())
    ar = AlertsReader(*AlertsReader.provide_default_basics())

    @route(
        ws.application.get,
        name='alerts/get-alarms',
        payload=[
            'tstart',
            'tstop',
            'opened',
            'resolved',
            'lookups',
            'filter',
            'search',
            'sort_key',
            'sort_dir',
            'skip',
            'limit',
            'with_steps',
            'natural_search',
            'active_columns',
            'hide_resources'
        ]
    )
    def get_alarms(
            tstart=None,
            tstop=None,
            opened=True,
            resolved=False,
            lookups=[],
            filter={},
            search='',
            sort_key='opened',
            sort_dir='DESC',
            skip=0,
            limit=None,
            with_steps=False,
            natural_search=False,
            active_columns=None,
            hide_resources=False
    ):
        """
        Return filtered, sorted and paginated alarms.

        :param tstart: Beginning timestamp of requested period
        :param tstop: End timestamp of requested period
        :type tstart: int or None
        :type tstop: int or None

        :param bool opened: If True, consider alarms that are currently opened
        :param bool resolved: If True, consider alarms that have been resolved

        :param list lookups: List of extra columns to compute for each
          returned alarm. Extra columns are "pbehaviors".

        :param dict filter: Mongo filter. Keys are UI column names.
        :param str search: Search expression in custom DSL

        :param str sort_key: Name of the column to sort
        :param str sort_dir: Either "ASC" or "DESC"

        :param int skip: Number of alarms to skip (pagination)
        :param int limit: Maximum number of alarms to return

        :param list active_columns: list of active columns on the brick
        listalarm .

        :param bool hide_resources: hide_resources if component has an alarm

        :returns: List of sorted alarms + pagination informations
        :rtype: dict
        """
        if isinstance(search, int):
            search = str(search)

        try:
            alarms = ar.get(
                tstart=tstart,
                tstop=tstop,
                opened=opened,
                resolved=resolved,
                lookups=lookups,
                filter_=filter,
                search=search.strip(),
                sort_key=sort_key,
                sort_dir=sort_dir,
                skip=skip,
                limit=limit,
                with_steps=with_steps,
                natural_search=natural_search,
                active_columns=active_columns,
                hide_resources=hide_resources
            )
        except OperationFailure as of_err:
            message = 'Operation failure on get-alarms: {}'.format(of_err)
            raise WebServiceError(message)

        alarms_ids = []
        for alarm in alarms['alarms']:
            tmp_id = alarm.get('d')
            if tmp_id:
                alarms_ids.append(tmp_id)
        entities = context_manager.get_entities_by_id(alarms_ids, with_links=True)
        entity_dict = {}
        for entity in entities:
            entity_dict[entity.get('_id')] = entity

        list_alarm = []
        for alarm in alarms['alarms']:
            now = int(time())
            alarm["v"]['duration'] = now - alarm.get('v', {}).get('creation_date', now)
            state_time = alarm.get('v', {}).get('state', {}).get('t', now)
            alarm["v"]['current_state_duration'] = now - state_time
            tmp_entity_id = alarm['d']

            if alarm['d'] in entity_dict:
                alarm['links'] = entity_dict[alarm['d']]['links']

                # TODO: 'infos' is already present in entity.
                # Remove this one if unused.
                if tmp_entity_id in entity_dict:
                    data = entity_dict[alarm['d']]['infos']
                    if alarm.get('infos'):
                        alarm['infos'].update(data)
                    else:
                        alarm['infos'] = data

            alarm = compat_go_crop_states(alarm)

            list_alarm.append(alarm)

        alarms['alarms'] = list_alarm

        return alarms

    @route(
        ws.application.get,
        name='alerts/search/validate',
        payload=['expression']
    )
    def validate_search(expression):
        """
        Tell if a search expression is valid from a grammatical propespective.

        :param str expression: Search expression

        :returns: True if valid, False otherwise
        :rtype: bool
        """

        try:
            ar.interpret_search(expression)

        except Exception:
            return False

        else:
            return True

    @route(
        ws.application.get,
        name='alerts/count',
        payload=['start', 'stop', 'limit', 'select'],
    )
    def count_by_period(
            start,
            stop,
            limit=100,
            select=None,
    ):
        """
        Count alarms that have been opened during (stop - start) period.

        :param start: Beginning timestamp of period
        :type start: int

        :param stop: End timestamp of period
        :type stop: int

        :param limit: Counts cannot exceed this value
        :type limit: int

        :param query: Custom mongodb filter for alarms
        :type query: dict

        :return: List in which each item contains a time interval and the
                 related count
        :rtype: list
        """

        return ar.count_alarms_by_period(
            start,
            stop,
            limit=limit,
            query=select,
        )

    @route(
        ws.application.get,
        name='alerts/get-current-alarm',
        payload=['entity_id'],
    )
    def get_current_alarm(entity_id):
        """
        Get current unresolved alarm for a entity.

        :param str entity_id: Entity ID of the alarm

        :returns: Alarm as dict if something is opened, else None
        """

        return am.get_current_alarm(entity_id)

    @ws.application.get(
        '/api/v2/alerts/filters/<entity_id:id_filter>'
    )
    def get_filter(entity_id):
        """
        Get all filters linked with an alarm.

        :param str entity_id: Entity ID of the alarm-filter

        :returns: a list of <AlarmFilter>
        """
        filters = am.alarm_filters.get_filter(entity_id)
        if filters is None:
            return gen_json_error({'description': 'nothing to return'},
                                  HTTP_ERROR)

        return gen_json([l.serialize() for l in filters])

    @ws.application.post(
        '/api/v2/alerts/filters'
    )
    def create_filter():
        """
        Create a new alarm filter.

        :returns: an <AlarmFilter>
        """
        # element is a full AlarmFilter (dict) to insert
        element = request.json

        if element is None:
            return gen_json_error(
                {'description': 'nothing to insert'}, HTTP_ERROR)

        new = am.alarm_filters.create_filter(element=element)
        new.save()

        return gen_json(new.serialize())

    @ws.application.put(
        '/api/v2/alerts/filters/<entity_id:id_filter>'
    )
    def update_filter(entity_id):
        """
        Update an existing alam filter.

        :param entity_id: Entity ID of the alarm-filter
        :type entity_id: str
        :returns: <AlarmFilter>
        :rtype: dict
        """
        dico = request.json

        if dico is None or not isinstance(dico, dict) or len(dico) <= 0:
            return gen_json_error(
                {'description': 'wrong update dict'}, HTTP_ERROR)

        af = am.alarm_filters.update_filter(filter_id=entity_id, values=dico)
        if not isinstance(af, AlarmFilter):
            return gen_json_error({'description': 'failed to update filter'},
                                  HTTP_ERROR)

        return gen_json(af.serialize())

    @ws.application.delete(
        '/api/v2/alerts/filters/<entity_id:id_filter>'
    )
    def delete_id(entity_id):
        """
        Delete a filter, based on his id.

        :param entity_id: Entity ID of the alarm-filter
        :type entity_id: str

        :rtype: dict
        """
        ws.logger.info('Delete alarm-filter : {}'.format(entity_id))

        return gen_json(am.alarm_filters.delete_filter(entity_id))

    @ws.application.delete(
        '/api/v2/alerts/<mfilter>'
    )
    def delete_filter(mfilter):
        """
        :param str mfilter: mongo filter
        :rtype: dict
        """
        return gen_json(ar.alarm_storage._backend.remove(json.loads(mfilter)))

    @ws.application.post(
        '/api/v2/alerts/done'
    )
    def done_action():
        """
        Trigger done action.

        For json payload, see doc/docs/fr/guide_developpeur/apis/v2/alerts.md

        :rtype: dict
        """
        dico = request.json

        if dico is None or not isinstance(dico, dict) or len(dico) <= 0:
            return gen_json_error(
                {'description': 'wrong done dict'}, HTTP_ERROR)

        author = dico.get(am.AUTHOR)
        event = forger(
            event_type=Check.EVENT_TYPE,
            author=author,
            connector=dico.get('connector'),
            connector_name=dico.get('connector_name'),
            component=dico.get('component'),
            output=dico.get('comment')
        )
        if dico.get('source_type', None) == 'resource':
            event['resource'] = dico['resource']
            event['source_type'] = 'resource'
        ws.logger.debug('Received done action: {}'.format(event))

        entity_id = am.context_manager.get_id(event)
        retour = am.execute_task(
            'alerts.useraction.done',
            event=event,
            author=author,
            entity_id=entity_id
        )
        return gen_json(retour)
Beispiel #9
0
class TestReader(BaseTest):
    def setUp(self):
        super(TestReader, self).setUp()

        mongo = MongoStore.get_default()
        collection = mongo.get_collection("default_testpbehavior")
        pb_coll = MongoCollection(collection)

        self.logger = Logger.get('alertsreader', '/tmp/null')
        conf = Configuration.load(PBehaviorManager.CONF_PATH, Ini)
        self.pbehavior_manager = PBehaviorManager(config=conf,
                                                  logger=self.logger,
                                                  pb_collection=pb_coll)

        self.reader = AlertsReader(config=conf,
                                   logger=self.logger,
                                   storage=self.manager.alerts_storage,
                                   pbehavior_manager=self.pbehavior_manager)

        self.reader._alarm_fields = {
            'properties': {
                'connector': {
                    'stored_name': 'v.ctr'
                },
                'component': {
                    'stored_name': 'v.cpt'
                },
                'entity_id': {
                    'stored_name': 'd'
                }
            }
        }

    def tearDown(self):
        """Teardown"""
        super(TestReader, self).setUp()
        self.pbehavior_manager.delete(_filter={})

    def test__translate_key(self):
        cases = [{
            'key': 'untranslated_key',
            'tkey': 'untranslated_key'
        }, {
            'key': 'connector',
            'tkey': 'v.ctr'
        }, {
            'key': 'entity_id',
            'tkey': 'd'
        }]

        for case in cases:
            tkey = self.reader._translate_key(case['key'])
            self.assertEqual(tkey, case['tkey'])

    def test__translate_filter(self):
        cases = [{
            'filter': {},
            'tfilter': {}
        }, {
            'filter': {
                'connector': 'c'
            },
            'tfilter': {
                'v.ctr': 'c'
            }
        }, {
            'filter': {
                '$or': [{
                    'connector': 'c1'
                }, {
                    'component': 'c2'
                }]
            },
            'tfilter': {
                '$or': [{
                    'v.ctr': 'c1'
                }, {
                    'v.cpt': 'c2'
                }]
            }
        }, {
            'filter': {
                '$or': [{
                    'entity_id': {
                        '$gte': 12
                    },
                    'untranslated': 'val'
                }, {
                    'connector': 'c1'
                }, {
                    '$or': [{
                        'component': 'c2'
                    }, {
                        'untranslated': 'val'
                    }]
                }]
            },
            'tfilter': {
                '$or': [{
                    'd': {
                        '$gte': 12
                    },
                    'untranslated': 'val'
                }, {
                    'v.ctr': 'c1'
                }, {
                    '$or': [{
                        'v.cpt': 'c2'
                    }, {
                        'untranslated': 'val'
                    }]
                }]
            }
        }]

        for case in cases:
            tfilter = self.reader._translate_filter(case['filter'])
            self.assertEqual(tfilter, case['tfilter'])

    def test__get_time_filter(self):
        # opened=False, resolved=False
        self.assertIs(
            self.reader._get_opened_resolved_time_filter(opened=False,
                                                         resolved=False,
                                                         tstart=0,
                                                         tstop=0), None)

        # opened=True, resolved=False
        expected_opened = {'v.resolved': None, 't': {'$lte': 2, "$gte": 1}}
        self.assertEqual(
            self.reader._get_opened_resolved_time_filter(opened=True,
                                                         resolved=False,
                                                         tstart=1,
                                                         tstop=2),
            expected_opened)

        # opened=False, resolved=True
        expected_resolved = {
            'v.resolved': {
                '$ne': None
            },
            't': {
                '$gte': 1,
                '$lte': 2
            }
        }
        self.assertEqual(
            self.reader._get_opened_resolved_time_filter(opened=False,
                                                         resolved=True,
                                                         tstart=1,
                                                         tstop=2),
            expected_resolved)

        # opened=True, resolved=True
        expected_both = {'$or': [expected_opened, expected_resolved]}
        self.assertEqual(
            self.reader._get_opened_resolved_time_filter(opened=True,
                                                         resolved=True,
                                                         tstart=1,
                                                         tstop=2),
            expected_both)

        # opened=True, resolved=True, tstart=tstop=None
        self.assertEqual(
            self.reader._get_opened_resolved_time_filter(opened=True,
                                                         resolved=True,
                                                         tstart=None,
                                                         tstop=None), {})

    def test__get_opened_time_filter(self):
        cases = [{
            'tstart': None,
            'tstop': None,
            'expected': {
                'v.resolved': None
            }
        }, {
            'tstart': None,
            'tstop': 0,
            'expected': {
                'v.resolved': None,
                't': {
                    '$lte': 0
                }
            }
        }, {
            'tstart': None,
            'tstop': 42,
            'expected': {
                'v.resolved': None,
                't': {
                    '$lte': 42
                }
            }
        }, {
            'tstart': 13,
            'tstop': None,
            'expected': {
                'v.resolved': None,
                't': {
                    '$gte': 13
                }
            }
        }, {
            'tstart': 13,
            'tstop': 42,
            'expected': {
                'v.resolved': None,
                't': {
                    '$lte': 42,
                    "$gte": 13
                }
            }
        }]

        for case in cases:
            time_filter = self.reader._get_opened_time_filter(
                case['tstart'], case['tstop'])
            self.assertEqual(time_filter, case['expected'])

    def test__get_resolved_time_filter(self):
        cases = [{
            'tstart': None,
            'tstop': None,
            'expected': {
                'v.resolved': {
                    '$ne': None
                }
            }
        }, {
            'tstart': 13,
            'tstop': None,
            'expected': {
                'v.resolved': {
                    '$ne': None
                },
                't': {
                    '$gte': 13
                }
            }
        }, {
            'tstart': None,
            'tstop': 42,
            'expected': {
                'v.resolved': {
                    '$ne': None
                },
                't': {
                    '$lte': 42
                }
            }
        }, {
            'tstart': 0,
            'tstop': 0,
            'expected': {
                'v.resolved': {
                    '$ne': None
                },
                't': {
                    '$gte': 0,
                    '$lte': 0
                }
            }
        }, {
            'tstart': 1,
            'tstop': 2,
            'expected': {
                'v.resolved': {
                    '$ne': None
                },
                't': {
                    '$gte': 1,
                    '$lte': 2
                }
            }
        }]

        for case in cases:
            time_filter = self.reader._get_resolved_time_filter(
                case['tstart'], case['tstop'])
            self.assertEqual(time_filter, case['expected'])

    def test__translate_sort(self):
        cases = [{
            'sort_key': 'untranslated',
            'sort_dir': 'DESC',
            'tkey': 'untranslated',
            'tdir': -1
        }, {
            'sort_key': 'untranslated',
            'sort_dir': 'ASC',
            'tkey': 'untranslated',
            'tdir': 1
        }, {
            'sort_key': 'component',
            'sort_dir': 'DESC',
            'tkey': 'v.cpt',
            'tdir': -1
        }]

        for case in cases:
            tkey, tdir = self.reader._translate_sort(case['sort_key'],
                                                     case['sort_dir'])

            self.assertEqual(tkey, case['tkey'])
            self.assertEqual(tdir, case['tdir'])

    def test__get_final_filter_bnf(self):
        view_filter = {'$and': [{'resource': 'companion cube'}]}
        time_filter = {'glados': 'shell'}
        bnf_search = 'NOT resource="turret"'
        active_columns = ['resource', 'component']

        filter_ = self.reader._get_final_filter(view_filter, time_filter,
                                                bnf_search, active_columns)

        ref_filter = {
            '$and': [{
                "d": {
                    "$not": re.compile("^meta-alarm-entity-.+")
                }
            }, view_filter, time_filter, {
                'resource': {
                    '$not': {
                        '$eq': 'turret'
                    }
                }
            }]
        }
        self.assertEqual(ref_filter, filter_)

    def test__get_final_filter_natural(self):
        view_filter = {'$and': [{'resource': 'companion cube'}]}
        time_filter = {'glados': 'shell'}
        search = 'turret'
        active_columns = ['resource', 'component']

        filter_ = self.reader._get_final_filter(view_filter, time_filter,
                                                search, active_columns)

        self.maxDiff = None
        ref_filter = {
            '$and': [{
                "d": {
                    "$not": re.compile("^meta-alarm-entity-.+")
                }
            }, view_filter, time_filter, {
                '$or': [{
                    'resource': {
                        '$regex': u'.*turret.*',
                        '$options': 'i'
                    }
                }, {
                    'component': {
                        '$regex': u'.*turret.*',
                        '$options': 'i'
                    }
                }, {
                    'd': {
                        '$regex': u'.*turret.*',
                        '$options': 'i'
                    }
                }]
            }]
        }

        # compiled regex resluted diffrent objects, that makes mismatched ref_filter and filter_
        # first assert equality of patterns of these values
        # then assert equality for rest of conditions without compiled pattern objects
        _get_regex_condition = lambda x: x["$and"][0]["d"]["$not"]
        _get_pattern = lambda x: _get_regex_condition(x).pattern

        def _del_pattern(x):
            del x["$and"][0]["d"]["$not"]
            return x

        ref_pattern, filter_pattern = _get_pattern(ref_filter), _get_pattern(
            filter_)
        self.assertEqual(ref_pattern, filter_pattern)
        print("representation of matched paterns: {} {}, compiled regex {} {}".
              format(ref_pattern, filter_pattern,
                     _get_regex_condition(ref_filter),
                     _get_regex_condition(filter_)))
        self.assertEqual(_del_pattern(ref_filter), _del_pattern(filter_))

    def test__get_final_filter_natural_numonly(self):
        view_filter = {}
        time_filter = {}
        search = 11111
        active_columns = ['resource']

        filter_ = self.reader._get_final_filter(view_filter, time_filter,
                                                search, active_columns)

        self.maxDiff = None
        res_filter = {
            '$and': [{
                "d": {
                    "$not": re.compile("^meta-alarm-entity-.+")
                }
            }, {
                '$or': [{
                    'resource': {
                        '$options': 'i',
                        '$regex': '.*11111.*'
                    }
                }, {
                    'd': {
                        '$options': 'i',
                        '$regex': '.*11111.*'
                    }
                }]
            }]
        }
        self.assertEqual(res_filter, filter_)

    def test_contains_wildcard_dynamic_filter(self):
        # not contains dynamic wildcard filter
        view_filter = {}
        time_filter = {}
        search = 11111
        active_columns = ['resource']

        filter_ = self.reader._get_final_filter(view_filter, time_filter,
                                                search, active_columns)

        self.maxDiff = None
        res_filter = {
            '$and': [{
                "d": {
                    "$not": re.compile("^meta-alarm-entity-.+")
                }
            }, {
                '$or': [{
                    'resource': {
                        '$options': 'i',
                        '$regex': '.*11111.*'
                    }
                }, {
                    'd': {
                        '$options': 'i',
                        '$regex': '.*11111.*'
                    }
                }]
            }]
        }
        t = self.reader.contains_wildcard_dynamic_filter(filter_)
        self.assertFalse(t)
        self.assertEqual(res_filter, filter_)

        # contains dynamic wildcard filter
        view_filter = {}
        time_filter = {}
        search = 11111
        active_columns = ['v.infos.*.type']

        filter_ = self.reader._get_final_filter(view_filter, time_filter,
                                                search, active_columns)

        t = self.reader.contains_wildcard_dynamic_filter(filter_)
        self.maxDiff = None
        res_filter = {
            '$and': [{
                "d": {
                    "$not": re.compile("^meta-alarm-entity-.+")
                }
            }, {
                '$or': [{
                    'infos_array.v.type': {
                        '$options': 'i',
                        '$regex': '.*11111.*'
                    }
                }, {
                    'd': {
                        '$options': 'i',
                        '$regex': '.*11111.*'
                    }
                }]
            }]
        }
        self.assertTrue(t)
        self.assertEqual(res_filter, filter_)

        # contains dynamic wildcard filter
        view_filter = {'$and': [{'v.infos.*.tt': 'companion cube'}]}
        time_filter = {'glados': 'shell'}
        bnf_search = 'NOT resource="turret"'
        active_columns = ['resource', 'component']

        filter_ = self.reader._get_final_filter(view_filter, time_filter,
                                                bnf_search, active_columns)

        ref_filter = {
            '$and': [{
                "d": {
                    "$not": re.compile("^meta-alarm-entity-.+")
                }
            }, {
                '$and': [{
                    'infos_array.v.tt': 'companion cube'
                }]
            }, time_filter, {
                'resource': {
                    '$not': {
                        '$eq': 'turret'
                    }
                }
            }]
        }
        t = self.reader.contains_wildcard_dynamic_filter(filter_)
        self.assertTrue(t)
        self.assertEqual(ref_filter, filter_)

    def test_count_alarms_by_period(self):
        day = 24 * 3600

        alarm0_id = '/fake/alarm/id0'
        event0 = {
            'connector': 'ut',
            'connector_name': 'ut0',
            'component': 'c',
            'output': '...',
            'timestamp': day / 2
        }
        alarm0 = self.manager.make_alarm(alarm0_id, event0)
        alarm0 = self.manager.update_state(alarm0, 1, event0)
        new_value0 = alarm0[self.manager.alerts_storage.VALUE]
        self.manager.update_current_alarm(alarm0, new_value0)

        alarm1_id = '/fake/alarm/id1'
        event1 = {
            'connector': 'ut',
            'connector_name': 'ut0',
            'component': 'c',
            'output': '...',
            'timestamp': 3 * day / 2
        }
        alarm1 = self.manager.make_alarm(alarm1_id, event1)
        alarm1 = self.manager.update_state(alarm1, 1, event1)
        new_value1 = alarm1[self.manager.alerts_storage.VALUE]
        self.manager.update_current_alarm(alarm1, new_value1)

        # Are subperiods well cut ?
        count = self.reader.count_alarms_by_period(0, day)
        self.assertEqual(len(count), 1)

        count = self.reader.count_alarms_by_period(0, day * 3)
        self.assertEqual(len(count), 3)

        count = self.reader.count_alarms_by_period(day, day * 10)
        self.assertEqual(len(count), 9)

        count = self.reader.count_alarms_by_period(
            0,
            day,
            subperiod={'hour': 1},
        )
        self.assertEqual(len(count), 24)

        # Are counts by period correct ?
        count = self.reader.count_alarms_by_period(0, day / 4)
        self.assertEqual(count[0]['count'], 0)

        count = self.reader.count_alarms_by_period(0, day)
        self.assertEqual(count[0]['count'], 1)

        count = self.reader.count_alarms_by_period(day / 2, 3 * day / 2)
        self.assertEqual(count[0]['count'], 2)

        # Does limit limits count ?
        count = self.reader.count_alarms_by_period(0, day, limit=100)
        self.assertEqual(count[0]['count'], 1)

        count = self.reader.count_alarms_by_period(day / 2,
                                                   3 * day / 2,
                                                   limit=1)
        self.assertEqual(count[0]['count'], 1)

    def test__get_disable_entity(self):
        event = {
            'connector': '03-K64_Firefly',
            'connector_name': 'serenity',
            'component': 'Malcolm_Reynolds',
            'output': 'the big red recall button',
            'timestamp': int(time.time()) - 100,
            "source_type": "component"
        }
        alarm_id = '/strawberry'
        alarm = self.manager.make_alarm(alarm_id, event)

        context_manager = ContextGraph(logger=LoggerMock())
        ent_id = context_manager.get_id(event)

        entity = context_manager.create_entity_dict(ent_id, "inara",
                                                    "component")
        entity["enabled"] = False
        context_manager._put_entities(entity)

        alarms = self.reader.get(opened=True)
        print(alarms)
        self.assertEqual(len(alarms["alarms"]), 0)
Beispiel #10
0
class TestReader(BaseTest):
    def setUp(self):
        super(TestReader, self).setUp()
        self.pb_storage = Middleware.get_middleware_by_uri(
            PBehaviorManager.PB_STORAGE_URI
        )

        self.logger = Logger.get('alertsreader', '/tmp/null')
        conf = Configuration.load(PBehaviorManager.CONF_PATH, Ini)
        self.pbehavior_manager = PBehaviorManager(config=conf,
                                                  logger=self.logger,
                                                  pb_storage=self.pb_storage)

        self.reader = AlertsReader(config=conf,
                                   logger=self.logger,
                                   storage=self.manager.alerts_storage,
                                   pbehavior_manager=self.pbehavior_manager)

        self.reader._alarm_fields = {
            'properties': {
                'connector': {'stored_name': 'v.ctr'},
                'component': {'stored_name': 'v.cpt'},
                'entity_id': {'stored_name': 'd'}
            }
        }

    def tearDown(self):
        """Teardown"""
        super(TestReader, self).setUp()
        self.pb_storage.remove_elements()

    def test__translate_key(self):
        cases = [
            {
                'key': 'untranslated_key',
                'tkey': 'untranslated_key'
            },
            {
                'key': 'connector',
                'tkey': 'v.ctr'
            },
            {
                'key': 'entity_id',
                'tkey': 'd'
            }
        ]

        for case in cases:
            tkey = self.reader._translate_key(case['key'])
            self.assertEqual(tkey, case['tkey'])

    def test__translate_filter(self):
        cases = [
            {
                'filter': {},
                'tfilter': {}
            },
            {
                'filter': {'connector': 'c'},
                'tfilter': {'v.ctr': 'c'}
            },
            {
                'filter': {'$or': [{'connector': 'c1'}, {'component': 'c2'}]},
                'tfilter': {'$or': [{'v.ctr': 'c1'}, {'v.cpt': 'c2'}]}
            },
            {
                'filter': {
                    '$or': [
                        {'entity_id': {'$gte': 12}, 'untranslated': 'val'},
                        {'connector': 'c1'},
                        {'$or': [{'component': 'c2'}, {'untranslated': 'val'}]}
                    ]
                },
                'tfilter': {
                    '$or': [
                        {'d': {'$gte': 12}, 'untranslated': 'val'},
                        {'v.ctr': 'c1'},
                        {'$or': [{'v.cpt': 'c2'}, {'untranslated': 'val'}]}
                    ]
                }
            }
        ]

        for case in cases:
            tfilter = self.reader._translate_filter(case['filter'])
            self.assertEqual(tfilter, case['tfilter'])

    def test__get_time_filter(self):
        # opened=False, resolved=False
        self.assertIs(
            self.reader._get_time_filter(
                opened=False, resolved=False, tstart=0, tstop=0),
            None
        )

        # opened=True, resolved=False
        expected_opened = {'v.resolved': None, 't': {'$lte': 2, "$gte": 1}}
        self.assertEqual(
            self.reader._get_time_filter(
                opened=True, resolved=False, tstart=1, tstop=2),
            expected_opened
        )

        # opened=False, resolved=True
        expected_resolved = {
            'v.resolved': {'$ne': None},
            't': {'$gte': 1, '$lte': 2}
        }
        self.assertEqual(
            self.reader._get_time_filter(
                opened=False, resolved=True, tstart=1, tstop=2),
            expected_resolved
        )

        # opened=True, resolved=True
        expected_both = {'$or': [expected_opened, expected_resolved]}
        self.assertEqual(
            self.reader._get_time_filter(
                opened=True, resolved=True, tstart=1, tstop=2),
            expected_both
        )

        # opened=True, resolved=True, tstart=tstop=None
        self.assertEqual(
            self.reader._get_time_filter(
                opened=True, resolved=True,
                tstart=None, tstop=None
            ),
            {}
        )

    def test__get_opened_time_filter(self):
        cases = [
            {
                'tstart': None,
                'tstop': None,
                'expected': {'v.resolved': None}
            },
            {
                'tstart': None,
                'tstop': 0,
                'expected': {'v.resolved': None, 't': {'$lte': 0}}
            },
            {
                'tstart': None,
                'tstop': 42,
                'expected': {'v.resolved': None, 't': {'$lte': 42}}
            },
            {
                'tstart': 13,
                'tstop': None,
                'expected': {'v.resolved': None, 't': {'$lte': 13}}
            },
            {
                'tstart': 13,
                'tstop': 42,
                'expected': {'v.resolved': None, 't': {'$lte': 42, "$gte": 13}}
            }
        ]

        for case in cases:
            time_filter = self.reader._get_opened_time_filter(
                case['tstart'],
                case['tstop']
            )
            self.assertEqual(time_filter, case['expected'])

    def test__get_resolved_time_filter(self):
        cases = [
            {
                'tstart': None,
                'tstop': None,
                'expected': {'v.resolved': {'$ne': None}}
            },
            {
                'tstart': 13,
                'tstop': None,
                'expected': {
                    'v.resolved': {'$ne': None, '$gte': 13}
                }
            },
            {
                'tstart': None,
                'tstop': 42,
                'expected': {
                    'v.resolved': {'$ne': None},
                    't': {'$lte': 42}
                }
            },
            {
                'tstart': 0,
                'tstop': 0,
                'expected': {
                    'v.resolved': {'$ne': None},
                    't': {'$gte': 0, '$lte': 0}
                }
            },
            {
                'tstart': 1,
                'tstop': 2,
                'expected': {
                    'v.resolved': {'$ne': None},
                    't': {'$gte': 1, '$lte': 2}
                }
            }
        ]

        for case in cases:
            time_filter = self.reader._get_resolved_time_filter(
                case['tstart'],
                case['tstop']
            )
            self.assertEqual(time_filter, case['expected'])

    def test__translate_sort(self):
        cases = [
            {
                'sort_key': 'untranslated',
                'sort_dir': 'DESC',
                'tkey': 'untranslated',
                'tdir': -1
            },
            {
                'sort_key': 'untranslated',
                'sort_dir': 'ASC',
                'tkey': 'untranslated',
                'tdir': 1
            },
            {
                'sort_key': 'component',
                'sort_dir': 'DESC',
                'tkey': 'v.cpt',
                'tdir': -1
            }
        ]

        for case in cases:
            tkey, tdir = self.reader._translate_sort(
                case['sort_key'],
                case['sort_dir']
            )

            self.assertEqual(tkey, case['tkey'])
            self.assertEqual(tdir, case['tdir'])

    def test__get_final_filter_bnf(self):
        view_filter = {'$and': [{'resource': 'companion cube'}]}
        time_filter = {'glados': 'shell'}
        bnf_search = 'NOT resource="turret"'
        active_columns = ['resource', 'component']

        filter_ = self.reader._get_final_filter(
            view_filter, time_filter, bnf_search, active_columns
        )

        ref_filter = {
            '$and': [
                view_filter,
                time_filter,
                {'resource': {'$not': {'$eq': 'turret'}}}
            ]
        }
        self.assertEqual(ref_filter, filter_)

    def test__get_final_filter_natural(self):
        view_filter = {'$and': [{'resource': 'companion cube'}]}
        time_filter = {'glados': 'shell'}
        search = 'turret'
        active_columns = ['resource', 'component']

        filter_ = self.reader._get_final_filter(
            view_filter, time_filter, search, active_columns
        )

        self.maxDiff = None
        ref_filter = {
            '$and': [
                view_filter,
                time_filter,
                {
                    '$or': [
                        {'resource': {
                            '$regex': '.*turret.*', '$options': 'i'}},
                        {'component': {
                            '$regex': '.*turret.*', '$options': 'i'}},
                        {'d': {
                            '$regex': '.*turret.*', '$options': 'i'}}
                    ]
                }
            ]
        }
        self.assertEqual(ref_filter, filter_)

    def test__get_final_filter_natural_numonly(self):
        view_filter = {}
        time_filter = {}
        search = 11111
        active_columns = ['resource']

        filter_ = self.reader._get_final_filter(
            view_filter, time_filter, search, active_columns
        )

        self.maxDiff = None
        res_filter = {
            '$and': [
                {'$or': [
                    {'resource': {'$options': 'i', '$regex': '.*11111.*'}},
                    {'d': {'$options': 'i', '$regex': '.*11111.*'}}
                ]}
            ]
        }
        self.assertEqual(res_filter, filter_)

    def test_count_alarms_by_period(self):
        day = 24 * 3600

        alarm0_id = '/fake/alarm/id0'
        event0 = {
            'connector': 'ut',
            'connector_name': 'ut0',
            'component': 'c',
            'output': '...',
            'timestamp': day / 2
        }
        alarm0 = self.manager.make_alarm(
            alarm0_id,
            event0
        )
        alarm0 = self.manager.update_state(alarm0, 1, event0)
        new_value0 = alarm0[self.manager.alerts_storage.VALUE]
        self.manager.update_current_alarm(alarm0, new_value0)

        alarm1_id = '/fake/alarm/id1'
        event1 = {
            'connector': 'ut',
            'connector_name': 'ut0',
            'component': 'c',
            'output': '...',
            'timestamp': 3 * day / 2
        }
        alarm1 = self.manager.make_alarm(
            alarm1_id,
            event1
        )
        alarm1 = self.manager.update_state(alarm1, 1, event1)
        new_value1 = alarm1[self.manager.alerts_storage.VALUE]
        self.manager.update_current_alarm(alarm1, new_value1)

        # Are subperiods well cut ?
        count = self.reader.count_alarms_by_period(0, day)
        self.assertEqual(len(count), 1)

        count = self.reader.count_alarms_by_period(0, day * 3)
        self.assertEqual(len(count), 3)

        count = self.reader.count_alarms_by_period(day, day * 10)
        self.assertEqual(len(count), 9)

        count = self.reader.count_alarms_by_period(
            0, day,
            subperiod={'hour': 1},
        )
        self.assertEqual(len(count), 24)

        # Are counts by period correct ?
        count = self.reader.count_alarms_by_period(0, day / 4)
        self.assertEqual(count[0]['count'], 0)

        count = self.reader.count_alarms_by_period(0, day)
        self.assertEqual(count[0]['count'], 1)

        count = self.reader.count_alarms_by_period(day / 2, 3 * day / 2)
        self.assertEqual(count[0]['count'], 2)

        # Does limit limits count ?
        count = self.reader.count_alarms_by_period(0, day, limit=100)
        self.assertEqual(count[0]['count'], 1)

        count = self.reader.count_alarms_by_period(day / 2, 3 * day / 2,
                                                   limit=1)
        self.assertEqual(count[0]['count'], 1)

    def test__get_disable_entity(self):
        event = {
            'connector': '03-K64_Firefly',
            'connector_name': 'serenity',
            'component': 'Malcolm_Reynolds',
            'output': 'the big red recall button',
            'timestamp': int(time.time()) - 100,
            "source_type": "component"
        }
        alarm_id = '/strawberry'
        alarm = self.manager.make_alarm(
            alarm_id,
            event
        )

        context_manager = ContextGraph(logger=LoggerMock())
        ent_id = context_manager.get_id(event)

        entity = context_manager.create_entity_dict(ent_id,
                                                    "inara",
                                                    "component")
        entity["enabled"] = False
        context_manager._put_entities(entity)

        alarms = self.reader.get(opened=True)
        print(alarms)
        self.assertEqual(len(alarms["alarms"]), 0)