Exemple #1
0
    def change_of_status(self, alarm, old_status, status, event):
        """
        Archive status change when ``archive_status()`` detected a status
        change.

        :param alarm: Associated alarm to status change event
        :type alarm: dict

        :param old_status: Previous status
        :type old_status: int

        :param status: New status
        :type status: int

        :param event: Associated event
        :type event: dict
        """

        if status > old_status:
            task = get_task(
                'alerts.systemaction.status_increase', cacheonly=True
            )

        elif status < old_status:
            task = get_task(
                'alerts.systemaction.status_decrease', cacheonly=True
            )

        value = alarm.get(self[Alerts.ALARM_STORAGE].VALUE)
        new_value = task(self, value, status, event)
        self.update_current_alarm(alarm, new_value)
Exemple #2
0
    def test_acknowledge(self):
        event = {
            'timestamp': 0,
            'source_type': 'component',
            'connector': 'c',
            'connector_name': 'cn',
            'component': 'cm',
        }

        task = get_task('alerts.useraction.ack')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm[AlarmField.ack.value] is not None)
        self.assertEqual(alarm[AlarmField.ack.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.ack.value]['a'], 'testauthor')
        self.assertEqual(alarm[AlarmField.ack.value]['m'], 'test message')
        self.assertTrue(alarm[AlarmField.ack.value] is get_previous_step(alarm, 'ack'))

        self.event_publisher.publish_statcounterinc_event.assert_not_called()
        self.event_publisher.publish_statduration_event.assert_called_once_with(
            0, StatDurations.ack_time, 0, {}, alarm, 'testauthor')
Exemple #3
0
    def test_acknowledge_twice(self):
        event = {
            'timestamp': 0,
            'source_type': 'component',
            'connector': 'c',
            'connector_name': 'cn',
            'component': 'cm',
        }

        ack_task = get_task('alerts.useraction.ack')
        #ackremove_task = get_task('alerts.useraction.ackremove')
        alarm = ack_task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )
        ack_task(
            self.manager,
            alarm,
            'testauthor',
            'test message',
            event
        )

        self.event_publisher.publish_statcounterinc_event.assert_not_called()
        self.event_publisher.publish_statduration_event.assert_called_once_with(
            0, StatDurations.ack_time, 0, {}, alarm, 'testauthor')
Exemple #4
0
    def test_restore(self):
        event = {'timestamp': 0}

        task = get_task('alerts.useraction.uncancel')
        self.alarm[AlarmField.canceled.value] = {
            '_t': 'cancel',
            't': 0,
            'a': 'testauthor',
            'm': 'test message'
        }

        alarm, _ = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm[AlarmField.canceled.value] is None)

        uncancel = get_previous_step(alarm, 'uncancel')
        self.assertFalse(uncancel is None)
        self.assertEqual(uncancel['t'], 0)
        self.assertEqual(uncancel['a'], 'testauthor')
        self.assertEqual(uncancel['m'], 'test message')
Exemple #5
0
    def test_snooze(self):
        event = {
            'connector': 'test',
            'connector_name': 'test0',
            'timestamp': 0,
            'output': 'test message',
            'duration': 3600,
        }

        task = get_task('alerts.useraction.snooze')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event,
        )

        self.assertIsNot(alarm[AlarmField.snooze.value], None)
        self.assertEqual(alarm[AlarmField.snooze.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.snooze.value]['a'], 'testauthor')
        self.assertEqual(alarm[AlarmField.snooze.value]['m'], 'test message')
        self.assertEqual(alarm[AlarmField.snooze.value]['val'], 0 + 3600)
        self.assertTrue(
            alarm[AlarmField.snooze.value] is get_previous_step(alarm, 'snooze')
        )
Exemple #6
0
    def test_hard_limit(self):
        class Manager(object):
            hard_limit = 100

        mgr = Manager()
        alarm = {'hard_limit': None, 'steps': []}

        task = get_task('alerts.systemaction.hard_limit')

        alarm = task(mgr, alarm)

        self.assertIsNot(alarm['hard_limit'], None)
        self.assertEqual(len(alarm['steps']), 1)
        self.assertEqual(alarm['steps'][0], alarm['hard_limit'])

        self.assertEqual(alarm['hard_limit']['_t'], 'hardlimit')
        self.assertIs(type(alarm['hard_limit']['t']), int)
        self.assertEqual(alarm['hard_limit']['a'], '__canopsis__')
        self.assertEqual(
            alarm['hard_limit']['m'],
            (
                'This alarm has reached an hard limit (100 steps recorded) : '
                'no more steps will be appended. Please cancel this alarm or '
                'extend hard limit value.'
            )
        )
        self.assertEqual(alarm['hard_limit']['val'], 100)
Exemple #7
0
    def test_get_unregisteredtask(self):
        """
        Test to get unregistered task.
        """

        getTaskTest = path(GetTaskTest)
        task = get_task(getTaskTest)
        self.assertEqual(task, GetTaskTest)
Exemple #8
0
    def change_of_status(self, alarm, old_status, status, event):
        """
        Change status when ``update_status()`` detected a status
        change.

        :param dict alarm: Associated alarm to status change event
        :param int old_status: Previous status
        :param int status: New status
        :param dict event: Associated event
        :return: alarm with changed status
        :rtype: dict
        """

        if status > old_status:
            task = get_task(
                'alerts.systemaction.status_increase', cacheonly=True
            )

        elif status < old_status:
            task = get_task(
                'alerts.systemaction.status_decrease', cacheonly=True
            )

        value = alarm.get(self.alerts_storage.VALUE)
        new_value = task(self, value, status, event)
        new_value[AlarmField.last_update_date.value] = int(time())

        alarm[self.alerts_storage.VALUE] = new_value

        entity_id = alarm[self.alerts_storage.DATA_ID]

        if status == CANCELED:
            entity = self.context_manager.get_entities_by_id(entity_id)
            try:
                entity = entity[0]
            except IndexError:
                entity = {}
            self.event_publisher.publish_statcounterinc_event(
                new_value[AlarmField.last_update_date.value],
                StatCounters.alarms_canceled,
                entity,
                new_value,
                event.get(self.AUTHOR))

        return alarm
Exemple #9
0
    def change_of_status(self, alarm, old_status, status, event):
        """
        Change status when ``update_status()`` detected a status
        change.

        :param dict alarm: Associated alarm to status change event
        :param int old_status: Previous status
        :param int status: New status
        :param dict event: Associated event
        :return: alarm with changed status
        :rtype: dict
        """

        if status > old_status:
            task = get_task(
                'alerts.systemaction.status_increase', cacheonly=True
            )

        elif status < old_status:
            task = get_task(
                'alerts.systemaction.status_decrease', cacheonly=True
            )

        value = alarm.get(self.alerts_storage.VALUE)
        new_value = task(self, value, status, event)
        new_value[AlarmField.last_update_date.value] = int(time())

        alarm[self.alerts_storage.VALUE] = new_value

        entity_id = alarm[self.alerts_storage.DATA_ID]

        if status == CANCELED:
            entity = self.context_manager.get_entities_by_id(entity_id)
            try:
                entity = entity[0]
            except IndexError:
                entity = {}
            self.event_publisher.publish_statcounterinc_event(
                new_value[AlarmField.last_update_date.value],
                StatCounters.alarms_canceled,
                entity,
                new_value,
                event.get(self.AUTHOR))

        return alarm
Exemple #10
0
    def test_get_registeredtask(self):
        """
        Test to get registered task.
        """

        _id = 'a'
        register_tasks(force=True, **{_id: GetTaskTest})
        task = get_task(_id=_id)
        self.assertEqual(task, GetTaskTest)
Exemple #11
0
    def crop_flapping_steps(self, alarm):
        """
        Remove old state changes for alarms that are flapping over long periods
        of time.

        :param dict alarm: Alarm value

        :return: Alarm with cropped steps or alarm if nothing to remove
        :rtype: dict
        """

        p_steps = self.flapping_persistant_steps

        if p_steps < 0:
            self.logger.warning(
                "Peristant steps is {} (< 0) : aborting flapping steps crop "
                "operation".format(p_steps)
            )
            return alarm

        last_status_i = alarm[AlarmField.steps.value].index(
            alarm[AlarmField.status.value])

        state_changes = filter(
            lambda step: step['_t'] in ['stateinc', 'statedec'],
            alarm[AlarmField.steps.value][last_status_i + 1:]
        )

        number_to_crop = len(state_changes) - p_steps

        if not number_to_crop > 0:
            return alarm

        crop_counter = {}

        # Removed steps are supposed unique due to their timestamps, so as
        # `remove` method does not cause any collisions.
        for i in range(number_to_crop):
            # Increase statedec or stateinc counter
            t = state_changes[i]['_t']
            crop_counter[t] = crop_counter.get(t, 0) + 1

            # Increase {0,1,2,3} counter
            s = 'state:{}'.format(state_changes[i]['val'])
            crop_counter[s] = crop_counter.get(s, 0) + 1

            alarm[AlarmField.steps.value].remove(state_changes[i])

        task = get_task('alerts.crop.update_state_counter')
        alarm = task(alarm, crop_counter)

        return alarm
Exemple #12
0
    def crop_flapping_steps(self, alarm):
        """
        Remove old state changes for alarms that are flapping over long periods
        of time.

        :param dict alarm: Alarm value

        :return: Alarm with cropped steps or alarm if nothing to remove
        :rtype: dict
        """

        p_steps = self.flapping_persistant_steps

        if p_steps < 0:
            self.logger.warning(
                "Peristant steps is {} (< 0) : aborting flapping steps crop "
                "operation".format(p_steps)
            )
            return alarm

        last_status_i = alarm[AlarmField.steps.value].index(
            alarm[AlarmField.status.value])

        state_changes = filter(
            lambda step: step['_t'] in ['stateinc', 'statedec'],
            alarm[AlarmField.steps.value][last_status_i + 1:]
        )

        number_to_crop = len(state_changes) - p_steps

        if not number_to_crop > 0:
            return alarm

        crop_counter = {}

        # Removed steps are supposed unique due to their timestamps, so as
        # `remove` method does not cause any collisions.
        for i in range(number_to_crop):
            # Increase statedec or stateinc counter
            t = state_changes[i]['_t']
            crop_counter[t] = crop_counter.get(t, 0) + 1

            # Increase {0,1,2,3} counter
            s = 'state:{}'.format(state_changes[i]['val'])
            crop_counter[s] = crop_counter.get(s, 0) + 1

            alarm[AlarmField.steps.value].remove(state_changes[i])

        task = get_task('alerts.crop.update_state_counter')
        alarm = task(alarm, crop_counter)

        return alarm
Exemple #13
0
    def change_of_status(self, alarm, old_status, status, event):
        """
        Change status when ``update_status()`` detected a status
        change.

        :param alarm: Associated alarm to status change event
        :type alarm: dict

        :param old_status: Previous status
        :type old_status: int

        :param status: New status
        :type status: int

        :param event: Associated event
        :type event: dict

        :return: alarm with changed status
        :rtype: dict
        """

        if status > old_status:
            task = get_task(
                'alerts.systemaction.status_increase', cacheonly=True
            )

        elif status < old_status:
            task = get_task(
                'alerts.systemaction.status_decrease', cacheonly=True
            )

        value = alarm.get(self[Alerts.ALARM_STORAGE].VALUE)
        new_value = task(self, value, status, event)

        alarm[self[Alerts.ALARM_STORAGE].VALUE] = new_value

        return alarm
Exemple #14
0
    def test_comment(self):
        event = {'timestamp': 0}

        task = get_task('alerts.useraction.comment')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertFalse(alarm[AlarmField.comment.value] is None)
        self.assertEqual(alarm[AlarmField.comment.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.comment.value]['a'], 'testauthor')
        self.assertEqual(alarm[AlarmField.comment.value]['m'], 'test message')
Exemple #15
0
    def test_register_force(self):
        """
        Test to register existing tasks with force.
        """

        self.assertNotIn('d', TASKS_BY_ID)
        new_tasks = {'a': 'a', 'c': 'c', 'd': 'd'}
        old_tasks = register_tasks(
            force=True, **new_tasks
        )
        for new_task in new_tasks:
            self.assertEqual(get_task(new_task), new_tasks[new_task])
        self.assertNotIn('b', old_tasks)
        self_tasks_wo_b = self.tasks
        del self_tasks_wo_b['b']
        self.assertEqual(old_tasks, self_tasks_wo_b)
Exemple #16
0
    def test_acknowledge(self):
        event = {'timestamp': 0}

        task = get_task('alerts.useraction.ack')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm['ack'] is not None)
        self.assertEqual(alarm['ack']['t'], 0)
        self.assertEqual(alarm['ack']['a'], 'testauthor')
        self.assertEqual(alarm['ack']['m'], 'test message')
        self.assertTrue(alarm['ack'] is get_previous_step(alarm, 'ack'))
Exemple #17
0
    def archive(self, event):
        """
        Archive event in corresponding alarm history.

        :param event: Event to archive
        :type event: dict
        """

        entity = self[Alerts.CONTEXT_MANAGER].get_entity(event)
        entity_id = self[Alerts.CONTEXT_MANAGER].get_entity_id(entity)

        author = event.get('author', None)
        message = event.get('output', None)

        if event['event_type'] == Check.EVENT_TYPE:
            if event[Check.STATE] != Check.OK:
                self.make_alarm(entity_id, event)

            alarm = self.get_current_alarm(entity_id)

            if alarm is not None:
                self.archive_state(alarm, event[Check.STATE], event)

        else:
            try:
                task = get_task('alerts.useraction.{0}'.format(
                    event['event_type']
                ), cacheonly=True)

            except ImportError:
                task = None

            if task is not None:
                alarm = self.get_current_alarm(entity_id)
                value = alarm.get(self[Alerts.ALARM_STORAGE].VALUE)

                new_value = task(self, value, author, message, event)
                status = None

                if isinstance(new_value, tuple):
                    new_value, status = new_value

                self.update_current_alarm(alarm, new_value)

                if status is not None:
                    self.archive_status(alarm, status, event)
Exemple #18
0
    def test_cancel(self):
        event = {'timestamp': 0}

        task = get_task('alerts.useraction.cancel')
        alarm, statusval = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertEqual(statusval, CANCELED)
        self.assertTrue(alarm[AlarmField.canceled.value] is not None)
        self.assertEqual(alarm[AlarmField.canceled.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.canceled.value]['a'], 'testauthor')
        self.assertEqual(alarm[AlarmField.canceled.value]['m'], 'test message')
        self.assertTrue(
            alarm[AlarmField.canceled.value] is get_previous_step(alarm, 'cancel')
        )
Exemple #19
0
    def test_declare_ticket(self):
        event = {'timestamp': 0}

        task = get_task('alerts.useraction.declareticket')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm[AlarmField.ticket.value] is not None)
        self.assertEqual(alarm[AlarmField.ticket.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.ticket.value]['a'], 'testauthor')
        self.assertEqual(alarm[AlarmField.ticket.value]['m'], None)
        self.assertEqual(alarm[AlarmField.ticket.value]['val'], None)
        self.assertTrue(
            alarm[AlarmField.ticket.value] is get_previous_step(alarm, 'declareticket')
        )
Exemple #20
0
    def test_status_increase(self):
        event = {
            'connector': 'test',
            'connector_name': 'test0',
            'timestamp': 0,
            'output': 'test message'
        }
        statusval = 2

        task = get_task('alerts.systemaction.status_increase')
        alarm = task(self.manager, self.alarm, statusval, event)

        self.assertTrue(alarm['status'] is not None)
        self.assertEqual(alarm['status']['t'], 0)
        self.assertEqual(alarm['status']['a'], 'test.test0')
        self.assertEqual(alarm['status']['m'], 'test message')
        self.assertEqual(alarm['status']['val'], statusval)
        self.assertTrue(
            alarm['status'] is get_previous_step(alarm, 'statusinc')
        )
Exemple #21
0
    def test_state_increase(self):
        event = {
            'connector': 'test',
            'connector_name': 'test0',
            'timestamp': 0,
            'output': 'test message'
        }
        state = 2

        task = get_task('alerts.systemaction.state_increase')
        alarm, _ = task(self.manager, self.alarm, state, event)

        self.assertTrue(alarm[AlarmField.state.value] is not None)
        self.assertEqual(alarm[AlarmField.state.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.state.value]['a'], 'test.test0')
        self.assertEqual(alarm[AlarmField.state.value]['m'], 'test message')
        self.assertEqual(alarm[AlarmField.state.value]['val'], state)
        self.assertTrue(
            alarm[AlarmField.state.value] is get_previous_step(alarm, 'stateinc')
        )
Exemple #22
0
    def test_status_decrease(self):
        event = {
            'connector': 'test',
            'connector_name': 'test0',
            'timestamp': 0,
            'output': 'test message'
        }
        statusval = 0

        task = get_task('alerts.systemaction.status_decrease')
        alarm = task(self.manager, self.alarm, statusval, event)

        self.assertTrue(alarm[AlarmField.status.value] is not None)
        self.assertEqual(alarm[AlarmField.status.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.status.value]['a'], DEFAULT_AUTHOR)
        self.assertEqual(alarm[AlarmField.status.value]['m'], 'test message')
        self.assertEqual(alarm[AlarmField.status.value]['val'], statusval)
        self.assertTrue(
            alarm[AlarmField.status.value] is get_previous_step(alarm, 'statusdec')
        )
Exemple #23
0
    def test_unacknowledge(self):
        event = {'timestamp': 0}

        task = get_task('alerts.useraction.ackremove')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm[AlarmField.ack.value] is None)

        unack = get_previous_step(alarm, 'ackremove')
        self.assertEqual(unack['t'], 0)
        self.assertEqual(unack['a'], 'testauthor')
        self.assertEqual(unack['m'], 'test message')

        self.event_publisher.publish_statcounterinc_event.assert_not_called()
        self.event_publisher.publish_statduration_event.assert_not_called()
Exemple #24
0
    def check_hard_limit(self, alarm):
        """
        Update hard limit informations if number of steps has exceeded this
        limit.

        :param dict alarm: Alarm value

        :return: Alarm with hard limit informations or alarm if nothing to do
        :rtype: dict
        """

        limit = alarm.get(AlarmField.hard_limit.value, None)

        if limit is not None and limit['val'] >= self.hard_limit:
            return alarm

        if len(alarm[AlarmField.steps.value]) >= self.hard_limit:
            task = get_task('alerts.check.hard_limit')
            return task(self, alarm)

        return alarm
Exemple #25
0
    def check_hard_limit(self, alarm):
        """
        Update hard limit informations if number of steps has exceeded this
        limit.

        :param dict alarm: Alarm value

        :return: Alarm with hard limit informations or alarm if nothing to do
        :rtype: dict
        """

        limit = alarm.get(AlarmField.hard_limit.value, None)

        if limit is not None and limit['val'] >= self.hard_limit:
            return alarm

        if len(alarm[AlarmField.steps.value]) >= self.hard_limit:
            task = get_task('alerts.check.hard_limit')
            return task(self, alarm)

        return alarm
Exemple #26
0
    def event_processing(self, value):
        """
        Change of event_processing.

        :param value: new event_processing to use. If None or wrong value,
            event_processing is used
        :type value: NoneType, str or function
        """

        # by default, load default event processing
        if value is None:
            value = event_processing
        # if str, load the related function
        elif isinstance(value, basestring):
            try:
                value = get_task(value)
            except ImportError:
                self.logger.error(u'Impossible to load %s' % value)
                value = event_processing

        # set _event_processing and work
        self._event_processing = value
Exemple #27
0
    def event_processing(self, value):
        """
        Change of event_processing.

        :param value: new event_processing to use. If None or wrong value,
            event_processing is used
        :type value: NoneType, str or function
        """

        # by default, load default event processing
        if value is None:
            value = event_processing
        # if str, load the related function
        elif isinstance(value, basestring):
            try:
                value = get_task(value)
            except ImportError:
                self.logger.error(u'Impossible to load %s' % value)
                value = event_processing

        # set _event_processing and work
        self._event_processing = value
Exemple #28
0
    def check_hard_limit(self, alarm):
        """
        Update hard limit informations if number of steps has exceeded this
        limit.

        :param dict alarm: Alarm value

        :return: Alarm with hard limit informations or alarm if nothing to do
        :rtype: dict
        """

        limit = alarm.get('hard_limit', None)

        if limit is not None:
            if limit['val'] >= self.hard_limit:
                return alarm

        if len(alarm['steps']) >= self.hard_limit:
            task = get_task('alerts.systemaction.hard_limit')
            return task(self, alarm)

        else:
            return alarm
Exemple #29
0
    def test_assoc_ticket(self):
        event = {
            'timestamp': 0,
            'ticket': 1234
        }

        task = get_task('alerts.useraction.assocticket')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm['ticket'] is not None)
        self.assertEqual(alarm['ticket']['t'], 0)
        self.assertEqual(alarm['ticket']['a'], 'testauthor')
        self.assertEqual(alarm['ticket']['m'], 'test message')
        self.assertEqual(alarm['ticket']['val'], 1234)
        self.assertTrue(
            alarm['ticket'] is get_previous_step(alarm, 'assocticket')
        )
Exemple #30
0
    def test_change_state(self):
        event = {
            'timestamp': 0,
            'state': 2
        }

        task = get_task('alerts.useraction.changestate')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm['state'] is not None)
        self.assertEqual(alarm['state']['t'], 0)
        self.assertEqual(alarm['state']['a'], 'testauthor')
        self.assertEqual(alarm['state']['m'], 'test message')
        self.assertEqual(alarm['state']['val'], 2)
        self.assertTrue(
            alarm['state'] is get_previous_step(alarm, 'changestate')
        )
Exemple #31
0
    def _lookup(self, alarms, lookups):
        """
        Add extra keys to a list of alarms.

        :param list alarms: List of alarms as dict
        :param list lookups: List of extra keys to add.

        :return: Alarms with extra keys
        :rtype: list
        """

        for lookup in lookups:
            task = get_task(
                'alerts.lookup.{}'.format(lookup),
                cacheonly=True
            )

            if task is None:
                raise ValueError('Unknown lookup "{}"'.format(lookup))

            for alarm in alarms:
                alarm = task(self, alarm)

        return alarms
Exemple #32
0
    def test_change_state(self):
        event = {
            'timestamp': 0,
            'state': 2
        }

        task = get_task('alerts.useraction.changestate')
        alarm = task(
            self.manager,
            self.alarm,
            'testauthor',
            'test message',
            event
        )

        self.assertTrue(alarm[AlarmField.state.value] is not None)
        self.assertEqual(alarm[AlarmField.state.value]['t'], 0)
        self.assertEqual(alarm[AlarmField.state.value]['a'], 'testauthor')
        self.assertEqual(alarm[AlarmField.state.value]['m'], 'test message')
        self.assertEqual(alarm[AlarmField.state.value]['val'], 2)
        self.assertTrue(
            alarm[AlarmField.state.value] is get_previous_step(alarm, States.changestate.value)
        )
        self.assertTrue(is_keeped_state(alarm))
Exemple #33
0
    def _lookup(self, alarms, lookups):
        """
        Add extra keys to a list of alarms.

        :param list alarms: List of alarms as dict
        :param list lookups: List of extra keys to add.

        :return: Alarms with extra keys
        :rtype: list
        """

        for lookup in lookups:
            task = get_task(
                'alerts.lookup.{}'.format(lookup),
                cacheonly=True
            )

            if task is None:
                raise ValueError('Unknown lookup "{}"'.format(lookup))

            for alarm in alarms:
                alarm = task(self, alarm)

        return alarms
Exemple #34
0
    def change_of_state(self, alarm, old_state, state, event):
        """
        Change state when ``update_state()`` detected a state change.

        :param dict alarm: Associated alarm to state change event
        :param int old_state: Previous state
        :param int state: New state
        :param dict event: Associated event
        :return: alarm with changed state
        :rtype: dict
        """

        storage_value = self.alerts_storage.VALUE
        # Check for a forced state on this alarm
        if is_keeped_state(alarm['value']):
            if state == Check.OK:
                # Disengaging 'keepstate' flag
                alarm[storage_value][AlarmField.state.value]['_t'] = None
            else:
                self.logger.info('Entity {} not allowed to change state: '
                                 'ignoring'.format(alarm['data_id']))
                return alarm

        # Escalation
        if state > old_state:
            task = get_task('alerts.systemaction.state_increase',
                            cacheonly=True)

        elif state < old_state:
            task = get_task('alerts.systemaction.state_decrease',
                            cacheonly=True)

        # Executing task
        now = int(time())
        value = alarm.get(self.alerts_storage.VALUE)
        new_value, status = task(self, value, state, event)
        new_value[AlarmField.last_update_date.value] = now

        entity_id = alarm[self.alerts_storage.DATA_ID]
        try:
            entity = self.context_manager.get_entities_by_id(entity_id)[0]
        except IndexError:
            entity = {}

        # Send statistics event
        last_state_change = entity.get(Entity.LAST_STATE_CHANGE)
        if last_state_change:
            self.event_publisher.publish_statstateinterval_event(
                now, StatStateIntervals.time_in_state, now - last_state_change,
                old_state, entity, new_value)

        if state == AlarmState.CRITICAL:
            self.event_publisher.publish_statcounterinc_event(
                now, StatCounters.downtimes, entity, new_value,
                event.get(self.AUTHOR))

        # Update entity's last_state_change
        if entity:
            entity[Entity.LAST_STATE_CHANGE] = now
            self.context_manager.update_entity_body(entity)

        alarm[storage_value] = new_value

        return self.update_status(alarm, status, event)
Exemple #35
0
    def consolidation(
            self, serieconf, perfdatas, timewindow,
            period=None, usenan=True, fixed=True
    ):
        """
        Get consolidated point from serie.

        :param serieconf: Serie used for consolidation
        :type serieconf: dict

        :param perfdatas: Aggregated perfdatas from ``aggregation()`` method
        :type perfdatas: dict

        :param timewindow: Time window used for consolidation
        :type timewindow: canopsis.timeserie.timewindow.TimeWindow

        :returns: Consolidated points
        """

        # configure consolidation period (same as aggregation period)
        tw, period, usenan, fixed = self.get_timewindow_period_usenan_fixed(
            serieconf, timewindow, period, usenan, fixed
        )

        intervals = Interval.get_intervals_by_period(
            tw.start(),
            tw.stop(),
            period
        )

        points = []

        # generator consolidation operators
        operatorset = get_task('serie.operatorset')

        # generate one point per aggregation interval in timewindow
        for interval in intervals:
            tw = TimeWindow(
                start=interval['begin'],
                stop=interval['end'] - 1
            )

            # operators are acting on a specific timewindow
            operators = operatorset(self, period, perfdatas, tw, usenan)

            # execute formula in sand-boxed environment
            restricted_globals = {
                '__builtins__': safe_builtins,
            }

            restricted_globals.update(operators)

            formula = serieconf['formula']
            code = compile_restricted(formula, '<string>', 'eval')

            try:
                val = eval(code, restricted_globals)

            except Exception as ex:
                self.logger.warning(
                    'Wrong serie formula: {0}/{1} ({2})'.format(
                        serieconf['crecord_name'], formula, ex
                    )
                )
                val = float('nan')

            else:
                if isnan(val):
                    self.logger.warning(
                        'Formula result is nan: {0}/{1}.'.format(
                            serieconf['crecord_name'], formula
                        )
                    )

            # result contains consolidated value
            # point is computed at the start of interval
            points.append((interval['begin'], val))

        return points
Exemple #36
0
    def archive(self, event):
        """
        Archive event in corresponding alarm history.

        :param event: Event to archive
        :type event: dict
        """

        entity = self[Alerts.CONTEXT_MANAGER].get_entity(event)
        entity_id = self[Alerts.CONTEXT_MANAGER].get_entity_id(entity)

        author = event.get('author', None)
        message = event.get('output', None)

        if event['event_type'] == Check.EVENT_TYPE:
            alarm = self.get_current_alarm(entity_id)

            if alarm is None:
                if event[Check.STATE] == Check.OK:
                    # If a check event with an OK state concerns an entity for
                    # which no alarm is opened, there is no point continuing
                    return

                # Check is not OK
                alarm = self.make_alarm(entity_id, event)
                alarm = self.update_state(alarm, event[Check.STATE], event)

            else:  # Alarm is already opened
                value = alarm.get(self[Alerts.ALARM_STORAGE].VALUE)
                if self.is_hard_limit_reached(value):
                    return

                alarm = self.update_state(alarm, event[Check.STATE], event)

            value = alarm.get(self[Alerts.ALARM_STORAGE].VALUE)

            value = self.crop_flapping_steps(value)

            value = self.check_hard_limit(value)

            self.update_current_alarm(alarm, value)

        else:
            try:
                task = get_task('alerts.useraction.{0}'.format(
                    event['event_type']
                ), cacheonly=True)

            except ImportError:
                task = None

            if task is not None:
                alarm = self.get_current_alarm(entity_id)
                if alarm is None:
                    self.logger.warning(
                        'Entity {} has no current alarm : ignoring'.format(
                            entity_id
                        )
                    )
                    return

                value = alarm.get(self[Alerts.ALARM_STORAGE].VALUE)

                if self.is_hard_limit_reached(value):
                    # Only cancel is allowed when hard limit has been reached
                    if event['event_type'] != 'cancel':
                        return

                new_value = task(self, value, author, message, event)
                status = None

                if isinstance(new_value, tuple):
                    new_value, status = new_value

                new_value = self.check_hard_limit(new_value)

                self.update_current_alarm(alarm, new_value)

                if status is not None:
                    alarm = self.update_status(alarm, status, event)
                    new_value = alarm[self[Alerts.ALARM_STORAGE].VALUE]

                    self.update_current_alarm(alarm, new_value)
Exemple #37
0
    def test_update_state_counter(self):
        cases = [
            {
                'alarm': {
                    'status': {
                        'a': 'ut',
                        't': 0
                    },
                    'steps': [{'a': 'ut', 't': 0}]
                },
                'diff_counter': {},
                'expected_steps': [
                    {
                        'a': 'ut',
                        't': 0
                    },
                    {
                        '_t': 'statecounter',
                        'a': 'ut',
                        't': 0,
                        'm': '',
                        'val': {}
                    }
                ]
            },
            {
                'alarm': {
                    'status': {
                        'a': 'ut',
                        't': 0
                    },
                    'steps': [{'a': 'ut', 't': 0}]
                },
                'diff_counter': {'item': 0},
                'expected_steps': [
                    {
                        'a': 'ut',
                        't': 0
                    },
                    {
                        '_t': 'statecounter',
                        'a': 'ut',
                        't': 0,
                        'm': '',
                        'val': {'item': 0}
                    }
                ]
            },
            {
                'alarm': {
                    'status': {
                        'a': 'ut',
                        't': 0
                    },
                    'steps': [{'a': 'ut', 't': 0}, {'_t': 'customstep'}]
                },
                'diff_counter': {'item1': 10, 'item2': 15},
                'expected_steps': [
                    {
                        'a': 'ut',
                        't': 0
                    },
                    {
                        '_t': 'statecounter',
                        'a': 'ut',
                        't': 0,
                        'm': '',
                        'val': {'item1': 10, 'item2': 15}
                    },
                    {
                        '_t': 'customstep'
                    }
                ]
            },
            {
                'alarm': {
                    'status': {
                        'a': 'ut',
                        't': 0
                    },
                    'steps': [
                        {
                            'a': 'ut',
                            't': 0
                        },
                        {
                            '_t': 'statecounter',
                            'a': 'ut',
                            't': 0,
                            'm': '',
                            'val': {'item1': 3}
                        },
                        {
                            '_t': 'customstep'
                        }
                    ]
                },
                'diff_counter': {'item1': 2, 'item2': 4},
                'expected_steps': [
                    {
                        'a': 'ut',
                        't': 0
                    },
                    {
                        '_t': 'statecounter',
                        'a': 'ut',
                        't': 0,
                        'm': '',
                        'val': {'item1': 5, 'item2': 4}
                    },
                    {
                        '_t': 'customstep'
                    }
                ]
            },
            {
                'alarm': {
                    'status': {
                        'a': 'ut',
                        't': 10
                    },
                    'steps': [
                        {
                            'a': 'ut',
                            't': 0
                        },
                        {
                            '_t': 'statecounter',
                            'a': 'ut',
                            't': 0,
                            'm': '',
                            'val': {'item1': 3}
                        },
                        {
                            '_t': 'customstep'
                        },
                        {
                            'a': 'ut',
                            't': 10
                        }
                    ]
                },
                'diff_counter': {'item1': 2, 'item2': 4},
                'expected_steps': [
                    {
                        'a': 'ut',
                        't': 0
                    },
                    {
                        '_t': 'statecounter',
                        'a': 'ut',
                        't': 0,
                        'm': '',
                        'val': {'item1': 3}
                    },
                    {
                        '_t': 'customstep'
                    },
                    {
                        'a': 'ut',
                        't': 10
                    },
                    {
                        '_t': 'statecounter',
                        'a': 'ut',
                        't': 10,
                        'm': '',
                        'val': {'item1': 2, 'item2': 4}
                    }
                ]
            }
        ]

        task = get_task('alerts.systemaction.update_state_counter')
        for case in cases:
            alarm = task(case['alarm'], case['diff_counter'])

            self.assertEqual(alarm['steps'], case['expected_steps'])
Exemple #38
0
    def execute_task(self,
                     name,
                     event,
                     entity_id,
                     author=None,
                     new_state=None,
                     diff_counter=None):
        """
        Find and execute a task.

        :param str name: Name of the task to execute
        :param dict event: Event to archive
        :param str entity_id: Id of the alarm
        :param str author: If needed, the author of the event
        :param int new_state: If needed, the new state in the event
        :param int diff_counter: For crop events, the new value of the counter
        """
        # Find the corresponding task
        try:
            task = get_task(name, cacheonly=True)
            # FIXIT: https://git.canopsis.net/canopsis/canopsis/issues/298
            if not callable(task):
                raise ImportError('cannot import task "{}"'.format(name))

        except ImportError:
            self.logger.debug('Unknown task {}'.format(name))
            return

        # Find the corresponding alarm
        alarm = self.get_current_alarm(entity_id)
        if alarm is None:
            self.logger.debug(
                'Entity {} has no current alarm : ignoring'.format(entity_id))
            return

        value = alarm.get(self.alerts_storage.VALUE)

        if self.is_hard_limit_reached(value):
            # Only cancel and ack are allowed when hard limit has been reached
            if event['event_type'] != 'cancel' and event['event_type'] != 'ack':
                self.logger.debug('Hard limit reached. Cancelling')

                return

        # Execute the desired task
        if '.systemaction' in name:
            new_value = task(self, value, new_state, event)
        elif '.useraction' in name:
            message = event.get('output', None)
            new_value = task(self, value, author, message, event)
        elif '.lookup' in name or '.check' in name:
            new_value = task(self, value)
        elif '.crop' in name:
            new_value = task(self, value, diff_counter)
        else:
            self.logger.warning('Unknown task type for {}'.format(name))
            return

        # Some tasks return two values (a value and a status)
        status = None
        if isinstance(new_value, tuple):
            new_value, status = new_value

        if event['event_type'] != 'cancel' and event['event_type'] != 'ack':
            new_value = self.check_hard_limit(new_value)

        self.update_current_alarm(alarm, new_value)

        # If needed, update status
        if status is not None:
            alarm = self.update_status(alarm, status, event)
            new_value = alarm[self.alerts_storage.VALUE]

            self.update_current_alarm(alarm, new_value)

        return new_value
Exemple #39
0
    def change_of_state(self, alarm, old_state, state, event):
        """
        Change state when ``update_state()`` detected a state change.

        :param dict alarm: Associated alarm to state change event
        :param int old_state: Previous state
        :param int state: New state
        :param dict event: Associated event
        :return: alarm with changed state
        :rtype: dict
        """

        storage_value = self.alerts_storage.VALUE
        # Check for a forced state on this alarm
        if is_keeped_state(alarm['value']):
            if state == Check.OK:
                # Disengaging 'keepstate' flag
                alarm[storage_value][AlarmField.state.value]['_t'] = None
            else:
                self.logger.info('Entity {} not allowed to change state: '
                                 'ignoring'.format(alarm['data_id']))
                return alarm

        # Escalation
        if state > old_state:
            task = get_task(
                'alerts.systemaction.state_increase', cacheonly=True
            )

        elif state < old_state:
            task = get_task(
                'alerts.systemaction.state_decrease', cacheonly=True
            )

        # Executing task
        now = int(time())
        value = alarm.get(self.alerts_storage.VALUE)
        new_value, status = task(self, value, state, event)
        new_value[AlarmField.last_update_date.value] = now

        entity_id = alarm[self.alerts_storage.DATA_ID]
        try:
            entity = self.context_manager.get_entities_by_id(entity_id)[0]
        except IndexError:
            entity = {}

        # Send statistics event
        last_state_change = entity.get(Entity.LAST_STATE_CHANGE)
        if last_state_change:
            self.event_publisher.publish_statstateinterval_event(
                now,
                StatStateIntervals.time_in_state,
                now - last_state_change,
                old_state,
                entity,
                new_value)

        if state == AlarmState.CRITICAL:
            self.event_publisher.publish_statcounterinc_event(
                now,
                StatCounters.downtimes,
                entity,
                new_value,
                event.get(self.AUTHOR))

        # Update entity's last_state_change
        if entity:
            entity[Entity.LAST_STATE_CHANGE] = now
            self.context_manager.update_entity_body(entity)

        alarm[storage_value] = new_value

        return self.update_status(alarm, status, event)