Source code for aodh.evaluator.combination

#
# Copyright 2013 eNovance <licensing@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.


from oslo_log import log
from six import moves

from aodh import evaluator
from aodh.i18n import _, _LE

LOG = log.getLogger(__name__)

COMPARATORS = {'and': all, 'or': any}


[docs]class CombinationEvaluator(evaluator.Evaluator): def _get_alarm_state(self, alarm_id): try: alarms = self._storage_conn.get_alarms(alarm_id=alarm_id) except Exception: LOG.exception(_LE('alarm %s retrieval failed'), alarm_id) return None if not alarms: LOG.error(_LE("alarm %s doesn't exist anymore"), alarm_id) return None return list(alarms)[0].state def _sufficient_states(self, alarm, states): """Check for the sufficiency of the data for evaluation. Ensure that there is sufficient data for evaluation, transitioning to unknown otherwise. """ # note(sileht): alarm can be evaluated only with # stable state of other alarm alarms_missing_states = [alarm_id for alarm_id, state in states if not state or state == evaluator.UNKNOWN] sufficient = len(alarms_missing_states) == 0 if not sufficient and alarm.rule['operator'] == 'or': # if operator is 'or' and there is one alarm, then the combinated # alarm's state should be 'alarm' sufficient = bool([alarm_id for alarm_id, state in states if state == evaluator.ALARM]) if not sufficient and alarm.state != evaluator.UNKNOWN: reason = (_('Alarms %(alarm_ids)s' ' are in unknown state') % {'alarm_ids': ",".join(alarms_missing_states)}) reason_data = self._reason_data(alarms_missing_states) self._refresh(alarm, evaluator.UNKNOWN, reason, reason_data) return sufficient @staticmethod def _reason_data(alarm_ids): """Create a reason data dictionary for this evaluator type.""" return {'type': 'combination', 'alarm_ids': alarm_ids} @classmethod def _reason(cls, alarm, state, underlying_states): """Fabricate reason string.""" transition = alarm.state != state alarms_to_report = [alarm_id for alarm_id, alarm_state in underlying_states if alarm_state == state] reason_data = cls._reason_data(alarms_to_report) if transition: return (_('Transition to %(state)s due to alarms' ' %(alarm_ids)s in state %(state)s') % {'state': state, 'alarm_ids': ",".join(alarms_to_report)}), reason_data return (_('Remaining as %(state)s due to alarms' ' %(alarm_ids)s in state %(state)s') % {'state': state, 'alarm_ids': ",".join(alarms_to_report)}), reason_data def _transition(self, alarm, underlying_states): """Transition alarm state if necessary.""" op = alarm.rule['operator'] if COMPARATORS[op](s == evaluator.ALARM for __, s in underlying_states): state = evaluator.ALARM else: state = evaluator.OK continuous = alarm.repeat_actions reason, reason_data = self._reason(alarm, state, underlying_states) if alarm.state != state or continuous: self._refresh(alarm, state, reason, reason_data)
[docs] def evaluate(self, alarm): if not self.within_time_constraint(alarm): LOG.debug('Attempted to evaluate alarm %s, but it is not ' 'within its time constraint.', alarm.alarm_id) return states = zip(alarm.rule['alarm_ids'], moves.map(self._get_alarm_state, alarm.rule['alarm_ids'])) # states is consumed more than once, we need a list states = list(states) if self._sufficient_states(alarm, states): self._transition(alarm, states)

Project Source