OpenStack RCA (Root Cause Analysis) Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
15KB

  1. # Copyright 2016 - Nokia
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  4. # not use this file except in compliance with the License. You may obtain
  5. # a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations
  13. # under the License.
  14. from six.moves import queue
  15. from vitrage.common.constants import DatasourceAction
  16. from vitrage.common.constants import DatasourceProperties as DSProp
  17. from vitrage.common.constants import EdgeLabel
  18. from vitrage.common.constants import EntityCategory
  19. from vitrage.common.constants import TemplateTopologyFields as TTFields
  20. from vitrage.common.constants import VertexProperties as VProps
  21. from vitrage.datasources.alarm_properties import AlarmProperties as AlarmProps
  22. from vitrage.datasources.nagios import NAGIOS_DATASOURCE
  23. from vitrage.datasources.nagios.properties import NagiosProperties as NProps
  24. from vitrage.datasources.nagios.properties import NagiosTestStatus
  25. from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE
  26. from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE
  27. from vitrage.entity_graph.mappings.operational_alarm_severity import \
  28. OperationalAlarmSeverity
  29. from vitrage.entity_graph.mappings.operational_resource_state import \
  30. OperationalResourceState
  31. from vitrage.evaluator.actions.action_executor import ActionExecutor
  32. from vitrage.evaluator.actions.base import ActionMode
  33. from vitrage.evaluator.actions.base import ActionType
  34. from vitrage.evaluator.actions.evaluator_event_transformer \
  35. import VITRAGE_DATASOURCE
  36. from vitrage.evaluator.actions.recipes.action_steps import ADD_VERTEX
  37. from vitrage.evaluator.actions.recipes.base import EVALUATOR_EVENT_TYPE
  38. from vitrage.evaluator.scenario_evaluator import ActionInfo
  39. from vitrage.evaluator.template_data import ActionSpecs
  40. from vitrage.evaluator.template_fields import TemplateFields as TFields
  41. from vitrage.opts import register_opts
  42. from vitrage.tests.functional.base import TestFunctionalBase
  43. from vitrage.tests.functional.test_configuration import TestConfiguration
  44. class TestActionExecutor(TestFunctionalBase, TestConfiguration):
  45. def setUp(self):
  46. super(TestActionExecutor, self).setUp()
  47. self.add_db()
  48. for datasource_name in self.conf.datasources.types:
  49. register_opts(datasource_name, self.conf.datasources.path)
  50. def _init_executer(self):
  51. event_queue = queue.Queue()
  52. def actions_callback(event_type, data):
  53. event_queue.put(data)
  54. return event_queue, ActionExecutor(actions_callback)
  55. def test_execute_set_state(self):
  56. # Test Setup
  57. processor = self._create_processor_with_graph()
  58. vertex_attrs = {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}
  59. host_vertices = processor.entity_graph.get_vertices(
  60. vertex_attr_filter=vertex_attrs)
  61. host_vertex_before = host_vertices[0]
  62. targets = {TFields.TARGET: host_vertex_before}
  63. props = {TFields.STATE: OperationalResourceState.SUBOPTIMAL}
  64. action_spec = ActionSpecs(0, ActionType.SET_STATE, targets, props)
  65. event_queue, action_executor = self._init_executer()
  66. # Test Action - do
  67. action_executor.execute(
  68. [ActionInfo(action_spec, ActionMode.DO, None, None)])
  69. self._consume_queue(event_queue, processor)
  70. host_vertex_after = processor.entity_graph.get_vertex(
  71. host_vertex_before.vertex_id)
  72. # Test Assertions
  73. agg_state_before = \
  74. host_vertex_before.get(VProps.VITRAGE_AGGREGATED_STATE)
  75. self.assertNotEqual(agg_state_before,
  76. OperationalResourceState.SUBOPTIMAL)
  77. self.assertNotIn(VProps.VITRAGE_STATE, host_vertex_before.properties)
  78. agg_state_after = \
  79. host_vertex_after.get(VProps.VITRAGE_AGGREGATED_STATE)
  80. self.assertEqual(agg_state_after, OperationalResourceState.SUBOPTIMAL)
  81. v_state_after = host_vertex_after.get(VProps.VITRAGE_STATE)
  82. self.assertEqual(v_state_after, OperationalResourceState.SUBOPTIMAL)
  83. # Test Action - undo
  84. action_executor.execute(
  85. [ActionInfo(action_spec, ActionMode.UNDO, None, None)])
  86. self._consume_queue(event_queue, processor)
  87. host_vertex_after_undo = processor.entity_graph.get_vertex(
  88. host_vertex_before.vertex_id)
  89. # Test Assertions
  90. agg_state_after_undo = \
  91. host_vertex_before.get(VProps.VITRAGE_AGGREGATED_STATE)
  92. self.assertEqual(agg_state_after_undo, agg_state_before)
  93. self.assertNotIn(
  94. VProps.VITRAGE_STATE, host_vertex_after_undo.properties)
  95. def test_execute_mark_instance_down(self):
  96. # Test Setup
  97. processor = self._create_processor_with_graph()
  98. vertex_attrs = {VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE}
  99. instance_vertices = processor.entity_graph.get_vertices(
  100. vertex_attr_filter=vertex_attrs)
  101. instance_vertex_before = instance_vertices[0]
  102. targets = {TFields.TARGET: instance_vertex_before}
  103. props = {}
  104. action_spec = ActionSpecs(0, ActionType.MARK_DOWN, targets, props)
  105. event_queue, action_executor = self._init_executer()
  106. # Test Action - do
  107. action_executor.execute(
  108. [ActionInfo(action_spec, ActionMode.DO, None, None)])
  109. self._consume_queue(event_queue, processor)
  110. instance_vertex_after = processor.entity_graph.get_vertex(
  111. instance_vertex_before.vertex_id)
  112. # Test Assertions
  113. self.assertTrue(instance_vertex_after.get(VProps.IS_MARKED_DOWN))
  114. # Test Action - undo
  115. action_executor.execute(
  116. [ActionInfo(action_spec, ActionMode.UNDO, None, None)])
  117. self._consume_queue(event_queue, processor)
  118. instance_vertex_after_undo = processor.entity_graph.get_vertex(
  119. instance_vertex_before.vertex_id)
  120. # Test Assertions
  121. self.assertFalse(instance_vertex_after_undo.get(VProps.IS_MARKED_DOWN))
  122. def test_execute_mark_down(self):
  123. # Test Setup
  124. processor = self._create_processor_with_graph()
  125. vertex_attrs = {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}
  126. host_vertices = processor.entity_graph.get_vertices(
  127. vertex_attr_filter=vertex_attrs)
  128. host_vertex_before = host_vertices[0]
  129. targets = {TFields.TARGET: host_vertex_before}
  130. props = {}
  131. action_spec = ActionSpecs(0, ActionType.MARK_DOWN, targets, props)
  132. event_queue, action_executor = self._init_executer()
  133. # Test Action - do
  134. action_executor.execute(
  135. [ActionInfo(action_spec, ActionMode.DO, None, None)])
  136. self._consume_queue(event_queue, processor)
  137. host_vertex_after = processor.entity_graph.get_vertex(
  138. host_vertex_before.vertex_id)
  139. # Test Assertions
  140. self.assertTrue(host_vertex_after.get(VProps.IS_MARKED_DOWN))
  141. # Test Action - undo
  142. action_executor.execute(
  143. [ActionInfo(action_spec, ActionMode.UNDO, None, None)])
  144. self._consume_queue(event_queue, processor)
  145. host_vertex_after_undo = processor.entity_graph.get_vertex(
  146. host_vertex_before.vertex_id)
  147. # Test Assertions
  148. self.assertFalse(host_vertex_after_undo.get(VProps.IS_MARKED_DOWN))
  149. def test_execute_add_edge(self):
  150. # Test Setup
  151. processor = self._create_processor_with_graph()
  152. vertex_attrs = {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}
  153. host_vertices = processor.entity_graph.get_vertices(
  154. vertex_attr_filter=vertex_attrs)
  155. host_1 = host_vertices[0]
  156. nagios_event1 = TestActionExecutor._get_nagios_event(
  157. host_1.get(VProps.ID), NOVA_HOST_DATASOURCE)
  158. processor.process_event(nagios_event1)
  159. host_2 = host_vertices[1]
  160. nagios_event2 = TestActionExecutor._get_nagios_event(
  161. host_2.get(VProps.ID), NOVA_HOST_DATASOURCE)
  162. processor.process_event(nagios_event2)
  163. alarms_attrs = {VProps.VITRAGE_TYPE: NAGIOS_DATASOURCE}
  164. alarms_vertices = processor.entity_graph.get_vertices(
  165. vertex_attr_filter=alarms_attrs)
  166. alarm1 = alarms_vertices[0]
  167. alarm2 = alarms_vertices[1]
  168. targets = {
  169. TFields.TARGET: alarm1,
  170. TFields.SOURCE: alarm2
  171. }
  172. action_spec = ActionSpecs(
  173. 0, ActionType.ADD_CAUSAL_RELATIONSHIP, targets, {})
  174. event_queue, action_executor = self._init_executer()
  175. before_edge = processor.entity_graph.get_edge(alarm2.vertex_id,
  176. alarm1.vertex_id,
  177. EdgeLabel.CAUSES)
  178. # Test Action - do
  179. action_executor.execute(
  180. [ActionInfo(action_spec, ActionMode.DO, None, None)])
  181. self._consume_queue(event_queue, processor)
  182. new_edge = processor.entity_graph.get_edge(alarm2.vertex_id,
  183. alarm1.vertex_id,
  184. EdgeLabel.CAUSES)
  185. # Test Assertions
  186. self.assertIsNone(before_edge)
  187. self.assertIsNotNone(new_edge)
  188. def test_execute_add_vertex(self):
  189. # Test Setup
  190. processor = self._create_processor_with_graph()
  191. vertex_attrs = {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}
  192. host_vertices = processor.entity_graph.get_vertices(
  193. vertex_attr_filter=vertex_attrs)
  194. host = host_vertices[0]
  195. targets = {TFields.TARGET: host}
  196. props = {
  197. TFields.ALARM_NAME: 'VM_CPU_SUBOPTIMAL_PERFORMANCE',
  198. TFields.SEVERITY: OperationalAlarmSeverity.CRITICAL,
  199. VProps.STATE: AlarmProps.ACTIVE_STATE,
  200. VProps.RESOURCE_ID: host[VProps.ID],
  201. VProps.VITRAGE_ID: 'DUMMY_ID'
  202. }
  203. # Raise alarm action adds new vertex with type vitrage to the graph
  204. action_spec = ActionSpecs(0, ActionType.RAISE_ALARM, targets, props)
  205. alarm_vertex_attrs = {VProps.VITRAGE_TYPE: VITRAGE_DATASOURCE}
  206. before_alarms = processor.entity_graph.get_vertices(
  207. vertex_attr_filter=alarm_vertex_attrs)
  208. event_queue, action_executor = self._init_executer()
  209. # Test Action
  210. action_executor.execute(
  211. [ActionInfo(action_spec, ActionMode.DO, None, None)])
  212. self._consume_queue(event_queue, processor)
  213. after_alarms = processor.entity_graph.get_vertices(
  214. vertex_attr_filter=alarm_vertex_attrs)
  215. # Assertions
  216. self.assertEqual(len(before_alarms) + 1, len(after_alarms))
  217. self.assert_is_not_empty(after_alarms)
  218. alarm = after_alarms[0]
  219. self.assertEqual(alarm.properties[VProps.VITRAGE_CATEGORY],
  220. EntityCategory.ALARM)
  221. self.assertEqual(alarm.properties[VProps.VITRAGE_TYPE],
  222. VITRAGE_DATASOURCE)
  223. self.assertEqual(alarm.properties[VProps.SEVERITY],
  224. props[TFields.SEVERITY])
  225. self.assertEqual(alarm.properties[VProps.VITRAGE_OPERATIONAL_SEVERITY],
  226. props[TFields.SEVERITY])
  227. self.assertEqual(alarm.properties[VProps.STATE],
  228. AlarmProps.ACTIVE_STATE)
  229. self.assertEqual(alarm.properties[VProps.VITRAGE_RESOURCE_ID],
  230. action_spec.targets
  231. [TTFields.TARGET][VProps.VITRAGE_ID]),
  232. self.assertEqual(alarm.properties[VProps.VITRAGE_RESOURCE_TYPE],
  233. NOVA_HOST_DATASOURCE)
  234. def test_execute_add_and_remove_vertex(self):
  235. # Test Setup
  236. processor = self._create_processor_with_graph()
  237. vertex_attrs = {VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE}
  238. host_vertices = processor.entity_graph.get_vertices(
  239. vertex_attr_filter=vertex_attrs)
  240. host = host_vertices[0]
  241. targets = {TFields.TARGET: host}
  242. props = {
  243. TFields.ALARM_NAME: 'VM_CPU_SUBOPTIMAL_PERFORMANCE',
  244. TFields.SEVERITY: OperationalAlarmSeverity.CRITICAL,
  245. VProps.STATE: AlarmProps.ACTIVE_STATE,
  246. VProps.RESOURCE_ID: host[VProps.ID]
  247. }
  248. action_spec = ActionSpecs(0, ActionType.RAISE_ALARM, targets, props)
  249. add_vertex_event = TestActionExecutor._get_vitrage_add_vertex_event(
  250. host,
  251. props[TFields.ALARM_NAME],
  252. props[TFields.SEVERITY])
  253. processor.process_event(add_vertex_event)
  254. alarm_vertex_attrs = {VProps.VITRAGE_TYPE: VITRAGE_DATASOURCE,
  255. VProps.VITRAGE_IS_DELETED: False}
  256. before_alarms = processor.entity_graph.get_vertices(
  257. vertex_attr_filter=alarm_vertex_attrs)
  258. event_queue, action_executor = self._init_executer()
  259. # Test Action - undo
  260. action_executor.execute(
  261. [ActionInfo(action_spec, ActionMode.UNDO, None, None)])
  262. self._consume_queue(event_queue, processor)
  263. after_alarms = processor.entity_graph.get_vertices(
  264. vertex_attr_filter=alarm_vertex_attrs)
  265. # Test Assertions
  266. self.assertEqual(len(before_alarms) - 1, len(after_alarms))
  267. @staticmethod
  268. def _get_nagios_event(resource_name, resource_type):
  269. return {NProps.LAST_CHECK: '2016-02-07 15:26:04',
  270. NProps.RESOURCE_NAME: resource_name,
  271. NProps.RESOURCE_TYPE: resource_type,
  272. NProps.SERVICE: 'Check_MK',
  273. NProps.STATUS: NagiosTestStatus.CRITICAL,
  274. NProps.STATUS_INFO: 'test test test',
  275. DSProp.DATASOURCE_ACTION: DatasourceAction.SNAPSHOT,
  276. DSProp.ENTITY_TYPE: NAGIOS_DATASOURCE,
  277. DSProp.SAMPLE_DATE: '2016-02-07T15:26:04Z'}
  278. @staticmethod
  279. def _get_vitrage_add_vertex_event(target_vertex, alarm_name, severity):
  280. return {TTFields.TARGET: target_vertex.vertex_id,
  281. VProps.UPDATE_TIMESTAMP: '2016-03-17 11:33:32.443002',
  282. DSProp.DATASOURCE_ACTION: DatasourceAction.UPDATE,
  283. TFields.ALARM_NAME: alarm_name,
  284. VProps.STATE: 'Active',
  285. EVALUATOR_EVENT_TYPE: ADD_VERTEX,
  286. DSProp.ENTITY_TYPE: VITRAGE_DATASOURCE,
  287. VProps.SEVERITY: OperationalAlarmSeverity.CRITICAL,
  288. VProps.VITRAGE_ID: 'mock_vitrage_id',
  289. VProps.VITRAGE_RESOURCE_TYPE: NOVA_HOST_DATASOURCE,
  290. VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
  291. VProps.VITRAGE_SAMPLE_TIMESTAMP:
  292. '2016-03-17 11:33:32.443002+00:00'}