Rewrite Aodh datasource

Implements: blueprint rewrite-aodh-datasource

Depends-On: I4b1140c20c68821eaf0849c9ee551ff9b1c27deb
Change-Id: Iaaa72dd5214f6d8168f4ba4560a6cec67d01d2a9
Signed-off-by: dongwenjuan <dong.wenjuan@zte.com.cn>
This commit is contained in:
dongwenjuan 2017-10-23 10:25:25 +08:00
parent 4e44ea6eeb
commit 501c0644d3
24 changed files with 1692 additions and 202 deletions

View File

@ -6,6 +6,7 @@ pbr!=2.1.0,>=2.0.0 # Apache-2.0
Babel!=2.4.0,>=2.3.4 # BSD
lxml!=3.7.0,>=3.4.1 # BSD
PyMySQL>=0.7.6 # MIT License
aodhclient>=0.9.0 # Apache-2.0
python-ceilometerclient>=2.5.0 # Apache-2.0
python-cinderclient>=3.2.0 # Apache-2.0
python-dateutil>=2.4.2 # BSD

View File

@ -19,6 +19,7 @@ from vitrage.common.constants import DatasourceProperties as DSProps
from vitrage.datasources.alarm_driver_base import AlarmDriverBase
from vitrage.datasources.aodh import AODH_DATASOURCE
from vitrage.datasources.aodh.properties import AodhEventType
from vitrage.datasources.aodh.properties import AodhExtendedAlarmType
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
from vitrage.datasources.aodh.properties import AodhState
from vitrage import os_clients
@ -34,12 +35,44 @@ class AodhDriver(AlarmDriverBase):
self._client = None
self.conf = conf
self._init_aodh_event_actions()
self._init_convert_aodh_alarm_rule_actions()
self._init_alarm_type_to_rule()
self._cache_all_alarms()
def _init_aodh_event_actions(self):
self.actions = {
AodhEventType.CREATION: self._convert_alarm_creation_event,
AodhEventType.RULE_CHANGE: self._convert_alarm_rule_change_event,
AodhEventType.STATE_TRANSITION:
self._convert_alarm_state_transition_event,
AodhEventType.DELETION: self._convert_alarm_deletion_event
}
def _init_convert_aodh_alarm_rule_actions(self):
self.convert_rule_actions = {
AodhExtendedAlarmType.VITRAGE:
self._convert_vitrage_alarm_rule,
AodhExtendedAlarmType.EVENT:
self._convert_event_alarm_rule,
AodhExtendedAlarmType.THRESHOLD:
self._convert_threshold_alarm_rule,
AodhExtendedAlarmType.GNOCCHI_RESOURCES_THRESHOLD:
self._convert_gnocchi_resources_threshold_alarm_rule
}
def _init_alarm_type_to_rule(self):
self.alarm_rule_types = {
AodhExtendedAlarmType.VITRAGE: AodhProps.EVENT_RULE,
AodhExtendedAlarmType.EVENT: AodhProps.EVENT_RULE,
AodhExtendedAlarmType.THRESHOLD: AodhProps.THRESHOLD_RULE,
AodhExtendedAlarmType.GNOCCHI_RESOURCES_THRESHOLD:
AodhProps.GNOCCHI_RESOURCES_THRESHOLD_RULE
}
@property
def client(self):
if not self._client:
self._client = os_clients.ceilometer_client(self.conf)
self._client = os_clients.aodh_client(self.conf)
return self._client
def _vitrage_type(self):
@ -55,7 +88,7 @@ class AodhDriver(AlarmDriverBase):
def _get_alarms(self):
try:
aodh_alarms = self.client.alarms.list()
aodh_alarms = self.client.alarm.list()
return [self._convert_alarm(alarm) for alarm in
aodh_alarms if alarm is not None]
except Exception as e:
@ -72,123 +105,37 @@ class AodhDriver(AlarmDriverBase):
def _is_valid(self, alarm):
return True
@classmethod
def _convert_event_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[AodhProps.EVENT_TYPE] = alarm.event_rule[AodhProps.EVENT_TYPE],
res[AodhProps.RESOURCE_ID] = _parse_query(alarm.event_rule,
AodhProps.EVENT_RESOURCE_ID)
return res
def _get_aodh_alarm_type(self, alarm):
@classmethod
def _convert_threshold_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[AodhProps.STATE_TIMESTAMP] = alarm.state_timestamp
res[AodhProps.RESOURCE_ID] = _parse_query(alarm.threshold_rule,
AodhProps.RESOURCE_ID)
return res
Aodh_type = [AodhExtendedAlarmType.EVENT,
AodhExtendedAlarmType.THRESHOLD,
AodhExtendedAlarmType.GNOCCHI_RESOURCES_THRESHOLD]
@classmethod
def _convert_gnocchi_resources_threshold(cls, alarm):
res = cls._convert_base_alarm_gnocchi(alarm)
if type(alarm) is not dict:
alarm = alarm.to_dict()
res[AodhProps.STATE_TIMESTAMP] = \
alarm.get(AodhProps.STATE_TIMESTAMP)
res[AodhProps.RESOURCE_ID] = \
alarm.get(AodhProps.GNOCCHI_RESOURCES_THRESHOLD_RULE,
{}).get(AodhProps.RESOURCE_ID)
else:
res[AodhProps.STATE_TIMESTAMP] = \
alarm.get(AodhProps.DETAIL, {}).get(AodhProps.STATE_TIMESTAMP)
res[AodhProps.RESOURCE_ID] = \
alarm.get(AodhProps.DETAIL,
{}).get(AodhProps.RULE,
{}).get(AodhProps.RESOURCE_ID)
return res
@classmethod
def _convert_vitrage_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[AodhProps.VITRAGE_ID] = _parse_query(alarm.event_rule,
AodhProps.VITRAGE_ID)
res[AodhProps.RESOURCE_ID] = _parse_query(alarm.event_rule,
AodhProps.RESOURCE_ID)
return res
@staticmethod
def _convert_base_dict_alarm_gnocchi(alarm):
detail = alarm.get(AodhProps.DETAIL)
return {
AodhProps.SEVERITY: alarm.get(AodhProps.SEVERITY),
AodhProps.PROJECT_ID: alarm.get(AodhProps.PROJECT_ID),
AodhProps.TIMESTAMP: alarm.get(AodhProps.TIMESTAMP),
AodhProps.TYPE: alarm.get(AodhProps.TYPE),
AodhProps.ALARM_ID: alarm.get(AodhProps.ALARM_ID),
AodhProps.DESCRIPTION: detail.get(AodhProps.DESCRIPTION),
AodhProps.ENABLED: detail.get(AodhProps.ENABLED),
AodhProps.NAME: detail.get(AodhProps.NAME),
AodhProps.REPEAT_ACTIONS: detail.get(AodhProps.REPEAT_ACTIONS),
AodhProps.STATE: detail.get(AodhProps.STATE)
}
@staticmethod
def _convert_base_non_dict_alarm_gnocchi(alarm):
alarm = alarm.to_dict()
return {
AodhProps.SEVERITY: alarm.get(AodhProps.SEVERITY),
AodhProps.DESCRIPTION: alarm.get(AodhProps.DESCRIPTION),
AodhProps.ENABLED: alarm.get(AodhProps.ENABLED),
AodhProps.ALARM_ID: alarm.get(AodhProps.ALARM_ID),
AodhProps.NAME: alarm.get(AodhProps.NAME),
AodhProps.PROJECT_ID: alarm.get(AodhProps.PROJECT_ID),
AodhProps.REPEAT_ACTIONS: alarm.get(AodhProps.REPEAT_ACTIONS),
AodhProps.STATE: alarm.get(AodhProps.STATE),
AodhProps.TIMESTAMP: alarm.get(AodhProps.TIMESTAMP),
AodhProps.TYPE: alarm.get(AodhProps.TYPE)
}
@classmethod
def _convert_base_alarm_gnocchi(cls, alarm):
"""distinguish between alarm received by notification (type dict)
to alarm received by _get_alarms() (type alarm).
"""
if type(alarm) is dict:
return cls._convert_base_dict_alarm_gnocchi(alarm)
return cls._convert_base_non_dict_alarm_gnocchi(alarm)
@staticmethod
def _convert_base_alarm(alarm):
return {
AodhProps.SEVERITY: alarm.severity,
AodhProps.DESCRIPTION: alarm.description,
AodhProps.ENABLED: alarm.enabled,
AodhProps.ALARM_ID: alarm.alarm_id,
AodhProps.NAME: alarm.name,
AodhProps.PROJECT_ID: alarm.project_id,
AodhProps.REPEAT_ACTIONS: alarm.repeat_actions,
AodhProps.STATE: alarm.state,
AodhProps.TIMESTAMP: alarm.timestamp,
AodhProps.TYPE: alarm.type
}
@classmethod
def _convert_alarm(cls, alarm):
alarm_type = alarm.type
alarm_type = alarm[AodhProps.TYPE]
if alarm_type == AodhProps.EVENT and \
_is_vitrage_alarm(alarm.event_rule):
return cls._convert_vitrage_alarm(alarm)
elif alarm_type == AodhProps.EVENT:
return cls._convert_event_alarm(alarm)
elif alarm_type == AodhProps.THRESHOLD:
return cls._convert_threshold_alarm(alarm)
elif alarm_type == AodhProps.GNOCCHI_RESOURCES_THRESHOLD:
return cls._convert_gnocchi_resources_threshold(alarm)
else:
_is_vitrage_alarm(alarm.get(AodhProps.EVENT_RULE)
or alarm.get(AodhProps.RULE)):
return AodhExtendedAlarmType.VITRAGE
elif alarm_type not in Aodh_type:
LOG.warning('Unsupported Aodh alarm of type %s' % alarm_type)
alarm_type = None
return alarm_type
def _convert_alarm(self, alarm):
entity = self._convert_alarm_common(alarm)
detail = self._convert_alarm_detail(alarm)
entity.update(detail)
alarm_type = self._get_aodh_alarm_type(alarm)
alarm_rule_type = self.alarm_rule_types[alarm_type]
alarm_rule = alarm[alarm_rule_type]
rule = self._convert_alarm_rule(alarm_type, alarm_rule)
entity.update(rule)
return entity
@staticmethod
def get_event_types():
@ -215,52 +162,27 @@ class AodhDriver(AlarmDriverBase):
AODH_DATASOURCE,
DatasourceAction.UPDATE)[0]
def _init_aodh_event_actions(self):
self.actions = {
AodhEventType.CREATION: self._convert_alarm_creation_event,
AodhEventType.RULE_CHANGE: self._convert_alarm_rule_change_event,
AodhEventType.STATE_TRANSITION:
self._convert_alarm_state_transition_event,
AodhEventType.DELETION: self._convert_alarm_deletion_event
}
@classmethod
def _convert_base_event(cls, event):
return {
AodhProps.PROJECT_ID: event[AodhProps.PROJECT_ID],
AodhProps.ALARM_ID: event[AodhProps.ALARM_ID],
AodhProps.SEVERITY: event[AodhProps.SEVERITY],
AodhProps.TIMESTAMP: event[AodhProps.TIMESTAMP],
}
@classmethod
def _convert_vitrage_alarm_event(cls, rule):
def _convert_vitrage_alarm_rule(cls, rule):
return {
AodhProps.VITRAGE_ID: _parse_query(rule, AodhProps.VITRAGE_ID),
AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID)
}
@classmethod
def _convert_threshold_alarm_event(cls, event):
rule = event[AodhProps.DETAIL][AodhProps.RULE]
def _convert_threshold_alarm_rule(cls, rule):
return {
AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID),
AodhProps.STATE_TIMESTAMP: event[AodhProps.STATE_TIMESTAMP]
AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID)
}
@classmethod
def _convert_gnocchi_resources_threshold_alarm_event(cls, event):
def _convert_gnocchi_resources_threshold_alarm_rule(cls, rule):
return {
AodhProps.RESOURCE_ID: event.get(
AodhProps.DETAIL, {}).get(AodhProps.RULE,
{}).get(AodhProps.RESOURCE_ID),
AodhProps.STATE_TIMESTAMP:
event.get(AodhProps.DETAIL, {}).get(AodhProps.STATE_TIMESTAMP)
AodhProps.RESOURCE_ID: _parse_query(rule, AodhProps.RESOURCE_ID)
}
@classmethod
def _convert_event_alarm_event(cls, rule):
def _convert_event_alarm_rule(cls, rule):
return {
AodhProps.EVENT_TYPE: rule[AodhProps.EVENT_TYPE],
AodhProps.RESOURCE_ID:
@ -268,32 +190,37 @@ class AodhDriver(AlarmDriverBase):
}
@classmethod
def _convert_detail_event(cls, event):
alarm_info = event[AodhProps.DETAIL]
alarm_rule = alarm_info[AodhProps.RULE]
entity_detail = {
AodhProps.DESCRIPTION: alarm_info[AodhProps.DESCRIPTION],
AodhProps.ENABLED: alarm_info[AodhProps.ENABLED],
AodhProps.NAME: alarm_info[AodhProps.NAME],
AodhProps.STATE: alarm_info[AodhProps.STATE],
AodhProps.REPEAT_ACTIONS: alarm_info[AodhProps.REPEAT_ACTIONS],
AodhProps.TYPE: alarm_info[AodhProps.TYPE]
def _convert_alarm_common(cls, alarm):
return {
AodhProps.ALARM_ID: alarm.get(AodhProps.ALARM_ID),
AodhProps.USER_ID: alarm.get(AodhProps.USER_ID),
AodhProps.PROJECT_ID: alarm.get(AodhProps.PROJECT_ID),
AodhProps.SEVERITY: alarm.get(AodhProps.SEVERITY),
AodhProps.TIMESTAMP: alarm.get(AodhProps.TIMESTAMP)
}
if _is_vitrage_alarm(alarm_rule):
entity_detail.update(cls._convert_vitrage_alarm_event(alarm_rule))
elif entity_detail[AodhProps.TYPE] == AodhProps.EVENT:
entity_detail.update(cls._convert_event_alarm_event(alarm_rule))
elif entity_detail[AodhProps.TYPE] == AodhProps.THRESHOLD:
entity_detail.update(
cls._convert_threshold_alarm_event(event))
elif entity_detail[AodhProps.TYPE] == \
AodhProps.GNOCCHI_RESOURCES_THRESHOLD:
entity_detail.update(
cls._convert_gnocchi_resources_threshold(event))
@classmethod
def _convert_alarm_detail(cls, alarm):
return entity_detail
return {
AodhProps.DESCRIPTION: alarm.get(AodhProps.DESCRIPTION),
AodhProps.ENABLED: alarm.get(AodhProps.ENABLED),
AodhProps.NAME: alarm.get(AodhProps.NAME),
AodhProps.STATE: alarm.get(AodhProps.STATE),
AodhProps.REPEAT_ACTIONS: alarm.get(AodhProps.REPEAT_ACTIONS),
AodhProps.TYPE: alarm.get(AodhProps.TYPE),
AodhProps.STATE_TIMESTAMP: alarm.get(AodhProps.STATE_TIMESTAMP),
AodhProps.STATE_REASON: alarm.get(AodhProps.STATE_REASON)
}
def _convert_alarm_rule(self, alarm_type, alarm_rule):
if alarm_type in self.convert_rule_actions:
entity = self.convert_rule_actions[alarm_type](alarm_rule)
else:
LOG.warning('Unsupported Aodh alarm type %s' % alarm_type)
return None
return entity
@classmethod
def _parse_changed_rule(cls, change_rule):
@ -312,10 +239,17 @@ class AodhDriver(AlarmDriverBase):
return entity
def _convert_alarm_creation_event(self, event):
entity = self._convert_base_event(event)
detail = self._convert_detail_event(event)
entity = self._convert_alarm_common(event)
alarm_info = event[AodhProps.DETAIL]
detail = self._convert_alarm_detail(alarm_info)
entity.update(detail)
alarm_type = self._get_aodh_alarm_type(alarm_info)
alarm_rule = alarm_info[AodhProps.RULE]
rule_info = self._convert_alarm_rule(alarm_type, alarm_rule)
entity.update(rule_info)
return self._filter_and_cache_alarm(entity, None,
self._filter_get_erroneous,
datetime_utils.utcnow(False))
@ -358,14 +292,6 @@ class AodhDriver(AlarmDriverBase):
except Exception as e:
LOG.exception("Failed to Convert alarm state"
" transition event - %s", e)
try:
state = event[AodhProps.DETAIL] # type unicode
unicode_to_str = state.encode("ascii")
str_to_dict = eval(unicode_to_str)
entity[AodhProps.STATE] = str_to_dict[AodhProps.STATE]
except Exception as e:
LOG.exception("Failed to Convert alarm state "
"transition event - %s", e)
return self._filter_and_cache_alarm(entity, old_alarm,
self._filter_get_change,

View File

@ -18,6 +18,7 @@ class AodhProperties(object):
DESCRIPTION = 'description'
ENABLED = 'enabled'
EVENT = 'event'
EVENT_RULE = 'event_rule'
EVENT_TYPE = 'event_type'
EVENT_RESOURCE_ID = 'traits.resource_id'
NAME = 'name'
@ -29,6 +30,7 @@ class AodhProperties(object):
SEVERITY = 'severity'
STATE_TIMESTAMP = 'state_timestamp'
THRESHOLD = 'threshold'
THRESHOLD_RULE = 'threshold_rule'
GNOCCHI_RESOURCES_THRESHOLD = 'gnocchi_resources_threshold'
TIMESTAMP = 'timestamp'
TYPE = 'type'
@ -36,6 +38,8 @@ class AodhProperties(object):
DETAIL = 'detail'
RULE = 'rule'
GNOCCHI_RESOURCES_THRESHOLD_RULE = 'gnocchi_resources_threshold_rule'
USER_ID = 'user_id'
STATE_REASON = 'state_reason'
class AodhState(object):
@ -49,3 +53,10 @@ class AodhEventType(object):
RULE_CHANGE = 'alarm.rule_change'
STATE_TRANSITION = 'alarm.state_transition'
DELETION = 'alarm.deletion'
class AodhExtendedAlarmType(object):
EVENT = 'event'
VITRAGE = 'vitrage'
THRESHOLD = 'threshold'
GNOCCHI_RESOURCES_THRESHOLD = 'gnocchi_resources_threshold'

View File

@ -0,0 +1,44 @@
# Copyright 2016 - Nokia
#
# 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_config import cfg
from vitrage.common.constants import DatasourceOpts as DSOpts
from vitrage.common.constants import UpdateMethod
CEILOMETER_DATASOURCE = 'ceilometer'
OPTS = [
cfg.StrOpt(DSOpts.TRANSFORMER,
default='vitrage.datasources.ceilometer.'
'transformer.CeilometerTransformer',
help='Ceilometer transformer class path',
required=True),
cfg.StrOpt(DSOpts.DRIVER,
default='vitrage.datasources.ceilometer.'
'driver.CeilometerDriver',
help='ceilometer driver class path',
required=True),
cfg.StrOpt(DSOpts.UPDATE_METHOD,
default=UpdateMethod.PUSH,
help='None: updates only via Vitrage periodic snapshots.'
'Pull: updates every [changes_interval] seconds.'
'Push: updates by getting notifications from the'
' datasource itself.',
required=True),
cfg.IntOpt(DSOpts.CHANGES_INTERVAL,
default=10,
min=10,
help='interval between checking changes'
'in ceilometer data source'),
]

View File

@ -0,0 +1,385 @@
# Copyright 2016 - Alcatel-Lucent
#
# 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 vitrage.common.constants import DatasourceAction
from vitrage.common.constants import DatasourceProperties as DSProps
from vitrage.datasources.alarm_driver_base import AlarmDriverBase
from vitrage.datasources.ceilometer import CEILOMETER_DATASOURCE
from vitrage.datasources.ceilometer.properties \
import CeilometerEventType as CeilEventType
from vitrage.datasources.ceilometer.properties \
import CeilometerProperties as CeilProps
from vitrage.datasources.ceilometer.properties \
import CeilometerState as CeilState
from vitrage import os_clients
from vitrage.utils import datetime as datetime_utils
LOG = log.getLogger(__name__)
class CeilometerDriver(AlarmDriverBase):
def __init__(self, conf):
super(CeilometerDriver, self).__init__()
self._client = None
self.conf = conf
self._init_aodh_event_actions()
self._cache_all_alarms()
@property
def client(self):
if not self._client:
self._client = os_clients.ceilometer_client(self.conf)
return self._client
def _vitrage_type(self):
return CEILOMETER_DATASOURCE
def _alarm_key(self, alarm):
return alarm[CeilProps.ALARM_ID]
def _cache_all_alarms(self):
alarms = self._get_alarms()
self._filter_and_cache_alarms(alarms,
self._filter_get_valid)
def _get_alarms(self):
try:
aodh_alarms = self.client.alarms.list()
return [self._convert_alarm(alarm) for alarm in
aodh_alarms if alarm is not None]
except Exception as e:
LOG.exception("Failed to get all alarms, Exception: %s", e)
return []
def _is_erroneous(self, alarm):
return alarm and alarm[CeilProps.STATE] == CeilState.ALARM
def _status_changed(self, alarm1, alarm2):
return alarm1 and alarm2 and \
not alarm1[CeilProps.STATE] == alarm2[CeilProps.STATE]
def _is_valid(self, alarm):
return True
@classmethod
def _convert_event_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[CeilProps.EVENT_TYPE] = alarm.event_rule[CeilProps.EVENT_TYPE],
res[CeilProps.RESOURCE_ID] = _parse_query(alarm.event_rule,
CeilProps.EVENT_RESOURCE_ID)
return res
@classmethod
def _convert_threshold_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[CeilProps.STATE_TIMESTAMP] = alarm.state_timestamp
res[CeilProps.RESOURCE_ID] = _parse_query(alarm.threshold_rule,
CeilProps.RESOURCE_ID)
return res
@classmethod
def _convert_gnocchi_resources_threshold(cls, alarm):
res = cls._convert_base_alarm_gnocchi(alarm)
if type(alarm) is not dict:
alarm = alarm.to_dict()
res[CeilProps.STATE_TIMESTAMP] = \
alarm.get(CeilProps.STATE_TIMESTAMP)
res[CeilProps.RESOURCE_ID] = \
alarm.get(CeilProps.GNOCCHI_RESOURCES_THRESHOLD_RULE,
{}).get(CeilProps.RESOURCE_ID)
else:
res[CeilProps.STATE_TIMESTAMP] = \
alarm.get(CeilProps.DETAIL, {}).get(CeilProps.STATE_TIMESTAMP)
res[CeilProps.RESOURCE_ID] = \
alarm.get(CeilProps.DETAIL,
{}).get(CeilProps.RULE,
{}).get(CeilProps.RESOURCE_ID)
return res
@classmethod
def _convert_vitrage_alarm(cls, alarm):
res = cls._convert_base_alarm(alarm)
res[CeilProps.VITRAGE_ID] = _parse_query(alarm.event_rule,
CeilProps.VITRAGE_ID)
res[CeilProps.RESOURCE_ID] = _parse_query(alarm.event_rule,
CeilProps.RESOURCE_ID)
return res
@staticmethod
def _convert_base_dict_alarm_gnocchi(alarm):
detail = alarm.get(CeilProps.DETAIL)
return {
CeilProps.SEVERITY: alarm.get(CeilProps.SEVERITY),
CeilProps.PROJECT_ID: alarm.get(CeilProps.PROJECT_ID),
CeilProps.TIMESTAMP: alarm.get(CeilProps.TIMESTAMP),
CeilProps.TYPE: alarm.get(CeilProps.TYPE),
CeilProps.ALARM_ID: alarm.get(CeilProps.ALARM_ID),
CeilProps.DESCRIPTION: detail.get(CeilProps.DESCRIPTION),
CeilProps.ENABLED: detail.get(CeilProps.ENABLED),
CeilProps.NAME: detail.get(CeilProps.NAME),
CeilProps.REPEAT_ACTIONS: detail.get(CeilProps.REPEAT_ACTIONS),
CeilProps.STATE: detail.get(CeilProps.STATE)
}
@staticmethod
def _convert_base_non_dict_alarm_gnocchi(alarm):
alarm = alarm.to_dict()
return {
CeilProps.SEVERITY: alarm.get(CeilProps.SEVERITY),
CeilProps.DESCRIPTION: alarm.get(CeilProps.DESCRIPTION),
CeilProps.ENABLED: alarm.get(CeilProps.ENABLED),
CeilProps.ALARM_ID: alarm.get(CeilProps.ALARM_ID),
CeilProps.NAME: alarm.get(CeilProps.NAME),
CeilProps.PROJECT_ID: alarm.get(CeilProps.PROJECT_ID),
CeilProps.REPEAT_ACTIONS: alarm.get(CeilProps.REPEAT_ACTIONS),
CeilProps.STATE: alarm.get(CeilProps.STATE),
CeilProps.TIMESTAMP: alarm.get(CeilProps.TIMESTAMP),
CeilProps.TYPE: alarm.get(CeilProps.TYPE)
}
@classmethod
def _convert_base_alarm_gnocchi(cls, alarm):
"""distinguish between alarm received by notification (type dict)
to alarm received by _get_alarms() (type alarm).
"""
if type(alarm) is dict:
return cls._convert_base_dict_alarm_gnocchi(alarm)
return cls._convert_base_non_dict_alarm_gnocchi(alarm)
@staticmethod
def _convert_base_alarm(alarm):
return {
CeilProps.SEVERITY: alarm.severity,
CeilProps.DESCRIPTION: alarm.description,
CeilProps.ENABLED: alarm.enabled,
CeilProps.ALARM_ID: alarm.alarm_id,
CeilProps.NAME: alarm.name,
CeilProps.PROJECT_ID: alarm.project_id,
CeilProps.REPEAT_ACTIONS: alarm.repeat_actions,
CeilProps.STATE: alarm.state,
CeilProps.TIMESTAMP: alarm.timestamp,
CeilProps.TYPE: alarm.type
}
@classmethod
def _convert_alarm(cls, alarm):
alarm_type = alarm.type
if alarm_type == CeilProps.EVENT and \
_is_vitrage_alarm(alarm.event_rule):
return cls._convert_vitrage_alarm(alarm)
elif alarm_type == CeilProps.EVENT:
return cls._convert_event_alarm(alarm)
elif alarm_type == CeilProps.THRESHOLD:
return cls._convert_threshold_alarm(alarm)
elif alarm_type == CeilProps.GNOCCHI_RESOURCES_THRESHOLD:
return cls._convert_gnocchi_resources_threshold(alarm)
else:
LOG.warning('Unsupported Ceilometer alarm type %s' % alarm_type)
@staticmethod
def get_event_types():
# Add event_types to receive notifications about
return [CeilEventType.CREATION,
CeilEventType.STATE_TRANSITION,
CeilEventType.RULE_CHANGE,
CeilEventType.DELETION]
def enrich_event(self, event, event_type):
if event_type in self.actions:
entity = self.actions[event_type](event)
else:
LOG.warning('Unsupported Ceilometer event type %s' % event_type)
return None
# Don't need to update entity, only update the cache
if entity is None:
return None
entity[DSProps.EVENT_TYPE] = event_type
return CeilometerDriver.make_pickleable(
[entity], CEILOMETER_DATASOURCE,
DatasourceAction.UPDATE)[0]
def _init_aodh_event_actions(self):
self.actions = {
CeilEventType.CREATION:
self._convert_alarm_creation_event,
CeilEventType.RULE_CHANGE:
self._convert_alarm_rule_change_event,
CeilEventType.STATE_TRANSITION:
self._convert_alarm_state_transition_event,
CeilEventType.DELETION:
self._convert_alarm_deletion_event
}
@classmethod
def _convert_base_event(cls, event):
return {
CeilProps.PROJECT_ID: event[CeilProps.PROJECT_ID],
CeilProps.ALARM_ID: event[CeilProps.ALARM_ID],
CeilProps.SEVERITY: event[CeilProps.SEVERITY],
CeilProps.TIMESTAMP: event[CeilProps.TIMESTAMP],
CeilProps.USER_ID: event[CeilProps.USER_ID]
}
@classmethod
def _convert_vitrage_alarm_rule(cls, rule):
return {
CeilProps.VITRAGE_ID: _parse_query(rule, CeilProps.VITRAGE_ID),
CeilProps.RESOURCE_ID: _parse_query(rule, CeilProps.RESOURCE_ID)
}
@classmethod
def _convert_threshold_alarm_rule(cls, rule):
return {
CeilProps.RESOURCE_ID: _parse_query(rule, CeilProps.RESOURCE_ID),
}
@classmethod
def _convert_gnocchi_resources_threshold_alarm_rule(cls, rule):
return {
CeilProps.RESOURCE_ID: _parse_query(rule, CeilProps.RESOURCE_ID),
}
@classmethod
def _convert_event_alarm_rule(cls, rule):
return {
CeilProps.EVENT_TYPE: rule[CeilProps.EVENT_TYPE],
CeilProps.RESOURCE_ID:
_parse_query(rule, CeilProps.EVENT_RESOURCE_ID)
}
@classmethod
def _convert_detail_event(cls, event):
alarm_info = event[CeilProps.DETAIL]
alarm_rule = alarm_info[CeilProps.RULE]
entity_detail = {
CeilProps.DESCRIPTION: alarm_info[CeilProps.DESCRIPTION],
CeilProps.ENABLED: alarm_info[CeilProps.ENABLED],
CeilProps.NAME: alarm_info[CeilProps.NAME],
CeilProps.STATE: alarm_info[CeilProps.STATE],
CeilProps.REPEAT_ACTIONS: alarm_info[CeilProps.REPEAT_ACTIONS],
CeilProps.TYPE: alarm_info[CeilProps.TYPE],
CeilProps.STATE_TIMESTAMP: alarm_info[CeilProps.STATE_TIMESTAMP],
CeilProps.STATE_REASON: alarm_info[CeilProps.STATE_REASON]
}
if _is_vitrage_alarm(alarm_rule):
entity_detail.update(cls._convert_vitrage_alarm_rule(alarm_rule))
elif entity_detail[CeilProps.TYPE] == CeilProps.EVENT:
entity_detail.update(cls._convert_event_alarm_rule(alarm_rule))
elif entity_detail[CeilProps.TYPE] == CeilProps.THRESHOLD:
entity_detail.update(
cls._convert_threshold_alarm_rule(alarm_rule))
elif entity_detail[CeilProps.TYPE] == \
CeilProps.GNOCCHI_RESOURCES_THRESHOLD:
entity_detail.update(
cls._convert_gnocchi_resources_threshold_alarm_rule(
alarm_rule))
return entity_detail
@classmethod
def _parse_changed_rule(cls, change_rule):
entity = {}
if CeilProps.EVENT_TYPE in change_rule:
entity[CeilProps.EVENT_TYPE] = change_rule[CeilProps.EVENT_TYPE]
if 'query' in change_rule:
event_resource_id = \
_parse_query(change_rule, CeilProps.EVENT_RESOURCE_ID)
resource_id = \
_parse_query(change_rule, CeilProps.RESOURCE_ID)
if event_resource_id or resource_id:
entity[CeilProps.RESOURCE_ID] = event_resource_id if \
event_resource_id is not None else resource_id
return entity
def _convert_alarm_creation_event(self, event):
entity = self._convert_base_event(event)
detail = self._convert_detail_event(event)
entity.update(detail)
return self._filter_and_cache_alarm(entity, None,
self._filter_get_erroneous,
datetime_utils.utcnow(False))
def _convert_alarm_rule_change_event(self, event):
"""handle alarm rule change notification
example of changed rule:
"detail": {"severity": "critical",
"rule":
{"query": [{"field": "traits.resource_id",
"type": "",
"value": "1",
"op": "eq"}],
"event_type": "instance.update"}}
"""
old_alarm = self._old_alarm(event)
entity = old_alarm.copy()
changed_rule = event[CeilProps.DETAIL]
for (changed_type, changed_info) in changed_rule.items():
# handle changed rule which may effect the neighbor
if changed_type == CeilProps.RULE:
entity.update(self._parse_changed_rule(
changed_rule[changed_type]))
# handle other changed alarm properties
elif changed_type in CeilProps.__dict__.values():
entity[changed_type] = changed_info
return self._filter_and_cache_alarm(entity, old_alarm,
self._filter_get_erroneous,
datetime_utils.utcnow(False))
def _convert_alarm_state_transition_event(self, event):
old_alarm = self._old_alarm(event)
entity = old_alarm.copy()
try:
entity[CeilProps.STATE] = event[CeilProps.DETAIL][CeilProps.STATE]
except Exception as e:
LOG.exception("Failed to Convert alarm state"
" transition event - %s", e)
return self._filter_and_cache_alarm(entity, old_alarm,
self._filter_get_change,
datetime_utils.utcnow(False))
def _convert_alarm_deletion_event(self, event):
alarm_key = self._alarm_key(event)
alarm = self.cache.pop(alarm_key)[0]
return alarm if self._is_erroneous(alarm) else None
def _parse_query(data, key):
query_fields = data.get(CeilProps.QUERY, {})
for query in query_fields:
field = query['field']
if field == key:
return query['value']
return None
def _is_vitrage_alarm(rule):
return _parse_query(rule, CeilProps.VITRAGE_ID) is not None

View File

@ -0,0 +1,53 @@
# Copyright 2016 - Nokia
#
# 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.
class CeilometerProperties(object):
ALARM_ID = 'alarm_id'
DESCRIPTION = 'description'
ENABLED = 'enabled'
EVENT = 'event'
EVENT_TYPE = 'event_type'
EVENT_RESOURCE_ID = 'traits.resource_id'
NAME = 'name'
STATE = 'state'
PROJECT_ID = 'project_id'
QUERY = 'query'
REPEAT_ACTIONS = 'repeat_actions'
RESOURCE_ID = 'resource_id'
SEVERITY = 'severity'
STATE_TIMESTAMP = 'state_timestamp'
THRESHOLD = 'threshold'
GNOCCHI_RESOURCES_THRESHOLD = 'gnocchi_resources_threshold'
TIMESTAMP = 'timestamp'
TYPE = 'type'
VITRAGE_ID = 'vitrage_id'
DETAIL = 'detail'
RULE = 'rule'
GNOCCHI_RESOURCES_THRESHOLD_RULE = 'gnocchi_resources_threshold_rule'
USER_ID = 'user_id'
STATE_REASON = 'state_reason'
class CeilometerState(object):
OK = 'ok'
ALARM = 'alarm'
INSUFFICIENT_DATA = 'insufficient_data'
class CeilometerEventType(object):
CREATION = 'alarm.creation'
RULE_CHANGE = 'alarm.rule_change'
STATE_TRANSITION = 'alarm.state_transition'
DELETION = 'alarm.deletion'

View File

@ -0,0 +1,167 @@
# Copyright 2016 - Nokia
#
# 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 vitrage.common.constants import DatasourceProperties as DSProps
from vitrage.common.constants import EdgeLabel
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import GraphAction
from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.alarm_transformer_base import AlarmTransformerBase
from vitrage.datasources.ceilometer import CEILOMETER_DATASOURCE
from vitrage.datasources.ceilometer.properties \
import CeilometerEventType as CeilEventType
from vitrage.datasources.ceilometer.properties \
import CeilometerProperties as CeilProps
from vitrage.datasources.ceilometer.properties \
import CeilometerState as CeilState
from vitrage.datasources import transformer_base as tbase
from vitrage.datasources.transformer_base import Neighbor
from vitrage.datasources.transformer_base import TransformerBase
from vitrage.evaluator.actions.evaluator_event_transformer \
import VITRAGE_DATASOURCE
import vitrage.graph.utils as graph_utils
from vitrage.utils import datetime as datetime_utils
class CeilometerTransformer(AlarmTransformerBase):
# Event types which need to refer them differently
GRAPH_ACTION_MAPPING = {
CeilEventType.DELETION: GraphAction.DELETE_ENTITY,
}
def __init__(self, transformers, conf):
super(CeilometerTransformer, self).__init__(transformers, conf)
def _create_snapshot_entity_vertex(self, entity_event):
if _is_vitrage_alarm(entity_event):
return self._create_merge_alarm_vertex(entity_event)
return self._create_vertex(entity_event)
def _create_update_entity_vertex(self, entity_event):
if _is_vitrage_alarm(entity_event):
return self._create_merge_alarm_vertex(entity_event)
return self._create_vertex(entity_event)
def _create_vertex(self, entity_event):
metadata = {
VProps.NAME: entity_event[CeilProps.NAME],
VProps.SEVERITY: entity_event[CeilProps.SEVERITY],
CeilProps.DESCRIPTION: entity_event[CeilProps.DESCRIPTION],
CeilProps.ENABLED: entity_event[CeilProps.ENABLED],
VProps.PROJECT_ID: entity_event.get(CeilProps.PROJECT_ID, None),
CeilProps.REPEAT_ACTIONS: entity_event[CeilProps.REPEAT_ACTIONS],
VProps.RESOURCE_ID: entity_event[CeilProps.RESOURCE_ID],
'alarm_type': entity_event[CeilProps.TYPE]
}
# TODO(annarez): convert EVENT_TYPE to tuple
if entity_event[CeilProps.TYPE] == CeilProps.EVENT:
metadata[CeilProps.EVENT_TYPE] = \
entity_event[CeilProps.EVENT_TYPE]
elif entity_event[CeilProps.TYPE] == CeilProps.THRESHOLD:
metadata[CeilProps.STATE_TIMESTAMP] = \
entity_event[CeilProps.STATE_TIMESTAMP]
vitrage_sample_timestamp = entity_event[DSProps.SAMPLE_DATE]
update_timestamp = self._format_update_timestamp(
CeilometerTransformer._timestamp(entity_event),
vitrage_sample_timestamp)
return graph_utils.create_vertex(
self._create_entity_key(entity_event),
vitrage_category=EntityCategory.ALARM,
vitrage_type=entity_event[DSProps.ENTITY_TYPE],
vitrage_sample_timestamp=vitrage_sample_timestamp,
entity_id=entity_event[CeilProps.ALARM_ID],
entity_state=self._get_alarm_state(entity_event),
update_timestamp=update_timestamp,
metadata=metadata)
def _create_snapshot_neighbors(self, entity_event):
return self._create_aodh_neighbors(entity_event)
def _create_update_neighbors(self, entity_event):
return self._create_aodh_neighbors(entity_event)
def _create_aodh_neighbors(self, entity_event):
graph_neighbors = entity_event.get(self.QUERY_RESULT, [])
result = []
for vertex in graph_neighbors:
edge = graph_utils.create_edge(
source_id=TransformerBase.uuid_from_deprecated_vitrage_id(
self._create_entity_key(entity_event)),
target_id=vertex.vertex_id,
relationship_type=EdgeLabel.ON)
result.append(Neighbor(vertex, edge))
return result
def _create_merge_alarm_vertex(self, entity_event):
"""Handle an alarm that already has a vitrage_id
This is a deduced alarm created in aodh by vitrage, so it already
exists in the graph.
This function will update the exiting vertex (and not create a new one)
"""
metadata = {
CeilProps.DESCRIPTION: entity_event[CeilProps.DESCRIPTION],
VProps.PROJECT_ID: entity_event[CeilProps.PROJECT_ID],
}
vitrage_sample_timestamp = entity_event[DSProps.SAMPLE_DATE]
update_timestamp = self._format_update_timestamp(
CeilometerTransformer._timestamp(entity_event),
vitrage_sample_timestamp)
return graph_utils.create_vertex(
self._create_entity_key(entity_event),
vitrage_category=EntityCategory.ALARM,
vitrage_type=VITRAGE_DATASOURCE,
vitrage_sample_timestamp=vitrage_sample_timestamp,
entity_id=entity_event.get(CeilProps.ALARM_ID),
update_timestamp=update_timestamp,
metadata=metadata)
def _ok_status(self, entity_event):
return entity_event[CeilProps.STATE] != CeilState.ALARM
def _create_entity_key(self, entity_event):
if _is_vitrage_alarm(entity_event):
return entity_event.get(CeilProps.VITRAGE_ID)
entity_type = entity_event[DSProps.ENTITY_TYPE]
alarm_id = entity_event[CeilProps.ALARM_ID]
return tbase.build_key((EntityCategory.ALARM, entity_type, alarm_id))
@staticmethod
def _timestamp(entity_event):
return datetime_utils.change_time_str_format(
entity_event[CeilProps.TIMESTAMP],
'%Y-%m-%dT%H:%M:%S.%f',
tbase.TIMESTAMP_FORMAT)
@staticmethod
def get_enrich_query(event):
affected_resource_id = event.get(CeilProps.RESOURCE_ID, None)
if not affected_resource_id:
return None
return {VProps.ID: affected_resource_id}
def get_vitrage_type(self):
return CEILOMETER_DATASOURCE
def _is_vitrage_alarm(entity_event):
return entity_event.get(CeilProps.VITRAGE_ID) is not None

View File

@ -41,7 +41,7 @@ class AodhNotifier(NotifierBase):
def __init__(self, conf):
super(AodhNotifier, self).__init__(conf)
self.client = os_clients.ceilometer_client(conf)
self.client = os_clients.aodh_client(conf)
def process_event(self, data, event_type):
response = None
@ -62,7 +62,7 @@ class AodhNotifier(NotifierBase):
alarm_request = _alarm_request(alarm, state)
try:
LOG.info('Aodh Alarm - Activate: ' + str(alarm_request))
return self.client.alarms.create(**alarm_request)
return self.client.alarm.create(alarm_request)
except Exception as e:
LOG.exception('Failed to activate Aodh Alarm Got Exception: %s', e)
return
@ -71,7 +71,9 @@ class AodhNotifier(NotifierBase):
aodh_id = alarm.get(VProps.ID)
try:
LOG.info('Aodh Alarm $%s update state %s', aodh_id, state)
return self.client.alarms.update(alarm_id=aodh_id, state=state)
alarm_update = {AodhState: state}
return self.client.alarm.update(alarm_id=aodh_id,
alarm_update=alarm_update)
except Exception as e:
LOG.exception('Failed to update Aodh Alarm Got Exception: %s', e)
return

View File

@ -22,6 +22,7 @@ LOG = log.getLogger(__name__)
OPTS = [
cfg.StrOpt('aodh_version', default='2', help='Aodh version'),
cfg.StrOpt('ceilometer_version', default='2', help='Ceilometer version'),
cfg.StrOpt('nova_version', default='2.11', help='Nova version'),
cfg.StrOpt('cinder_version', default='2', help='Cinder version'),
cfg.StrOpt('glance_version', default='2', help='Glance version'),
@ -30,6 +31,7 @@ OPTS = [
]
_client_modules = {
'aodh': 'aodhclient.client',
'ceilometer': 'ceilometerclient.client',
'nova': 'novaclient.client',
'cinder': 'cinderclient.client',
@ -46,13 +48,26 @@ def driver_module(driver):
return module
def aodh_client(conf):
"""Get an instance of aodh client"""
try:
aodh_client = driver_module('aodh')
client = aodh_client.Client(
conf.aodh_version,
session=keystone_client.get_session(conf))
LOG.info('Aodh client created')
return client
except Exception as e:
LOG.exception('Create Aodh client - Got Exception: %s', e)
def ceilometer_client(conf):
"""Get an instance of ceilometer client"""
auth_config = conf.service_credentials
try:
cm_client = driver_module('ceilometer')
client = cm_client.get_client(
version=conf.aodh_version,
version=conf.ceilometer_version,
session=keystone_client.get_session(conf),
region_name=auth_config.region_name,
interface=auth_config.interface,

View File

@ -14,6 +14,7 @@
from oslo_config import cfg
from vitrage.common.constants import DatasourceProperties as DSProp
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.aodh import AODH_DATASOURCE
@ -57,7 +58,8 @@ class TestAodhAlarms(TestDataSourcesBase):
self.assertEqual(self._num_total_expected_vertices(),
len(processor.entity_graph))
detail = {TransformerBase.QUERY_RESULT: ''}
detail = {TransformerBase.QUERY_RESULT: '',
DSProp.ENTITY_TYPE: AODH_DATASOURCE}
spec_list = \
mock_transformer.simple_aodh_alarm_generators(alarm_num=1,
snapshot_events=1,

View File

@ -0,0 +1,15 @@
# Copyright 2017 - ZTE
#
# 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.
__author__ = 'stack'

View File

@ -0,0 +1,94 @@
# Copyright 2016 - ZTE, Nokia
#
# 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_config import cfg
from vitrage.common.constants import DatasourceProperties as DSProp
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.ceilometer import CEILOMETER_DATASOURCE
from vitrage.datasources.ceilometer.properties \
import CeilometerProperties as CeilProps
from vitrage.datasources import NOVA_HOST_DATASOURCE
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
from vitrage.datasources import NOVA_ZONE_DATASOURCE
from vitrage.datasources.transformer_base import TransformerBase
from vitrage.tests.functional.datasources.base import \
TestDataSourcesBase
from vitrage.tests.mocks import mock_transformer
class TestCeilometerAlarms(TestDataSourcesBase):
DATASOURCES_OPTS = [
cfg.ListOpt('types',
default=[CEILOMETER_DATASOURCE,
NOVA_HOST_DATASOURCE,
NOVA_INSTANCE_DATASOURCE,
NOVA_ZONE_DATASOURCE],
help='Names of supported driver data sources'),
cfg.ListOpt('path',
default=['vitrage.datasources'],
help='base path for data sources')
]
# noinspection PyPep8Naming
@classmethod
def setUpClass(cls):
super(TestCeilometerAlarms, cls).setUpClass()
cls.conf = cfg.ConfigOpts()
cls.conf.register_opts(cls.PROCESSOR_OPTS, group='entity_graph')
cls.conf.register_opts(cls.DATASOURCES_OPTS, group='datasources')
cls.load_datasources(cls.conf)
def test_ceilometer_alarms_validity(self):
# Setup
processor = self._create_processor_with_graph(self.conf)
self.assertEqual(self._num_total_expected_vertices(),
len(processor.entity_graph))
detail = {TransformerBase.QUERY_RESULT: '',
DSProp.ENTITY_TYPE: CEILOMETER_DATASOURCE}
spec_list = \
mock_transformer.simple_aodh_alarm_generators(alarm_num=1,
snapshot_events=1,
snap_vals=detail)
static_events = mock_transformer.generate_random_events_list(spec_list)
aodh_event = static_events[0]
aodh_event[CeilProps.RESOURCE_ID] = \
self._find_entity_id_by_type(processor.entity_graph,
NOVA_HOST_DATASOURCE)
# Action
processor.process_event(aodh_event)
# Test assertions
self.assertEqual(self._num_total_expected_vertices() + 1,
len(processor.entity_graph))
aodh_vertices = processor.entity_graph.get_vertices(
vertex_attr_filter={
VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
VProps.VITRAGE_TYPE: CEILOMETER_DATASOURCE
})
self.assertEqual(1, len(aodh_vertices))
aodh_neighbors = processor.entity_graph.neighbors(
aodh_vertices[0].vertex_id)
self.assertEqual(1, len(aodh_neighbors))
self.assertEqual(NOVA_HOST_DATASOURCE,
aodh_neighbors[0][VProps.VITRAGE_TYPE])

View File

@ -0,0 +1,15 @@
# Copyright 2017 - ZTE
#
# 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.
__author__ = 'stack'

View File

@ -0,0 +1,119 @@
# Copyright 2017 - ZTE, Nokia
#
# 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 vitrage.common.constants import DatasourceAction
from vitrage.common.constants import DatasourceProperties as DSProps
from vitrage.common.constants import EdgeLabel
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import GraphAction
from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
from vitrage.datasources.ceilometer.properties \
import CeilometerProperties as CeilProps
from vitrage.datasources.ceilometer.properties import CeilometerState
from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
from vitrage.datasources.transformer_base import TransformerBase
from vitrage.graph.driver.elements import Vertex
from vitrage.tests import base
class CeilometerTransformerBaseTest(base.BaseTest):
def _validate_aodh_vertex_props(self, vertex, event):
self.assertEqual(EntityCategory.ALARM,
vertex[VProps.VITRAGE_CATEGORY])
self.assertEqual(event[DSProps.ENTITY_TYPE],
vertex[VProps.VITRAGE_TYPE])
self.assertEqual(event[CeilProps.NAME], vertex[VProps.NAME])
self.assertEqual(event[CeilProps.SEVERITY],
vertex[VProps.SEVERITY])
self.assertEqual(event[CeilProps.DESCRIPTION],
vertex[CeilProps.DESCRIPTION])
self.assertEqual(event[CeilProps.ENABLED],
vertex[CeilProps.ENABLED])
self.assertEqual(event[CeilProps.PROJECT_ID],
vertex[VProps.PROJECT_ID])
self.assertEqual(event[CeilProps.REPEAT_ACTIONS],
vertex[CeilProps.REPEAT_ACTIONS])
self.assertEqual(event[CeilProps.TYPE], vertex['alarm_type'])
if event[CeilProps.TYPE] == CeilProps.EVENT:
self.assertEqual(event[CeilProps.EVENT_TYPE],
vertex[CeilProps.EVENT_TYPE])
elif event[CeilProps.TYPE] == CeilProps.THRESHOLD:
self.assertEqual(event[CeilProps.STATE_TIMESTAMP],
vertex[CeilProps.STATE_TIMESTAMP])
self.assertEqual(event[DSProps.SAMPLE_DATE],
vertex[VProps.VITRAGE_SAMPLE_TIMESTAMP])
event_status = event[CeilProps.STATE]
if event_status == CeilometerState.OK:
self.assertEqual(AlarmProps.INACTIVE_STATE,
vertex[VProps.STATE])
else:
self.assertEqual(AlarmProps.ACTIVE_STATE,
vertex[VProps.STATE])
self.assertFalse(vertex[VProps.VITRAGE_IS_PLACEHOLDER])
self.assertFalse(vertex[VProps.VITRAGE_IS_DELETED])
def _validate_action(self, alarm, wrapper):
if DSProps.EVENT_TYPE in alarm \
and alarm[DSProps.EVENT_TYPE] in GraphAction.__dict__.values():
self.assertEqual(alarm[DSProps.EVENT_TYPE], wrapper.action)
return
ds_action = alarm[DSProps.DATASOURCE_ACTION]
if ds_action in (DatasourceAction.SNAPSHOT, DatasourceAction.UPDATE):
self.assertEqual(GraphAction.UPDATE_ENTITY, wrapper.action)
else:
self.assertEqual(GraphAction.CREATE_ENTITY, wrapper.action)
def _validate_neighbors(self, neighbors, alarm_id, event):
resource_counter = 0
for neighbor in neighbors:
resource_id = event[CeilProps.RESOURCE_ID]
self._validate_instance_neighbor(neighbor,
resource_id,
alarm_id)
resource_counter += 1
self.assertEqual(1,
resource_counter,
'Alarm can be belonged to only one resource')
def _validate_instance_neighbor(self,
alarm_neighbor,
resource_id,
alarm_vertex_id):
# validate neighbor vertex
self.assertEqual(EntityCategory.RESOURCE,
alarm_neighbor.vertex[VProps.VITRAGE_CATEGORY])
self.assertEqual(NOVA_INSTANCE_DATASOURCE,
alarm_neighbor.vertex[VProps.VITRAGE_TYPE])
self.assertEqual(resource_id, alarm_neighbor.vertex[VProps.ID])
self.assertFalse(alarm_neighbor.vertex[VProps.VITRAGE_IS_PLACEHOLDER])
self.assertFalse(alarm_neighbor.vertex[VProps.VITRAGE_IS_DELETED])
# Validate neighbor edge
edge = alarm_neighbor.edge
self.assertEqual(edge.target_id, alarm_neighbor.vertex.vertex_id)
self.assertEqual(edge.source_id, alarm_vertex_id)
self.assertEqual(edge.label, EdgeLabel.ON)
def _convert_dist_to_vertex(self, neighbor):
ver_id = neighbor[VProps.VITRAGE_CATEGORY] + \
TransformerBase.KEY_SEPARATOR + neighbor[VProps.VITRAGE_TYPE] + \
TransformerBase.KEY_SEPARATOR + neighbor[VProps.ID]
return Vertex(vertex_id=ver_id, properties=neighbor)

View File

@ -0,0 +1,27 @@
# Copyright 2017 - Nokia
#
# 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 vitrage.datasources.ceilometer.driver import CeilometerDriver
class MockCeilometerDriver(CeilometerDriver):
"""A aodh driver for tests.
"""
def __init__(self, conf):
super(MockCeilometerDriver, self).__init__(conf)
def _cache_all_alarms(self):
pass

View File

@ -0,0 +1,389 @@
# Copyright 2017 - ZTE, Nokia
#
# 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_config import cfg
from vitrage.common.constants import DatasourceOpts as DSOpts
from vitrage.common.constants import DatasourceProperties as DSProps
from vitrage.common.constants import UpdateMethod
from vitrage.datasources.ceilometer import CEILOMETER_DATASOURCE
from vitrage.datasources.ceilometer.properties import CeilometerEventType
from vitrage.datasources.ceilometer.properties \
import CeilometerProperties as CeilProps
from vitrage.tests import base
from vitrage.tests.mocks import mock_driver
from vitrage.tests.unit.datasources.ceilometer.mock_driver \
import MockCeilometerDriver
class CeilometerDriverTest(base.BaseTest):
OPTS = [
cfg.StrOpt(DSOpts.UPDATE_METHOD,
default=UpdateMethod.PUSH),
]
# noinspection PyPep8Naming
@classmethod
def setUpClass(cls):
cls.conf = cfg.ConfigOpts()
cls.conf.register_opts(cls.OPTS, group=CEILOMETER_DATASOURCE)
def test_event_alarm_notifications(self):
aodh_driver = MockCeilometerDriver(self.conf)
# 1. alarm creation with 'ok' state
# prepare data
detail_data = {"type": "creation",
CeilProps.DETAIL: self._create_alarm_data_type_event(),
}
generators = \
mock_driver.simple_aodh_alarm_notification_generators(
alarm_num=1,
update_events=1,
update_vals=detail_data)
alarm = mock_driver.generate_sequential_events_list(generators)[0]
alarm_info = alarm.copy()
# action
entity = aodh_driver.enrich_event(alarm, CeilometerEventType.CREATION)
# Test assertions
# alarm with status OK should not be handled
self.assertIsNone(entity)
# 2.alarm state transition from 'ok' to 'alarm'
detail_data = {"type": "state transition",
CeilProps.DETAIL: {CeilProps.STATE: "alarm"}}
alarm.update(detail_data)
entity = aodh_driver.enrich_event(alarm,
CeilometerEventType.STATE_TRANSITION)
# Test assertions
# alarm state change: ok->alarm, need to be added
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[CeilProps.STATE],
alarm[CeilProps.DETAIL][CeilProps.STATE])
self.assertEqual(entity[CeilProps.SEVERITY],
alarm[CeilProps.SEVERITY])
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.STATE_TRANSITION)
# 3. delete alarm which is 'alarm' state
# prepare data
detail_data = {"type": "deletion"}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.DELETION)
# Test assertions
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.DELETION)
# 4. alarm creation with 'alarm' state
# prepare data
detail_data = {"type": "creation",
CeilProps.DETAIL:
self._create_alarm_data_type_event(state="alarm")}
generators = \
mock_driver.simple_aodh_alarm_notification_generators(
alarm_num=1,
update_events=1,
update_vals=detail_data)
alarm = mock_driver.generate_sequential_events_list(generators)[0]
alarm_info = alarm.copy()
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.CREATION)
# Test assertions
# alarm with status 'alarm' need to be added
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[CeilProps.STATE],
alarm[CeilProps.DETAIL][CeilProps.STATE])
self.assertEqual(entity[CeilProps.SEVERITY],
alarm[CeilProps.SEVERITY])
self.assertIsNone(entity[CeilProps.RESOURCE_ID])
self.assertEqual("*", entity[CeilProps.EVENT_TYPE])
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.CREATION)
# 5. alarm rule change
# prepare data
detail_data = {"type": "rule change",
CeilProps.DETAIL: {
"severity": "critical",
CeilProps.RULE:
{"query": [{"field": "traits.resource_id",
"type": "",
"value": "1",
"op": "eq"}],
"event_type": "instance.update"}}}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.RULE_CHANGE)
# Test assertions
# alarm rule change: need to be update
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[CeilProps.SEVERITY],
alarm[CeilProps.DETAIL][CeilProps.SEVERITY])
self.assertEqual(
entity[CeilProps.EVENT_TYPE],
alarm[CeilProps.DETAIL][CeilProps.RULE][CeilProps.EVENT_TYPE])
self.assertEqual("1", entity[CeilProps.RESOURCE_ID])
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.RULE_CHANGE)
# 6. alarm state change from 'alarm' to 'ok'
# prepare data
detail_data = {"type": "state transition",
CeilProps.DETAIL: {CeilProps.STATE: "ok"}}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.STATE_TRANSITION)
# Test assertions
# alarm state change: alarm->OK, need to be deleted
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.STATE_TRANSITION)
# 7. delete alarm which is 'ok' state
# prepare data
detail_data = {"type": "deletion"}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.DELETION)
# Test assertions
self.assertIsNone(entity)
def test_gnocchi_threshold_alarm_notifications(self):
aodh_driver = MockCeilometerDriver(self.conf)
# 1. alarm creation with 'ok' state
# prepare data
detail_data = {"type": "gnocchi_resources_threshold",
CeilProps.DETAIL: self._create_alarm_data_gnocchi()}
generators = \
mock_driver.simple_aodh_alarm_notification_generators(
alarm_num=1,
update_events=1,
update_vals=detail_data)
alarm = mock_driver.generate_sequential_events_list(generators)[0]
alarm_info = alarm.copy()
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.CREATION)
# Test assertions
# alarm with status OK should not be handled
self.assertIsNone(entity)
# 2.alarm state transition from 'ok' to 'alarm'
detail_data = {"type": "state transition",
CeilProps.DETAIL: {CeilProps.STATE: "alarm"}}
alarm.update(detail_data)
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.STATE_TRANSITION)
# Test assertions
# alarm state change: ok->alarm, need to be added
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[CeilProps.STATE],
alarm[CeilProps.DETAIL][CeilProps.STATE])
self.assertEqual(entity[CeilProps.SEVERITY],
alarm[CeilProps.SEVERITY])
# 3. delete alarm which is 'alarm' state
# prepare data
detail_data = {"type": "deletion"}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.DELETION)
# Test assertions
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.DELETION)
# 4. alarm creation with 'alarm' state
# prepare data
detail_data = {"type": "gnocchi_resources_threshold",
CeilProps.DETAIL:
self._create_alarm_data_gnocchi(state="alarm")}
generators = \
mock_driver.simple_aodh_alarm_notification_generators(
alarm_num=1,
update_events=1,
update_vals=detail_data)
alarm = mock_driver.generate_sequential_events_list(generators)[0]
alarm_info = alarm.copy()
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.CREATION)
# Test assertions
# alarm with status 'alarm' need to be added
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[CeilProps.STATE],
alarm[CeilProps.DETAIL][CeilProps.STATE])
self.assertEqual(entity[CeilProps.SEVERITY],
alarm[CeilProps.SEVERITY])
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.CREATION)
# 5. alarm rule change
# prepare data
detail_data = {"type": "rule change",
CeilProps.DETAIL: {
"severity": "critical",
CeilProps.RULE:
{"granularity": "300",
"threshold": "0.0123",
"comparison_operator": "eq"}}}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.RULE_CHANGE)
# Test assertions
# alarm rule change: need to be update
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[CeilProps.SEVERITY],
alarm[CeilProps.DETAIL][CeilProps.SEVERITY])
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.RULE_CHANGE)
# 6. alarm state change from 'alarm' to 'ok'
# prepare data
detail_data = {"type": "state transition",
CeilProps.DETAIL: {CeilProps.STATE: "ok"}}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm,
CeilometerEventType.STATE_TRANSITION)
# Test assertions
# alarm state change: alarm->OK, need to be deleted
self.assertIsNotNone(entity)
self._validate_aodh_entity_comm_props(entity, alarm_info)
self.assertEqual(entity[DSProps.EVENT_TYPE],
CeilometerEventType.STATE_TRANSITION)
# 7. delete alarm which is 'ok' state
# prepare data
detail_data = {"type": "deletion"}
alarm.update(detail_data)
# action
entity = aodh_driver.enrich_event(
alarm, CeilometerEventType.DELETION)
# Test assertions
self.assertIsNone(entity)
def _create_alarm_data_gnocchi(self,
state="ok",
type="gnocchi_resources_threshold",
rule=None):
if rule is None:
rule = {"granularity": "300",
"threshold": "0.001",
"comparison_operator": "gt",
"resource_type": "instance"
}
return {CeilProps.DESCRIPTION: "test",
CeilProps.TIMESTAMP: "2016-11-09T01:39:13.839584",
CeilProps.ENABLED: True,
CeilProps.STATE_TIMESTAMP: "2016-11-09T01:39:13.839584",
CeilProps.ALARM_ID: "7e5c3754-e2eb-4782-ae00-7da5ded8568b",
CeilProps.REPEAT_ACTIONS: False,
CeilProps.PROJECT_ID: "c365d18fcc03493187016ae743f0cc4d",
CeilProps.NAME: "test",
CeilProps.SEVERITY: "low",
CeilProps.RESOURCE_ID: "88cd2d1d-8af4-4d00-9b5e-f82f8c8b0f8d",
CeilProps.TYPE: type,
CeilProps.STATE: state,
CeilProps.RULE: rule,
CeilProps.STATE_REASON: 'for test'}
def _create_alarm_data_type_event(self,
state="ok",
type="event",
rule=None):
if rule is None:
rule = {"query": [], "event_type": "*"}
return {CeilProps.DESCRIPTION: "test",
CeilProps.TIMESTAMP: "2016-11-09T01:39:13.839584",
CeilProps.ENABLED: True,
CeilProps.STATE_TIMESTAMP: "2016-11-09T01:39:13.839584",
CeilProps.ALARM_ID: "7e5c3754-e2eb-4782-ae00-7da5ded8568b",
CeilProps.REPEAT_ACTIONS: False,
CeilProps.PROJECT_ID: "c365d18fcc03493187016ae743f0cc4d",
CeilProps.NAME: "test",
CeilProps.SEVERITY: "low",
CeilProps.TYPE: type,
CeilProps.STATE: state,
CeilProps.RULE: rule,
CeilProps.STATE_REASON: 'for test'}
def _validate_aodh_entity_comm_props(self, entity, alarm):
self.assertEqual(entity[CeilProps.ALARM_ID],
alarm[CeilProps.ALARM_ID])
self.assertEqual(entity[CeilProps.PROJECT_ID],
alarm[CeilProps.PROJECT_ID])
self.assertEqual(entity[CeilProps.TIMESTAMP],
alarm[CeilProps.TIMESTAMP])
self.assertEqual(entity[CeilProps.DESCRIPTION],
alarm[CeilProps.DETAIL][CeilProps.DESCRIPTION])
self.assertEqual(entity[CeilProps.ENABLED],
alarm[CeilProps.DETAIL][CeilProps.ENABLED])
self.assertEqual(entity[CeilProps.NAME],
alarm[CeilProps.DETAIL][CeilProps.NAME])
self.assertEqual(entity[CeilProps.REPEAT_ACTIONS],
alarm[CeilProps.DETAIL][CeilProps.REPEAT_ACTIONS])
self.assertEqual(entity[CeilProps.TYPE],
alarm[CeilProps.DETAIL][CeilProps.TYPE])

View File

@ -0,0 +1,161 @@
# Copyright 2016 - ZTE, Nokia
#
# 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_config import cfg
from oslo_log import log as logging
from vitrage.common.constants import DatasourceOpts as DSOpts
from vitrage.common.constants import DatasourceProperties as DSProps
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import UpdateMethod
from vitrage.datasources.ceilometer import CEILOMETER_DATASOURCE
from vitrage.datasources.ceilometer.properties \
import CeilometerProperties as CeilProps
from vitrage.datasources.ceilometer.transformer import CeilometerTransformer
from vitrage.datasources.transformer_base import TransformerBase
from vitrage.tests.mocks import mock_transformer as mock_sync
from vitrage.tests.unit.datasources.ceilometer.\
ceilometer_transformer_base_test \
import CeilometerTransformerBaseTest
LOG = logging.getLogger(__name__)
class TestCeilometerAlarmTransformer(CeilometerTransformerBaseTest):
OPTS = [
cfg.StrOpt(DSOpts.UPDATE_METHOD,
default=UpdateMethod.PULL),
]
@classmethod
def setUpClass(cls):
cls.transformers = {}
cls.conf = cfg.ConfigOpts()
cls.conf.register_opts(cls.OPTS, group=CEILOMETER_DATASOURCE)
cls.transformers[CEILOMETER_DATASOURCE] = \
CeilometerTransformer(cls.transformers, cls.conf)
def test_key_values_with_vitrage_alarm(self):
LOG.debug('Ceilometer transformer test: '
'get key values(vitrage_alarm)')
# Test setup
entity = {CeilProps.VITRAGE_ID: 'test',
DSProps.ENTITY_TYPE: CEILOMETER_DATASOURCE,
CeilProps.ALARM_ID: '12345'}
transformer = self.transformers[CEILOMETER_DATASOURCE]
# Test action
observed_key_fields = transformer._create_entity_key(entity)
# Test assertions
self.assertEqual('test', observed_key_fields)
def test_key_values(self):
LOG.debug('Ceilometer transformer test: get key values(aodh alarm)')
# Test setup
entity = {DSProps.ENTITY_TYPE: CEILOMETER_DATASOURCE,
CeilProps.ALARM_ID: '12345'}
transformer = self.transformers[CEILOMETER_DATASOURCE]
# Test action
entity_key_fields = transformer._create_entity_key(entity).split(":")
# Test assertions
self.assertEqual(EntityCategory.ALARM, entity_key_fields[0])
self.assertEqual(CEILOMETER_DATASOURCE, entity_key_fields[1])
self.assertEqual(entity[CeilProps.ALARM_ID], entity_key_fields[2])
def test_snapshot_transform(self):
LOG.debug('Ceilometer alarm transformer test: '
'transform entity event snapshot')
# Test setup
spec_list = mock_sync.simple_aodh_alarm_generators(alarm_num=3,
snapshot_events=3)
static_events = mock_sync.generate_random_events_list(spec_list)
for event in static_events:
# convert neighbor from dict to vertex object
neighbors = event[TransformerBase.QUERY_RESULT]
vertices = []
for neighbor in neighbors:
neighbor_vertex = self._convert_dist_to_vertex(neighbor)
vertices.append(self.transformers[CEILOMETER_DATASOURCE].
update_uuid_in_vertex(neighbor_vertex))
event[TransformerBase.QUERY_RESULT] = vertices
# Test action
wrapper = self.transformers[CEILOMETER_DATASOURCE].transform(event)
# Test assertions
vertex = wrapper.vertex
self._validate_aodh_vertex_props(vertex, event)
neighbors = wrapper.neighbors
self.assertEqual(1, len(neighbors))
self._validate_neighbors(neighbors, vertex.vertex_id, event)
self._validate_action(event, wrapper)
class TestCeilometerAlarmPushTransformer(CeilometerTransformerBaseTest):
OPTS = [
cfg.StrOpt(DSOpts.UPDATE_METHOD,
default=UpdateMethod.PUSH),
]
@classmethod
def setUpClass(cls):
cls.transformers = {}
cls.conf = cfg.ConfigOpts()
cls.conf.register_opts(cls.OPTS, group=CEILOMETER_DATASOURCE)
cls.transformers[CEILOMETER_DATASOURCE] = \
CeilometerTransformer(cls.transformers, cls.conf)
def test_update_transform(self):
LOG.debug('Ceilometer update alarm transformer test:'
'transform entity event update')
# Test setup
spec_list = \
mock_sync.simple_aodh_update_alarm_generators(alarm_num=5,
update_events=5)
static_events = mock_sync.generate_random_events_list(spec_list)
for event in static_events:
# convert neighbor from dict to vertex object
neighbors = event[TransformerBase.QUERY_RESULT]
vertices = []
for neighbor in neighbors:
neighbor_vertex = self._convert_dist_to_vertex(neighbor)
vertices.append(self.transformers[CEILOMETER_DATASOURCE].
update_uuid_in_vertex(neighbor_vertex))
event[TransformerBase.QUERY_RESULT] = vertices
# Test action
wrapper = self.transformers[CEILOMETER_DATASOURCE].transform(event)
# Test assertions
vertex = wrapper.vertex
self._validate_aodh_vertex_props(vertex, event)
neighbors = wrapper.neighbors
self.assertEqual(1, len(neighbors))
self._validate_neighbors(neighbors, vertex.vertex_id, event)
self._validate_action(event, wrapper)

View File

@ -12,9 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
from vitrage_tempest_tests.tests.base import BaseVitrageTempest
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
TEMPLATES_RESOURCES_PATH = 'resources/templates/'
TEMPLATES_SOURCES_PATH = '/etc/vitrage/templates/'
@ -27,8 +29,8 @@ class BaseAlarmsTest(BaseVitrageTempest):
super(BaseAlarmsTest, cls).setUpClass()
def _check_num_alarms(self, num_alarms=0, state=''):
if len(TempestClients.ceilometer().alarms.list()) != num_alarms:
if len(TempestClients.aodh().alarm.list()) != num_alarms:
return False
return all(alarm.state.upper() == state.upper()
for alarm in TempestClients.ceilometer().alarms.list())
return all(alarm[AodhProps.STATE].upper() == state.upper()
for alarm in TempestClients.aodh().alarm.list())

View File

@ -19,7 +19,7 @@ from oslo_log import log as logging
from vitrage.common.constants import VertexProperties as VProps
from vitrage.datasources.aodh import AODH_DATASOURCE
from vitrage_tempest_tests.tests.api.alarms.base import BaseAlarmsTest
from vitrage_tempest_tests.tests.common import ceilometer_utils
from vitrage_tempest_tests.tests.common import aodh_utils
from vitrage_tempest_tests.tests.common import nova_utils
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
from vitrage_tempest_tests.tests import utils
@ -41,7 +41,7 @@ class TestAlarms(BaseAlarmsTest):
instances = nova_utils.create_instances(num_instances=1)
self.assertNotEqual(len(instances), 0,
'The instances list is empty')
ceilometer_utils.create_ceilometer_alarm(
aodh_utils.create_aodh_alarm(
resource_id=instances[0].id,
name='tempest_aodh_test')
@ -55,7 +55,7 @@ class TestAlarms(BaseAlarmsTest):
self._handle_exception(e)
raise
finally:
ceilometer_utils.delete_all_ceilometer_alarms()
aodh_utils.delete_all_ceilometer_alarms()
nova_utils.delete_all_instances()
def _compare_alarms_lists(self, api_alarms, cli_alarms,

View File

@ -29,7 +29,7 @@ from vitrage.entity_graph.mappings.operational_resource_state \
from vitrage.evaluator.actions.evaluator_event_transformer \
import VITRAGE_DATASOURCE
from vitrage_tempest_tests.tests.api.alarms.base import BaseAlarmsTest
from vitrage_tempest_tests.tests.common import ceilometer_utils
from vitrage_tempest_tests.tests.common import aodh_utils
from vitrage_tempest_tests.tests.common import nova_utils
from vitrage_tempest_tests.tests.common import vitrage_utils
from vitrage_tempest_tests.tests import utils
@ -47,12 +47,12 @@ class BaseRcaTest(BaseAlarmsTest):
def _clean_all(self):
nova_utils.delete_all_instances()
ceilometer_utils.delete_all_ceilometer_alarms()
aodh_utils.delete_all_aodh_alarms()
def _create_alarm(self, resource_id, alarm_name, unic=False):
ceilometer_utils.create_ceilometer_alarm(resource_id=resource_id,
name=alarm_name,
unic=unic)
aodh_utils.create_aodh_alarm(resource_id=resource_id,
name=alarm_name,
unic=unic)
list_alarms = self.vitrage_client.alarm.list(vitrage_id=None)
expected_alarm = self._filter_list_by_pairs_parameters(

View File

@ -151,9 +151,9 @@ class TestRca(BaseRcaTest):
alarm_name=RCA_ALARM_NAME)
vitrage_alarms = TempestClients.vitrage().alarm.list(
vitrage_id=None)
ceilometer_alarms = TempestClients.ceilometer().alarms.list()
aodh_alarms = TempestClients.aodh().alarm.list()
self._validate_notifier(alarms=ceilometer_alarms,
self._validate_notifier(alarms=aodh_alarms,
vitrage_alarms=vitrage_alarms)
except Exception as e:
self._handle_exception(e)

View File

@ -0,0 +1,55 @@
# Copyright 2017 - Nokia
#
# 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.
import random
import time
from vitrage.datasources.aodh.properties import AodhProperties as AodhProps
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
def create_aodh_alarm(resource_id=None, name=None, unic=True):
if not name:
name = '%s-%s' % ('test_', random.randrange(0, 100000, 1))
elif unic:
name = '%s-%s' % (name, random.randrange(0, 100000, 1))
aodh_request = _aodh_request(resource_id=resource_id, name=name)
TempestClients.aodh().alarm.create(aodh_request)
time.sleep(45)
def delete_all_aodh_alarms():
alarms = TempestClients.aodh().alarm.list()
for alarm in alarms:
TempestClients.aodh().alarm.delete(alarm[AodhProps.ALARM_ID])
time.sleep(120)
def _aodh_request(resource_id=None, name=None):
query = []
if resource_id:
query = [
dict(
field=u'traits.resource_id',
type='',
op=u'eq',
value=resource_id)
]
return dict(
name=name,
description=u'test alarm',
event_rule=dict(query=query),
severity=u'low',
state=u'alarm',
type=u'event')

View File

@ -29,6 +29,7 @@ class TempestClients(object):
cls._neutron = None
cls._heat = None
cls._mistral = None
cls._aodh = None
@classmethod
def vitrage(cls):
@ -78,3 +79,9 @@ class TempestClients(object):
if not cls._mistral:
cls._mistral = os_clients.mistral_client(cls._conf)
return cls._mistral
@classmethod
def aodh(cls):
if not cls._aodh:
cls._aodh = os_clients.aodh_client(cls._conf)
return cls._aodh

View File

@ -16,7 +16,7 @@ from oslo_log import log as logging
from vitrage_tempest_tests.tests import utils
from vitrage_tempest_tests.tests.api.alarms.base import BaseAlarmsTest
from vitrage_tempest_tests.tests.common import ceilometer_utils
from vitrage_tempest_tests.tests.common import aodh_utils
from vitrage_tempest_tests.tests.common import nova_utils
from vitrage_tempest_tests.tests.common.tempest_clients import TempestClients
@ -36,7 +36,7 @@ class TestAodhAlarm(BaseAlarmsTest):
try:
# Action
nova_utils.create_instances(num_instances=self.NUM_INSTANCE)
ceilometer_utils.create_ceilometer_alarm(
aodh_utils.create_aodh_alarm(
self._find_instance_resource_id())
# Calculate expected results
@ -64,14 +64,14 @@ class TestAodhAlarm(BaseAlarmsTest):
self._handle_exception(e)
raise
finally:
ceilometer_utils.delete_all_ceilometer_alarms()
aodh_utils.delete_all_aodh_alarms()
nova_utils.delete_all_instances()
@utils.tempest_logger
def test_alarm_without_resource_id(self):
try:
# Action
ceilometer_utils.create_ceilometer_alarm()
aodh_utils.create_aodh_alarm()
# Calculate expected results
api_graph = self.vitrage_client.topology.get(all_tenants=True)
@ -94,7 +94,7 @@ class TestAodhAlarm(BaseAlarmsTest):
self._handle_exception(e)
raise
finally:
ceilometer_utils.delete_all_ceilometer_alarms()
aodh_utils.delete_all_aodh_alarms()
def _find_instance_resource_id(self):
servers = TempestClients.nova().servers.list()