aodh的告警计算代码分析

来源:互联网 发布:小黄鸭淘宝软件多少钱 编辑:程序博客网 时间:2024/06/18 11:44

        aodh的告警计算模块为aodh-evaluator

        1、aodh的启动,源码位于  aodh/aodh/evaluator/__init__.py  中的start

def start(self):
    super(AlarmEvaluationService, self).start()
    self.partition_coordinator.start()
    self.partition_coordinator.join_group(self.PARTITIONING_GROUP_NAME)
    # allow time for coordination if necessary
    
delay_start = self.partition_coordinator.is_active()
    if self.evaluators:
        interval = self.conf.evaluation_interval
        self.tg.add_timer(
            interval,
            self._evaluate_assigned_alarms,
            initial_delay=interval if delay_start elseNone)


2、告警分配 _evaluate_assigned_alarms,该功能应该是参考ceilometer的告警分配机制,每个计算模块,分配一定的告警规则

def_evaluate_assigned_alarms(self):
    try:
        alarms = self._assigned_alarms()
        LOG.info(_('initiating evaluation cycle on %d alarms') %
                 len(alarms))
        foralarm inalarms:
            self._evaluate_alarm(alarm)
    exceptException:
        LOG.exception(_('alarm evaluation cycle failed'))

    3、计算告警 _evaluate_alarm状态

def_evaluate_alarm(self, alarm):
    """Evaluate the alarms assigned to this evaluator."""
    
ifalarm.type not inself.evaluators:
        LOG.debug('skipping alarm %s: type unsupported', alarm.alarm_id)
        return

    
LOG.debug('evaluating alarm %s', alarm.alarm_id)
    try:
        self.evaluators[alarm.type].obj.evaluate(alarm)
    exceptException:
        LOG.exception(_('Failed to evaluate alarm %s'), alarm.alarm_id)


其中:evaluators 从entry_point中获取

EVALUATOR_EXTENSIONS_NAMESPACE ="aodh.evaluator"

self.evaluators = extension.ExtensionManager(
    namespace=self.EVALUATOR_EXTENSIONS_NAMESPACE,
    invoke_on_load=True,
    invoke_args=(self.conf,))

entry_points中,定义了如下扩展接口,分别表示不同的告警状态计算方式

[aodh.evaluator]
gnocchi_aggregation_by_metrics_threshold = aodh.evaluator.gnocchi:GnocchiAggregationMetricsThresholdEvaluator
combination = aodh.evaluator.combination:CombinationEvaluator
composite = aodh.evaluator.composite:CompositeEvaluator
gnocchi_resources_threshold = aodh.evaluator.gnocchi:GnocchiResourceThresholdEvaluator
gnocchi_aggregation_by_resources_threshold = aodh.evaluator.gnocchi:GnocchiAggregationResourcesThresholdEvaluator
threshold = aodh.evaluator.threshold:ThresholdEvaluator


当采用ceilometer alarm-gnocchi-resources-threshold-create创建告警的时候,告警类型是gnocchi_resources_threshold,统计信息的获取是调用gnocchi的api

如果采用ceilometer alarm-create,默认的告警类型是threshold,统计信息的获取是通过ceilometer

    4、gnocchi_resources_threshold  对应的告警计算源码位于 aodh/evaluator/gnocchi.py

       __statistics为实现每个资源的统计信息的获取方式
class GnocchiAggregationResourcesThresholdEvaluator(GnocchiBase):    def _statistics(self, rule, start, end):        # FIXME(sileht): In case of a heat autoscaling stack decide to        # delete an instance, the gnocchi metrics associated to this        # instance will be no more updated and when the alarm will ask        # for the aggregation, gnocchi will raise a 'No overlap'        # exception.        # So temporary set 'needed_overlap' to 0 to disable the        # gnocchi checks about missing points. For more detail see:        #   https://bugs.launchpad.net/gnocchi/+bug/1479429        try:            return self._gnocchi_client.metric.aggregation(                metrics=rule['metric'],                query=jsonutils.loads(rule['query']),                resource_type=rule["resource_type"],                start=start, stop=end,                aggregation=rule['aggregation_method'],                needed_overlap=0,            )        except Exception:            LOG.exception(_('alarm stats retrieval failed'))            return []
    5、GnocchiAggregationResourcesThresholdEvaluator的父类GnocchiBase代码如下:

       _sanitize根据告警规则,获取相应的统计周期下的数据:

classGnocchiBase(threshold.ThresholdEvaluator):
    def__init__(self, conf):
        super(GnocchiBase,self).__init__(conf)
        self._gnocchi_client = client.Client(
            '1', keystone_client.get_session(conf),
            interface=conf.service_credentials.interface,
            region_name=conf.service_credentials.region_name,
            endpoint_override=conf.gnocchi_url)

    @staticmethod
    def_sanitize(rule, statistics):
        """Return the datapoints that correspond to the alarm granularity"""
        #
TODO(sileht): if there's no direct match, but there is an archive
        
# policy with granularity that's an even divisor or the period,
        # we could potentially do a mean-of-means (or max-of-maxes or whatever,
        # but not a stddev-of-stddevs).
        #
TODO(sileht): support alarm['exclude_outliers']
        
LOG.debug('sanitize stats %s', statistics)
        statistics = [stats[2]forstats instatistics
                      ifstats[1] == rule['granularity']]
        statistics = statistics[-rule['evaluation_periods']:]
        LOG.debug('pruned statistics to %d',len(statistics))
        returnstatistics

    6、GnocchiBase的父类threshold.ThresholdEvaluator计算过程:

源码位于 aodh/evaluator/threshold.py中

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

    
state, trending_state, statistics, outside_count =self.evaluate_rule(
        alarm.rule)
    self._transition_alarm(alarm, state, trending_state, statistics,
                           outside_count)

    7、计算规则:

defevaluate_rule(self, alarm_rule):
    """Evaluate alarm rule.

    
:returns: state, trending state and statistics.
    """
    
start, end =self._bound_duration(alarm_rule)
    statistics = self._statistics(alarm_rule, start, end)
    statistics = self._sanitize(alarm_rule, statistics)
    sufficient = len(statistics) >= alarm_rule['evaluation_periods']
    if notsufficient:
        returnevaluator.UNKNOWN, None, statistics,len(statistics)

    def_compare(value):
        op = COMPARATORS[alarm_rule['comparison_operator']]
        limit = alarm_rule['threshold']
        LOG.debug('comparing value %(value)s against threshold'
                  ' %(limit)s'
, {'value': value, 'limit': limit})
        returnop(value, limit)

    compared = list(six.moves.map(_compare, statistics))
    distilled = all(compared)
    unequivocal = distilled or not any(compared)
    number_outside = len([cforc incompared ifc])

    ifunequivocal:
        state = evaluator.ALARMifdistilled elseevaluator.OK
        returnstate, None, statistics, number_outside
    else:
        trending_state = evaluator.ALARMifcompared[-1]elseevaluator.OK
        returnNone, trending_state, statistics, number_outside







0 0