diff --git a/vitrage/api_handler/apis/alarm.py b/vitrage/api_handler/apis/alarm.py index 9c88231f2..5d9a1d204 100644 --- a/vitrage/api_handler/apis/alarm.py +++ b/vitrage/api_handler/apis/alarm.py @@ -53,8 +53,6 @@ class AlarmApis(EntityGraphApisBase): vertex_attr_filter={VProps.CATEGORY: EntityCategory.ALARM, VProps.IS_DELETED: False}) - self._add_resource_details_to_alarms(alarms) - return json.dumps({'alarms': [v.properties for v in alarms]}) def _get_alarms(self, project_id, is_admin_project): diff --git a/vitrage/api_handler/apis/base.py b/vitrage/api_handler/apis/base.py index 5ca168e69..7e3742f94 100644 --- a/vitrage/api_handler/apis/base.py +++ b/vitrage/api_handler/apis/base.py @@ -14,7 +14,6 @@ from oslo_log import log -from vitrage.common.constants import EdgeLabel from vitrage.common.constants import EdgeProperties as EProps from vitrage.common.constants import EntityCategory from vitrage.common.constants import VertexProperties as VProps @@ -199,25 +198,6 @@ class EntityGraphApisBase(object): else: return None - def _add_resource_details_to_alarms(self, alarms): - for alarm in alarms: - try: - resources = self.entity_graph.neighbors( - v_id=alarm.vertex_id, - edge_attr_filter={EProps.RELATIONSHIP_TYPE: EdgeLabel.ON}, - direction=Direction.OUT) - - resource = self._get_first(resources) - if resource: - alarm["resource_id"] = resource.get(VProps.ID, '') - alarm["resource_type"] = resource.get(VProps.TYPE, '') - else: - alarm["resource_id"] = '' - alarm["resource_type"] = '' - - except ValueError as ve: - LOG.error('Alarm %s\nException %s', alarm, ve) - def _is_project_admin(self, project_id): keystone_client = ks_client(self.conf) project = keystone_client.projects.get(project_id) diff --git a/vitrage/api_handler/apis/rca.py b/vitrage/api_handler/apis/rca.py index c5a6e1029..70d8546e6 100644 --- a/vitrage/api_handler/apis/rca.py +++ b/vitrage/api_handler/apis/rca.py @@ -60,7 +60,6 @@ class RcaApis(EntityGraphApisBase): is_admin_project) alarms = unified_graph.get_vertices(query_dict=ALARMS_ALL_QUERY) - self._add_resource_details_to_alarms(alarms) unified_graph.update_vertices(alarms) json_graph = unified_graph.json_output_graph( diff --git a/vitrage/api_handler/apis/topology.py b/vitrage/api_handler/apis/topology.py index 86c1039e9..8bc775736 100644 --- a/vitrage/api_handler/apis/topology.py +++ b/vitrage/api_handler/apis/topology.py @@ -75,7 +75,6 @@ class TopologyApis(EntityGraphApisBase): root) alarms = graph.get_vertices(query_dict=ALARMS_ALL_QUERY) - self._add_resource_details_to_alarms(alarms) graph.update_vertices(alarms) return graph.json_output_graph() diff --git a/vitrage/common/constants.py b/vitrage/common/constants.py index 4bda0c73d..7ba4a7e46 100644 --- a/vitrage/common/constants.py +++ b/vitrage/common/constants.py @@ -37,6 +37,8 @@ class VertexProperties(object): GRAPH_INDEX = 'graph_index' RAWTEXT = 'rawtext' RESOURCE_ID = 'resource_id' + VITRAGE_RESOURCE_ID = 'vitrage_resource_id' + VITRAGE_RESOURCE_TYPE = 'vitrage_resource_type' RESOURCE = 'resource' IS_REAL_VITRAGE_ID = 'is_real_vitrage_id' diff --git a/vitrage/entity_graph/processor/processor.py b/vitrage/entity_graph/processor/processor.py index bec6d7de5..1833ab247 100644 --- a/vitrage/entity_graph/processor/processor.py +++ b/vitrage/entity_graph/processor/processor.py @@ -17,6 +17,7 @@ from oslo_log import log from oslo_utils import uuidutils +from vitrage.common.constants import EntityCategory from vitrage.common.constants import GraphAction from vitrage.common.constants import VertexProperties as VProps from vitrage.common.exception import VitrageError @@ -83,6 +84,7 @@ class Processor(processor.ProcessorBase): # _find_and_fix_graph_vertex method call to the process_event method # so it will be done in one central place self._find_and_fix_graph_vertex(new_vertex, neighbors) + self._add_resource_details_to_alarm(new_vertex, neighbors) self.entity_graph.add_vertex(new_vertex) self._connect_neighbors(neighbors, set(), GraphAction.CREATE_ENTITY) @@ -107,6 +109,7 @@ class Processor(processor.ProcessorBase): if (not graph_vertex) or \ PUtils.is_newer_vertex(graph_vertex, updated_vertex): + self._add_resource_details_to_alarm(updated_vertex, neighbors) PUtils.update_entity_graph_vertex(self.entity_graph, graph_vertex, updated_vertex) @@ -426,6 +429,24 @@ class Processor(processor.ProcessorBase): edge.source_id = vitrage_id edge.target_id = neighbor_vertex.vertex_id + def _add_resource_details_to_alarm(self, vertex, neighbors): + + if not vertex.get(VProps.CATEGORY) == EntityCategory.ALARM \ + or not neighbors: + return + + # for the possibility that alarm doesn't have resource + vertex.properties[VProps.VITRAGE_RESOURCE_ID] = None + vertex.properties[VProps.VITRAGE_RESOURCE_TYPE] = None + + for neighbor in neighbors: + + if neighbor.vertex.get(VProps.CATEGORY) == EntityCategory.RESOURCE: + vertex.properties[VProps.VITRAGE_RESOURCE_ID] = \ + neighbor.vertex.vertex_id + vertex.properties[VProps.VITRAGE_RESOURCE_TYPE] = \ + neighbor.vertex.get(VProps.TYPE) + def _get_single_graph_vertex_by_props(self, vertex, include_deleted=False): """Returns a single vertex by it's defining properties diff --git a/vitrage/evaluator/actions/evaluator_event_transformer.py b/vitrage/evaluator/actions/evaluator_event_transformer.py index 9a36a3d4d..9875ee795 100644 --- a/vitrage/evaluator/actions/evaluator_event_transformer.py +++ b/vitrage/evaluator/actions/evaluator_event_transformer.py @@ -104,6 +104,7 @@ class EvaluatorEventTransformer(transformer_base.TransformerBase): return self._create_vitrage_neighbors(event) def _create_vitrage_neighbors(self, event): + event_type = event[EVALUATOR_EVENT_TYPE] timestamp = transformer_base.convert_timestamp_format( @@ -112,7 +113,6 @@ class EvaluatorEventTransformer(transformer_base.TransformerBase): ) if event_type in [ADD_EDGE, REMOVE_EDGE]: - relation_edge = graph_utils.create_edge( source_id=event[TFields.SOURCE], target_id=event[TFields.TARGET], @@ -122,7 +122,6 @@ class EvaluatorEventTransformer(transformer_base.TransformerBase): return [Neighbor(None, relation_edge)] if event_type == ADD_VERTEX: - relation_edge = graph_utils.create_edge( source_id=self._create_entity_key(event), target_id=event[TFields.TARGET], @@ -133,7 +132,9 @@ class EvaluatorEventTransformer(transformer_base.TransformerBase): VProps.IS_PLACEHOLDER: True, VProps.UPDATE_TIMESTAMP: timestamp, VProps.SAMPLE_TIMESTAMP: event[VProps.SAMPLE_TIMESTAMP], - VProps.IS_REAL_VITRAGE_ID: True + VProps.IS_REAL_VITRAGE_ID: True, + VProps.TYPE: event[VProps.VITRAGE_RESOURCE_TYPE], + VProps.CATEGORY: EntityCategory.RESOURCE, } neighbor = Vertex(event[TFields.TARGET], neighbor_props) return [Neighbor(neighbor, relation_edge)] diff --git a/vitrage/evaluator/actions/recipes/raise_alarm.py b/vitrage/evaluator/actions/recipes/raise_alarm.py index d77efa001..d2577c015 100644 --- a/vitrage/evaluator/actions/recipes/raise_alarm.py +++ b/vitrage/evaluator/actions/recipes/raise_alarm.py @@ -57,7 +57,8 @@ class RaiseAlarm(base.Recipe): target_resource = action_spec.targets[TFields.TARGET] add_vertex_params = { - TFields.TARGET: target_resource.vertex_id + TFields.TARGET: target_resource.vertex_id, + VProps.VITRAGE_RESOURCE_TYPE: target_resource[VProps.TYPE], } add_vertex_params.update(action_spec.properties) diff --git a/vitrage/tests/functional/evaluator/test_action_executor.py b/vitrage/tests/functional/evaluator/test_action_executor.py index c5fa586be..5ef0f74ea 100644 --- a/vitrage/tests/functional/evaluator/test_action_executor.py +++ b/vitrage/tests/functional/evaluator/test_action_executor.py @@ -16,11 +16,14 @@ from oslo_config import cfg from six.moves import queue +from vitrage.common.constants import DatasourceProperties as DSProp from vitrage.common.constants import EdgeLabel from vitrage.common.constants import EntityCategory +from vitrage.common.constants import TemplateTopologyFields as TTFields from vitrage.common.constants import VertexProperties as VProps from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps from vitrage.datasources.nagios import NAGIOS_DATASOURCE +from vitrage.datasources.nagios.properties import NagiosProperties as NProps from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE from vitrage.entity_graph.mappings.operational_resource_state import \ OperationalResourceState @@ -233,6 +236,11 @@ class TestActionExecutor(TestFunctionalBase): props[TFields.SEVERITY]) self.assertEqual(alarm.properties[VProps.STATE], AlarmProps.ACTIVE_STATE) + self.assertEqual(alarm.properties[VProps.VITRAGE_RESOURCE_ID], + action_spec.targets + [TTFields.TARGET][VProps.VITRAGE_ID]), + self.assertEqual(alarm.properties[VProps.VITRAGE_RESOURCE_TYPE], + NOVA_HOST_DATASOURCE) def test_execute_add_and_remove_vertex(self): @@ -283,27 +291,28 @@ class TestActionExecutor(TestFunctionalBase): @staticmethod def _get_nagios_event(resource_name, resource_type): - return {'last_check': '2016-02-07 15:26:04', - 'resource_name': resource_name, - 'resource_type': resource_type, - 'service': 'Check_MK', - 'status': 'CRITICAL', - 'status_info': 'test test test', - 'vitrage_datasource_action': 'snapshot', - 'vitrage_entity_type': 'nagios', - 'vitrage_sample_date': '2016-02-07 15:26:04'} + return {NProps.LAST_CHECK: '2016-02-07 15:26:04', + NProps.RESOURCE_NAME: resource_name, + NProps.RESOURCE_TYPE: resource_type, + NProps.SERVICE: 'Check_MK', + NProps.STATUS: 'CRITICAL', + NProps.STATUS_INFO: 'test test test', + DSProp.DATASOURCE_ACTION: 'snapshot', + DSProp.ENTITY_TYPE: 'nagios', + DSProp.SAMPLE_DATE: '2016-02-07 15:26:04'} @staticmethod def _get_vitrage_add_vertex_event(target_vertex, alarm_name, severity): - return {'target': target_vertex.vertex_id, - 'update_timestamp': '2016-03-17 11:33:32.443002', - 'vitrage_datasource_action': 'update', - 'alarm_name': alarm_name, - 'state': 'Active', - 'type': 'add_vertex', - 'vitrage_entity_type': 'vitrage', - 'severity': 'CRITICAL', - 'vitrage_id': 'mock_vitrage_id', - 'category': 'RESOURCE', - 'sample_timestamp': '2016-03-17 11:33:32.443002+00:00'} + return {TTFields.TARGET: target_vertex.vertex_id, + VProps.UPDATE_TIMESTAMP: '2016-03-17 11:33:32.443002', + DSProp.DATASOURCE_ACTION: 'update', + TFields.ALARM_NAME: alarm_name, + VProps.STATE: 'Active', + VProps.TYPE: 'add_vertex', + DSProp.ENTITY_TYPE: 'vitrage', + VProps.SEVERITY: 'CRITICAL', + VProps.VITRAGE_ID: 'mock_vitrage_id', + VProps.VITRAGE_RESOURCE_TYPE: 'nova.host', + VProps.CATEGORY: 'ALARM', + VProps.SAMPLE_TIMESTAMP: '2016-03-17 11:33:32.443002+00:00'} diff --git a/vitrage/tests/unit/evaluator/recipes/test_raise_alarm.py b/vitrage/tests/unit/evaluator/recipes/test_raise_alarm.py index 8360e64c3..728fdaf34 100644 --- a/vitrage/tests/unit/evaluator/recipes/test_raise_alarm.py +++ b/vitrage/tests/unit/evaluator/recipes/test_raise_alarm.py @@ -12,7 +12,9 @@ # License for the specific language governing permissions and limitations # under the License. +from vitrage.common.constants import VertexProperties as VProps from vitrage.datasources.alarm_properties import AlarmProperties +from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE from vitrage.evaluator.actions.base import ActionType from vitrage.evaluator.actions.recipes.action_steps import ADD_VERTEX from vitrage.evaluator.actions.recipes.action_steps import REMOVE_VERTEX @@ -29,7 +31,9 @@ class RaiseAlarmRecipeTest(base.BaseTest): @classmethod def setUpClass(cls): - cls.target_vertex = Vertex('RESOURCE:nova.host:test1') + cls.target_props = {VProps.TYPE: NOVA_HOST_DATASOURCE} + cls.target_vertex = Vertex('RESOURCE:nova.host:test1', + cls.target_props) cls.targets = {TFields.TARGET: cls.target_vertex} cls.props = {TFields.ALARM_NAME: 'VM_CPU_SUBOPTIMAL_PERFORMANCE'} @@ -49,7 +53,7 @@ class RaiseAlarmRecipeTest(base.BaseTest): self.assertEqual(ADD_VERTEX, action_steps[0].type) add_vertex_step_params = action_steps[0].params - self.assertEqual(3, len(add_vertex_step_params)) + self.assertEqual(4, len(add_vertex_step_params)) alarm_name = add_vertex_step_params[TFields.ALARM_NAME] self.assertEqual(self.props[TFields.ALARM_NAME], alarm_name) @@ -60,6 +64,11 @@ class RaiseAlarmRecipeTest(base.BaseTest): alarm_state = add_vertex_step_params[TFields.STATE] self.assertEqual(alarm_state, AlarmProperties.ACTIVE_STATE) + alarm_vitrage_resource_type = \ + add_vertex_step_params[VProps.VITRAGE_RESOURCE_TYPE] + self.assertEqual(self.target_vertex.properties[VProps.TYPE], + alarm_vitrage_resource_type) + def test_get_undo_recipe(self): # Test Action @@ -73,8 +82,9 @@ class RaiseAlarmRecipeTest(base.BaseTest): self.assertEqual(REMOVE_VERTEX, action_steps[0].type) remove_vertex_step_params = action_steps[0].params - # remove_vertex expects three params: alarm name, state and target - self.assertEqual(3, len(remove_vertex_step_params)) + # remove_vertex expects four params: alarm name, state, target, + # and type + self.assertEqual(4, len(remove_vertex_step_params)) alarm_name = remove_vertex_step_params[TFields.ALARM_NAME] self.assertEqual(self.props[TFields.ALARM_NAME], alarm_name) @@ -84,3 +94,8 @@ class RaiseAlarmRecipeTest(base.BaseTest): alarm_state = remove_vertex_step_params[TFields.STATE] self.assertEqual(alarm_state, AlarmProperties.INACTIVE_STATE) + + alarm_vitrage_resource_type = \ + remove_vertex_step_params[VProps.VITRAGE_RESOURCE_TYPE] + self.assertEqual(self.target_vertex.properties[VProps.TYPE], + alarm_vitrage_resource_type)