first aodh plugin get-all implementation + some nagios fixes
Change-Id: I53e3ddc62d1617410694d899f81efc38d125b877 implements: blueprint synchronizer-aodh-get-all
This commit is contained in:
parent
8ab57009c0
commit
3d9b9659a9
@ -5,6 +5,7 @@
|
||||
pbr>=1.6
|
||||
Babel>=1.3
|
||||
lxml>=2.3
|
||||
python-ceilometerclient>=2.2.1 # Apache-2.0
|
||||
python-dateutil>=2.4.2
|
||||
python-novaclient>=2.26.0
|
||||
networkx>=1.10
|
||||
|
@ -8,6 +8,7 @@ coverage>=3.6
|
||||
discover
|
||||
lxml>=2.3
|
||||
networkx>=1.10
|
||||
python-ceilometerclient>=2.2.1 # Apache-2.0
|
||||
python-novaclient>=2.26.0
|
||||
python-subunit>=0.0.18
|
||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
||||
|
@ -69,6 +69,7 @@ class EntityType(object):
|
||||
STATIC_PHYSICAL = 'static_physical'
|
||||
NAGIOS = 'nagios'
|
||||
VITRAGE = 'vitrage'
|
||||
AODH = 'aodh'
|
||||
|
||||
|
||||
class EventAction(object):
|
||||
|
@ -22,6 +22,7 @@ OPTS = [
|
||||
'nova.host',
|
||||
'nova.instance',
|
||||
'nova.zone',
|
||||
'static_physical'],
|
||||
'static_physical',
|
||||
'aodh'],
|
||||
help='Names of supported plugins'),
|
||||
]
|
||||
|
39
vitrage/synchronizer/plugins/aodh/__init__.py
Normal file
39
vitrage/synchronizer/plugins/aodh/__init__.py
Normal file
@ -0,0 +1,39 @@
|
||||
# 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
|
||||
|
||||
OPTS = [
|
||||
cfg.StrOpt('transformer',
|
||||
default='vitrage.synchronizer.plugins.aodh.'
|
||||
'transformer.AodhTransformer',
|
||||
help='Aodh plugin transformer class path',
|
||||
required=True),
|
||||
cfg.StrOpt('synchronizer',
|
||||
default='vitrage.synchronizer.plugins.aodh.synchronizer'
|
||||
'.AodhSynchronizer',
|
||||
help='Aodh plugin synchronizer class path',
|
||||
required=True),
|
||||
cfg.IntOpt('changes_interval',
|
||||
default=30,
|
||||
min=30,
|
||||
help='interval between checking changes in aodh plugin',
|
||||
required=True),
|
||||
cfg.StrOpt('user', default='admin', help='Aodh user name'),
|
||||
cfg.StrOpt('password', default='password', help='Aodh user password'),
|
||||
cfg.StrOpt('url', default='http://localhost:5000/v2.0/',
|
||||
help='Aodh authentication url'),
|
||||
cfg.StrOpt('version', default='2', help='Aodh version'),
|
||||
cfg.StrOpt('project', default='admin', help='Aodh project'),
|
||||
]
|
38
vitrage/synchronizer/plugins/aodh/properties.py
Normal file
38
vitrage/synchronizer/plugins/aodh/properties.py
Normal file
@ -0,0 +1,38 @@
|
||||
# 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 AodhProperties(object):
|
||||
ALARM_ID = 'alarm_id'
|
||||
DESCRIPTION = 'description'
|
||||
ENABLED = 'enabled'
|
||||
EVENT = 'event'
|
||||
EVENT_TYPE = 'event_type'
|
||||
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'
|
||||
TIMESTAMP = 'timestamp'
|
||||
TYPE = 'type'
|
||||
|
||||
|
||||
class AodhState(object):
|
||||
OK = 'ok'
|
||||
ALARM = 'alarm'
|
||||
INSUFFICIENT_DATA = 'insufficient_data'
|
140
vitrage/synchronizer/plugins/aodh/synchronizer.py
Normal file
140
vitrage/synchronizer/plugins/aodh/synchronizer.py
Normal file
@ -0,0 +1,140 @@
|
||||
# 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.
|
||||
import traceback
|
||||
|
||||
from ceilometerclient import client
|
||||
from oslo_log import log
|
||||
from vitrage.common.constants import EntityType
|
||||
from vitrage.synchronizer.plugins.aodh.properties import AodhProperties \
|
||||
as AodhProps
|
||||
from vitrage.synchronizer.plugins.aodh.properties import AodhState
|
||||
from vitrage.synchronizer.plugins.base.alarm.synchronizer \
|
||||
import BaseAlarmSynchronizer
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class AodhSynchronizer(BaseAlarmSynchronizer):
|
||||
|
||||
def __init__(self, conf):
|
||||
super(AodhSynchronizer, self).__init__()
|
||||
|
||||
version = conf[EntityType.AODH].version
|
||||
user = conf[EntityType.AODH].user
|
||||
password = conf[EntityType.AODH].password
|
||||
project = conf[EntityType.AODH].project
|
||||
auth_url = conf[EntityType.AODH].url
|
||||
|
||||
try:
|
||||
self.client = client.Client(version,
|
||||
None,
|
||||
username=user,
|
||||
password=password,
|
||||
tenant_name=project,
|
||||
auth_url=auth_url)
|
||||
except Exception:
|
||||
LOG.error("Failed to initialize ceilometer client. Exception: %s",
|
||||
traceback.print_exc())
|
||||
|
||||
def _sync_type(self):
|
||||
return EntityType.AODH
|
||||
|
||||
def _alarm_key(self, alarm):
|
||||
return alarm[AodhProps.NAME]
|
||||
|
||||
def _get_alarms(self):
|
||||
return []
|
||||
# TODO(iafek): enable the code below
|
||||
|
||||
# try:
|
||||
# aodh_alarms = self.client.alarms.list()
|
||||
# return [_convert_alarm(alarm)
|
||||
# for alarm in aodh_alarms]
|
||||
# except Exception:
|
||||
# LOG.error("Exception: %s", traceback.print_exc())
|
||||
# return []
|
||||
|
||||
def _is_erroneous(self, alarm):
|
||||
return alarm and alarm[AodhProps.STATE] != AodhState.OK
|
||||
|
||||
def _status_changed(self, alarm1, alarm2):
|
||||
return alarm1 and alarm2 and \
|
||||
not alarm1[AodhProps.STATE] == alarm2[AodhProps.STATE]
|
||||
|
||||
def _is_valid(self, alarm):
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _convert_event_alarm(alarm):
|
||||
converted_alarm = AodhSynchronizer._convert_base_alarm(alarm)
|
||||
event_type, resource_id = \
|
||||
AodhSynchronizer._parse_event_rule(alarm.event_rule)
|
||||
converted_alarm[AodhProps.EVENT_TYPE] = event_type
|
||||
converted_alarm[AodhProps.RESOURCE_ID] = resource_id
|
||||
return converted_alarm
|
||||
|
||||
@staticmethod
|
||||
def _convert_threshold_alarm(alarm):
|
||||
converted_alarm = AodhSynchronizer._convert_base_alarm(alarm)
|
||||
converted_alarm[AodhProps.STATE_TIMESTAMP] = alarm.state_timestamp
|
||||
converted_alarm[AodhProps.RESOURCE_ID] = \
|
||||
AodhSynchronizer._parse_threshold_rule(alarm.threshold_rule)
|
||||
return converted_alarm
|
||||
|
||||
@staticmethod
|
||||
def _convert_base_alarm(alarm):
|
||||
# TODO(iafek): what if the alarm state is 'insufficient data'
|
||||
|
||||
return {
|
||||
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.SEVERITY: alarm.severity,
|
||||
AodhProps.STATE: alarm.state,
|
||||
AodhProps.TIMESTAMP: alarm.timestamp,
|
||||
AodhProps.TYPE: alarm.type
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _parse_event_rule(rule):
|
||||
event_type = rule[AodhProps.EVENT_TYPE]
|
||||
resource_id = \
|
||||
AodhSynchronizer._parse_resource_id(rule[AodhProps.QUERY])
|
||||
return event_type, resource_id
|
||||
|
||||
@staticmethod
|
||||
def _parse_threshold_rule(rule):
|
||||
return AodhSynchronizer._parse_resource_id(rule[AodhProps.QUERY])
|
||||
|
||||
@staticmethod
|
||||
def _parse_resource_id(query_fields):
|
||||
for query in query_fields:
|
||||
field = query['field']
|
||||
if field == AodhProps.RESOURCE_ID:
|
||||
return query['value']
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _convert_alarm(alarm):
|
||||
alarm_type = alarm.type
|
||||
if alarm_type == AodhProps.EVENT:
|
||||
return AodhSynchronizer._convert_event_alarm(alarm)
|
||||
elif alarm_type == AodhProps.THRESHOLD:
|
||||
return AodhSynchronizer._convert_threshold_alarm(alarm)
|
||||
else:
|
||||
LOG.info('Unsopported Aodh alarm of type %s' % alarm_type)
|
87
vitrage/synchronizer/plugins/aodh/transformer.py
Normal file
87
vitrage/synchronizer/plugins/aodh/transformer.py
Normal file
@ -0,0 +1,87 @@
|
||||
# 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_log import log as logging
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import SynchronizerProperties as SyncProps
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.common import datetime_utils
|
||||
import vitrage.graph.utils as graph_utils
|
||||
from vitrage.synchronizer.plugins.aodh.properties import AodhProperties \
|
||||
as AodhProps
|
||||
from vitrage.synchronizer.plugins.base.alarm.properties \
|
||||
import AlarmProperties as AlarmProps
|
||||
from vitrage.synchronizer.plugins.base.alarm.transformer \
|
||||
import BaseAlarmTransformer
|
||||
from vitrage.synchronizer.plugins import transformer_base as tbase
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AodhTransformer(BaseAlarmTransformer):
|
||||
|
||||
STATUS_OK = 'ok'
|
||||
|
||||
def __init__(self, transformers):
|
||||
super(AodhTransformer, self).__init__(transformers)
|
||||
|
||||
def _create_entity_vertex(self, entity_event):
|
||||
metadata = {
|
||||
VProps.NAME: entity_event[AodhProps.NAME],
|
||||
VProps.SEVERITY: entity_event[AodhProps.SEVERITY],
|
||||
AodhProps.DESCRIPTION: entity_event[AodhProps.DESCRIPTION],
|
||||
AodhProps.ENABLED: entity_event[AodhProps.ENABLED],
|
||||
VProps.PROJECT_ID: entity_event[AodhProps.PROJECT_ID],
|
||||
AodhProps.REPEAT_ACTIONS: entity_event[AodhProps.REPEAT_ACTIONS],
|
||||
'alarm_type': entity_event[AodhProps.TYPE]
|
||||
}
|
||||
|
||||
if entity_event[AodhProps.TYPE] == AodhProps.EVENT:
|
||||
metadata[AodhProps.EVENT_TYPE] = entity_event[AodhProps.EVENT_TYPE]
|
||||
|
||||
elif entity_event[AodhProps.TYPE] == AodhProps.THRESHOLD:
|
||||
metadata[AodhProps.STATE_TIMESTAMP] = \
|
||||
entity_event[AodhProps.STATE_TIMESTAMP]
|
||||
|
||||
return graph_utils.create_vertex(
|
||||
self.extract_key(entity_event),
|
||||
entity_id=entity_event[AodhProps.ALARM_ID],
|
||||
entity_category=EntityCategory.ALARM,
|
||||
entity_type=entity_event[SyncProps.SYNC_TYPE],
|
||||
entity_state=AlarmProps.ALARM_STATE,
|
||||
update_timestamp=AodhTransformer._timestamp(entity_event),
|
||||
metadata=metadata)
|
||||
|
||||
def _create_neighbors(self, entity_event):
|
||||
# TODO(iafek): get neighbour resource by its id
|
||||
return []
|
||||
|
||||
def _ok_status(self, entity_event):
|
||||
return entity_event[AodhProps.STATE] == self.STATUS_OK
|
||||
|
||||
def extract_key(self, entity_event):
|
||||
sync_type = entity_event[SyncProps.SYNC_TYPE]
|
||||
alarm_name = entity_event[AodhProps.NAME]
|
||||
resource_id = entity_event[AodhProps.RESOURCE_ID]
|
||||
return (tbase.build_key(self.key_values([sync_type,
|
||||
resource_id,
|
||||
alarm_name])) if resource_id
|
||||
else tbase.build_key(self.key_values([sync_type, alarm_name])))
|
||||
|
||||
@staticmethod
|
||||
def _timestamp(entity_event):
|
||||
return datetime_utils.change_time_str_format(
|
||||
entity_event[AodhProps.TIMESTAMP],
|
||||
'%Y-%m-%dT%H:%M:%S.%f',
|
||||
tbase.TIMESTAMP_FORMAT)
|
15
vitrage/synchronizer/plugins/base/__init__.py
Normal file
15
vitrage/synchronizer/plugins/base/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
15
vitrage/synchronizer/plugins/base/alarm/__init__.py
Normal file
15
vitrage/synchronizer/plugins/base/alarm/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
|
||||
__author__ = 'stack'
|
18
vitrage/synchronizer/plugins/base/alarm/properties.py
Normal file
18
vitrage/synchronizer/plugins/base/alarm/properties.py
Normal file
@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
__author__ = 'stack'
|
||||
|
||||
|
||||
class AlarmProperties(object):
|
||||
ALARM_STATE = 'Active'
|
122
vitrage/synchronizer/plugins/base/alarm/synchronizer.py
Normal file
122
vitrage/synchronizer/plugins/base/alarm/synchronizer.py
Normal file
@ -0,0 +1,122 @@
|
||||
# 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_log import log
|
||||
from vitrage.synchronizer.plugins.synchronizer_base import SynchronizerBase
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseAlarmSynchronizer(SynchronizerBase):
|
||||
def __init__(self):
|
||||
super(SynchronizerBase, self).__init__()
|
||||
self.cache = dict()
|
||||
|
||||
def _sync_type(self):
|
||||
"""Return the type of the plugin """
|
||||
pass
|
||||
|
||||
def _alarm_key(self, alarm):
|
||||
"""Return a unique key of the alarm, to identify it in the cache """
|
||||
pass
|
||||
|
||||
def _get_alarms(self):
|
||||
"""Return the list of alarms of this plugin """
|
||||
pass
|
||||
|
||||
def _enrich_alarms(self, alarms):
|
||||
"""Optionally add more data to the alarms
|
||||
|
||||
:param alarms: list of alarms to be enriched
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def _is_erroneous(self, alarm):
|
||||
"""Check if the state of the alarm is erroneous
|
||||
|
||||
:param alarm:
|
||||
:return: True/False based on the alarm state
|
||||
"""
|
||||
pass
|
||||
|
||||
def _status_changed(self, alarm1, alarm2):
|
||||
"""Check if the status of the two alarms is different
|
||||
|
||||
:param alarm1:
|
||||
:param alarm2:
|
||||
:return: True/False based on the alarms states
|
||||
"""
|
||||
pass
|
||||
|
||||
def _is_valid(self, alarm):
|
||||
"""Check if the alarm is valid
|
||||
|
||||
:param alarm: an alarm to check
|
||||
:return: True/False
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_all(self, sync_mode):
|
||||
return self.make_pickleable(self._get_all_alarms(),
|
||||
self._sync_type(),
|
||||
sync_mode)
|
||||
|
||||
def get_changes(self, sync_mode):
|
||||
return self.make_pickleable(self._get_changed_alarms(),
|
||||
self._sync_type(),
|
||||
sync_mode)
|
||||
|
||||
def _get_all_alarms(self):
|
||||
alarms = self._get_alarms()
|
||||
self._enrich_alarms(alarms)
|
||||
return self._filter_and_cache_alarms(
|
||||
alarms,
|
||||
BaseAlarmSynchronizer._filter_get_all)
|
||||
|
||||
def _get_changed_alarms(self):
|
||||
alarms = self._get_alarms()
|
||||
self._enrich_alarms(alarms)
|
||||
return self._filter_and_cache_alarms(
|
||||
alarms,
|
||||
BaseAlarmSynchronizer._filter_get_changes)
|
||||
|
||||
def _filter_and_cache_alarms(self, alarms, filter_):
|
||||
alarms_to_update = []
|
||||
|
||||
for alarm in alarms:
|
||||
alarm_key = self._alarm_key(alarm)
|
||||
old_alarm = self.cache.get(alarm_key, None)
|
||||
|
||||
if filter_(self, alarm, old_alarm):
|
||||
alarms_to_update.append(alarm)
|
||||
|
||||
self.cache[alarm_key] = alarm
|
||||
|
||||
return alarms_to_update
|
||||
|
||||
def _filter_get_all(self, alarm, old_alarm):
|
||||
return alarm \
|
||||
if self._is_valid(alarm) and \
|
||||
(self._is_erroneous(alarm) or self._is_erroneous(old_alarm)) \
|
||||
else None
|
||||
|
||||
def _filter_get_changes(self, alarm, old_alarm):
|
||||
if not self._is_valid(alarm):
|
||||
return None
|
||||
if self._status_changed(alarm, old_alarm):
|
||||
return alarm
|
||||
elif not old_alarm and self._is_erroneous(alarm):
|
||||
return alarm
|
||||
else:
|
||||
return None
|
50
vitrage/synchronizer/plugins/base/alarm/transformer.py
Normal file
50
vitrage/synchronizer/plugins/base/alarm/transformer.py
Normal file
@ -0,0 +1,50 @@
|
||||
# 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_log import log as logging
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import EventAction
|
||||
from vitrage.common.constants import SynchronizerProperties as SyncProps
|
||||
from vitrage.common.constants import SyncMode
|
||||
from vitrage.common.exception import VitrageTransformerError
|
||||
from vitrage.synchronizer.plugins import transformer_base as tbase
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseAlarmTransformer(tbase.TransformerBase):
|
||||
|
||||
def __init__(self, transformers):
|
||||
self.transformers = transformers
|
||||
|
||||
def _ok_status(self, entity_event):
|
||||
pass
|
||||
|
||||
def create_placeholder_vertex(self, properties={}):
|
||||
LOG.info('An alarm cannot be a placeholder')
|
||||
pass
|
||||
|
||||
def _extract_action_type(self, entity_event):
|
||||
sync_mode = entity_event[SyncProps.SYNC_MODE]
|
||||
if sync_mode in (SyncMode.UPDATE, SyncMode.SNAPSHOT):
|
||||
if self._ok_status(entity_event):
|
||||
return EventAction.DELETE_ENTITY
|
||||
else:
|
||||
return EventAction.UPDATE_ENTITY
|
||||
if SyncMode.INIT_SNAPSHOT == sync_mode:
|
||||
return EventAction.CREATE_ENTITY
|
||||
raise VitrageTransformerError('Invalid sync mode: (%s)' % sync_mode)
|
||||
|
||||
def key_values(self, mutable_fields=[]):
|
||||
return [EntityCategory.ALARM] + mutable_fields
|
@ -13,7 +13,6 @@
|
||||
# under the License.
|
||||
|
||||
|
||||
# TODO(ifat_afek): unite with nagios transformer properties
|
||||
class NagiosProperties(object):
|
||||
NUM_COLUMNS = 7
|
||||
RESOURCE_TYPE = 'resource_type'
|
||||
|
@ -21,50 +21,33 @@ from vitrage.common.constants import EntityType
|
||||
from vitrage.common.constants import SynchronizerProperties as SyncProps
|
||||
from vitrage.i18n import _LE
|
||||
from vitrage.i18n import _LW
|
||||
from vitrage.synchronizer.plugins.base.alarm.synchronizer \
|
||||
import BaseAlarmSynchronizer
|
||||
from vitrage.synchronizer.plugins.nagios.config import NagiosConfig
|
||||
from vitrage.synchronizer.plugins.nagios.parser import NagiosParser
|
||||
from vitrage.synchronizer.plugins.nagios.properties import NagiosProperties \
|
||||
as NagiosProps
|
||||
from vitrage.synchronizer.plugins.nagios.properties import NagiosStatus
|
||||
from vitrage.synchronizer.plugins.synchronizer_base import SynchronizerBase
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class NagiosSynchronizer(SynchronizerBase):
|
||||
class NagiosSynchronizer(BaseAlarmSynchronizer):
|
||||
ServiceKey = namedtuple('ServiceKey', ['host_name', 'service'])
|
||||
|
||||
def __init__(self, conf):
|
||||
super(NagiosSynchronizer, self).__init__()
|
||||
self.conf = conf
|
||||
self.cache = dict()
|
||||
self.config = NagiosConfig(conf)
|
||||
|
||||
def get_all(self, sync_mode):
|
||||
return self.make_pickleable(self._get_all_services(),
|
||||
EntityType.NAGIOS,
|
||||
sync_mode)
|
||||
def _sync_type(self):
|
||||
return EntityType.NAGIOS
|
||||
|
||||
def get_changes(self, sync_mode):
|
||||
return self.make_pickleable(self._get_changed_services(),
|
||||
EntityType.NAGIOS,
|
||||
sync_mode)
|
||||
def _alarm_key(self, alarm):
|
||||
return self.ServiceKey(host_name=alarm[NagiosProps.RESOURCE_NAME],
|
||||
service=alarm[NagiosProps.SERVICE])
|
||||
|
||||
def _get_all_services(self):
|
||||
nagios_services = self._get_services_from_nagios()
|
||||
self._enrich_services(nagios_services)
|
||||
return self._filter_and_cache_services(
|
||||
nagios_services,
|
||||
NagiosSynchronizer._filter_get_all)
|
||||
|
||||
def _get_changed_services(self):
|
||||
nagios_services = self._get_services_from_nagios()
|
||||
self._enrich_services(nagios_services)
|
||||
return self._filter_and_cache_services(
|
||||
nagios_services,
|
||||
NagiosSynchronizer._filter_get_changes)
|
||||
|
||||
def _get_services_from_nagios(self):
|
||||
def _get_alarms(self):
|
||||
nagios_user = self.conf.nagios.user
|
||||
nagios_password = self.conf.nagios.password
|
||||
nagios_url = self.conf.nagios.url
|
||||
@ -95,59 +78,27 @@ class NagiosSynchronizer(SynchronizerBase):
|
||||
response.status_code)
|
||||
return []
|
||||
|
||||
def _enrich_services(self, nagios_services):
|
||||
for service in nagios_services:
|
||||
def _enrich_alarms(self, alarms):
|
||||
for alarm in alarms:
|
||||
# based on nagios configuration file, convert nagios host name
|
||||
# to vitrage resource type and name
|
||||
service[SyncProps.SYNC_TYPE] = NagiosProps.NAGIOS
|
||||
alarm[SyncProps.SYNC_TYPE] = NagiosProps.NAGIOS
|
||||
|
||||
nagios_host = service[NagiosProps.RESOURCE_NAME]
|
||||
nagios_host = alarm[NagiosProps.RESOURCE_NAME]
|
||||
vitrage_resource = self.config.get_vitrage_resource(nagios_host)
|
||||
|
||||
service[NagiosProps.RESOURCE_TYPE] = \
|
||||
alarm[NagiosProps.RESOURCE_TYPE] = \
|
||||
vitrage_resource[0] if vitrage_resource else None
|
||||
service[NagiosProps.RESOURCE_NAME] = \
|
||||
vitrage_resource[1] if vitrage_resource \
|
||||
else service[NagiosProps.RESOURCE_NAME]
|
||||
alarm[NagiosProps.RESOURCE_NAME] = \
|
||||
vitrage_resource[1] if vitrage_resource else None
|
||||
|
||||
def _filter_and_cache_services(self, nagios_services, filter_):
|
||||
services_to_update = []
|
||||
def _is_erroneous(self, alarm):
|
||||
return alarm and alarm[NagiosProps.STATUS] != NagiosStatus.OK
|
||||
|
||||
for service in nagios_services:
|
||||
service_key = self.ServiceKey(
|
||||
host_name=service[NagiosProps.RESOURCE_NAME],
|
||||
service=service[NagiosProps.SERVICE])
|
||||
def _status_changed(self, alarm1, alarm2):
|
||||
return alarm1 and alarm2 and \
|
||||
not alarm1[NagiosProps.STATUS] == alarm2[NagiosProps.STATUS]
|
||||
|
||||
old_service = self.cache.get(service_key, None)
|
||||
|
||||
if filter_(service, old_service):
|
||||
services_to_update.append(service)
|
||||
|
||||
self.cache[service_key] = service
|
||||
|
||||
return services_to_update
|
||||
|
||||
@staticmethod
|
||||
def _filter_get_all(service, old_service):
|
||||
return service \
|
||||
if (NagiosSynchronizer._is_erroneous(service) or
|
||||
NagiosSynchronizer._is_erroneous(old_service)) \
|
||||
else None
|
||||
|
||||
@staticmethod
|
||||
def _filter_get_changes(service, old_service):
|
||||
if NagiosSynchronizer._status_changed(service, old_service):
|
||||
return service
|
||||
elif not old_service and NagiosSynchronizer._is_erroneous(service):
|
||||
return service
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _is_erroneous(service):
|
||||
return service and service[NagiosProps.STATUS] != NagiosStatus.OK
|
||||
|
||||
@staticmethod
|
||||
def _status_changed(service1, service2):
|
||||
return service1 and service2 and \
|
||||
not service1[NagiosProps.STATUS] == service2[NagiosProps.STATUS]
|
||||
def _is_valid(self, alarm):
|
||||
return alarm[NagiosProps.RESOURCE_TYPE] is not None and \
|
||||
alarm[NagiosProps.RESOURCE_NAME] is not None
|
||||
|
@ -16,29 +16,26 @@ from oslo_log import log as logging
|
||||
from vitrage.common.constants import EdgeLabels
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import EntityType
|
||||
from vitrage.common.constants import EventAction
|
||||
from vitrage.common.constants import SynchronizerProperties as SyncProps
|
||||
from vitrage.common.constants import SyncMode
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.common import datetime_utils
|
||||
from vitrage.common.exception import VitrageTransformerError
|
||||
import vitrage.graph.utils as graph_utils
|
||||
from vitrage.synchronizer.plugins.base.alarm.properties \
|
||||
import AlarmProperties as AlarmProps
|
||||
from vitrage.synchronizer.plugins.base.alarm.transformer \
|
||||
import BaseAlarmTransformer
|
||||
from vitrage.synchronizer.plugins.nagios.properties import NagiosProperties
|
||||
from vitrage.synchronizer.plugins import transformer_base as tbase
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NagiosTransformer(tbase.TransformerBase):
|
||||
class NagiosTransformer(BaseAlarmTransformer):
|
||||
|
||||
STATUS_OK = 'OK'
|
||||
NAGIOS_ALARM_STATE = 'Active'
|
||||
|
||||
def __init__(self, transformers):
|
||||
self.transformers = transformers
|
||||
|
||||
def create_placeholder_vertex(self, properties={}):
|
||||
LOG.info('Nagios alarm cannot be a placeholder')
|
||||
super(NagiosTransformer, self).__init__(transformers)
|
||||
|
||||
def _create_entity_vertex(self, entity_event):
|
||||
|
||||
@ -57,7 +54,7 @@ class NagiosTransformer(tbase.TransformerBase):
|
||||
self.extract_key(entity_event),
|
||||
entity_category=EntityCategory.ALARM,
|
||||
entity_type=entity_event[SyncProps.SYNC_TYPE],
|
||||
entity_state=self.NAGIOS_ALARM_STATE,
|
||||
entity_state=AlarmProps.ALARM_STATE,
|
||||
update_timestamp=timestamp,
|
||||
metadata=metadata)
|
||||
|
||||
@ -100,16 +97,8 @@ class NagiosTransformer(tbase.TransformerBase):
|
||||
LOG.warning('Cannot transform host, host transformer does not exist')
|
||||
return None
|
||||
|
||||
def _extract_action_type(self, entity_event):
|
||||
sync_mode = entity_event[SyncProps.SYNC_MODE]
|
||||
if sync_mode in (SyncMode.UPDATE, SyncMode.SNAPSHOT):
|
||||
if entity_event[NagiosProperties.STATUS] == self.STATUS_OK:
|
||||
return EventAction.DELETE_ENTITY
|
||||
else:
|
||||
return EventAction.UPDATE_ENTITY
|
||||
if SyncMode.INIT_SNAPSHOT == sync_mode:
|
||||
return EventAction.CREATE_ENTITY
|
||||
raise VitrageTransformerError('Invalid sync mode: (%s)' % sync_mode)
|
||||
def _ok_status(self, entity_event):
|
||||
return entity_event[NagiosProperties.STATUS] == self.STATUS_OK
|
||||
|
||||
def extract_key(self, entity_event):
|
||||
|
||||
@ -119,6 +108,3 @@ class NagiosTransformer(tbase.TransformerBase):
|
||||
return tbase.build_key(self.key_values([sync_type,
|
||||
resource_name,
|
||||
alarm_name]))
|
||||
|
||||
def key_values(self, mutable_fields=[]):
|
||||
return [EntityCategory.ALARM] + mutable_fields
|
||||
|
@ -30,7 +30,7 @@ class NagiosSynchronizerWithMockData(NagiosSynchronizer):
|
||||
def set_service_datas(self, service_datas):
|
||||
self.service_datas = service_datas
|
||||
|
||||
def _get_services_from_nagios(self):
|
||||
def _get_alarms(self):
|
||||
alarms = []
|
||||
for service_data in self.service_datas:
|
||||
generators = mock_sync.simple_nagios_alarm_generators(
|
||||
|
@ -20,6 +20,8 @@ from vitrage.common.constants import EventAction
|
||||
from vitrage.common.constants import SynchronizerProperties as SyncProps
|
||||
from vitrage.common.constants import SyncMode
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.synchronizer.plugins.base.alarm.properties \
|
||||
import AlarmProperties as AlarmProps
|
||||
from vitrage.synchronizer.plugins.nagios.properties import NagiosProperties
|
||||
from vitrage.synchronizer.plugins.nagios.transformer import NagiosTransformer
|
||||
from vitrage.synchronizer.plugins.nova.host.transformer import HostTransformer
|
||||
@ -102,8 +104,7 @@ class NagiosTransformerTest(base.BaseTest):
|
||||
self.assertEqual(EntityCategory.ALARM, vertex[VProps.CATEGORY])
|
||||
self.assertEqual(event[SyncProps.SYNC_TYPE], vertex[VProps.TYPE])
|
||||
self.assertEqual(event[NagiosProperties.SERVICE], vertex[VProps.NAME])
|
||||
self.assertEqual(NagiosTransformer.NAGIOS_ALARM_STATE,
|
||||
vertex[VProps.STATE])
|
||||
self.assertEqual(AlarmProps.ALARM_STATE, vertex[VProps.STATE])
|
||||
|
||||
self.assertEqual(event[NagiosProperties.STATUS],
|
||||
vertex[VProps.SEVERITY])
|
||||
|
@ -28,11 +28,11 @@ LOG = logging.getLogger(__name__)
|
||||
class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
|
||||
OPTS = [
|
||||
cfg.StrOpt(
|
||||
'config_file',
|
||||
default=utils.get_resources_dir() + '/nagios/nagios_conf.yaml',
|
||||
help='Nagios configuation file'
|
||||
),
|
||||
cfg.StrOpt('config_file',
|
||||
default=utils.get_resources_dir() +
|
||||
'/nagios/nagios_conf.yaml',
|
||||
help='Nagios configuation file'
|
||||
),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@ -65,7 +65,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Services with status OK should not be returned
|
||||
@ -87,7 +87,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -109,7 +109,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -132,7 +132,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
# The services of service_data1/2 should be returned although their
|
||||
@ -143,7 +143,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self._assert_contains(service_data2, services)
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Calling get_services again should not return anything, since all
|
||||
@ -176,7 +176,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Services with status OK should not be returned
|
||||
@ -198,7 +198,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -220,7 +220,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -243,7 +243,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -265,7 +265,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -274,7 +274,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self._assert_contains(service_data2, services)
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'services is None')
|
||||
@ -301,7 +301,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -309,7 +309,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self._assert_contains(service_data1, services)
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Calling get_changes for the second time should return nothing
|
||||
@ -317,7 +317,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self.assertEqual(0, len(services))
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -325,7 +325,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self._assert_contains(service_data1, services)
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Calling get_all for the second time should return the same results
|
||||
@ -348,7 +348,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -357,7 +357,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self._assert_contains(service_data2, services)
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Calling get_changes after get_all should return nothing
|
||||
@ -365,7 +365,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self.assertEqual(0, len(services))
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Calling get_all for the second time should return the same results
|
||||
@ -389,7 +389,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -412,7 +412,7 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
service_data2,
|
||||
service_data3])
|
||||
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'No services returned')
|
||||
@ -420,14 +420,14 @@ class NagiosSynchronizerTest(NagiosBaseTest):
|
||||
self._assert_contains(service_data1, services)
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_changed_services()
|
||||
services = nagios_synchronizer._get_changed_alarms()
|
||||
|
||||
# Test assertions
|
||||
self.assertIsNotNone(services, 'services is None')
|
||||
self.assertEqual(0, len(services))
|
||||
|
||||
# Action
|
||||
services = nagios_synchronizer._get_all_services()
|
||||
services = nagios_synchronizer._get_all_alarms()
|
||||
|
||||
# Test assertions
|
||||
# Calling get_all for the second time should return the same results
|
||||
|
Loading…
Reference in New Issue
Block a user