diff --git a/etc/vitrage/templates.sample/host_down_scenarios.yaml b/etc/vitrage/templates.sample/host_down_scenarios.yaml index 746bd1648..ad66716f4 100644 --- a/etc/vitrage/templates.sample/host_down_scenarios.yaml +++ b/etc/vitrage/templates.sample/host_down_scenarios.yaml @@ -68,3 +68,7 @@ scenarios: action_target: source: host_down_alarm target: instance_alarm + - action: + action_type: mark_down + action_target: + target: instance diff --git a/vitrage/notifier/plugins/nova/__init__.py b/vitrage/notifier/plugins/nova/__init__.py index 9575afbd1..7abd66730 100644 --- a/vitrage/notifier/plugins/nova/__init__.py +++ b/vitrage/notifier/plugins/nova/__init__.py @@ -21,3 +21,8 @@ OPTS = [ help='nova notifier class path', required=True), ] + + +class InstanceState(object): + ERROR = 'error' + ACTIVE = 'active' diff --git a/vitrage/notifier/plugins/nova/nova_notifier.py b/vitrage/notifier/plugins/nova/nova_notifier.py index 230efe18d..92bef269b 100644 --- a/vitrage/notifier/plugins/nova/nova_notifier.py +++ b/vitrage/notifier/plugins/nova/nova_notifier.py @@ -16,7 +16,9 @@ from oslo_log import log as logging from vitrage.common.constants import NotifierEventTypes from vitrage.common.constants import VertexProperties as VProps from vitrage.datasources import NOVA_HOST_DATASOURCE +from vitrage.datasources import NOVA_INSTANCE_DATASOURCE from vitrage.notifier.plugins.base import NotifierBase +from vitrage.notifier.plugins.nova import InstanceState from vitrage import os_clients LOG = logging.getLogger(__name__) @@ -31,13 +33,21 @@ class NovaNotifier(NotifierBase): def __init__(self, conf): super(NovaNotifier, self).__init__(conf) self.client = os_clients.nova_client(conf) + self.actions = { + NOVA_HOST_DATASOURCE: self._mark_host_down, + NOVA_INSTANCE_DATASOURCE: self._reset_instance_state + } def process_event(self, data, event_type): - if data and data.get(VProps.VITRAGE_TYPE) == NOVA_HOST_DATASOURCE: + if data and data.get(VProps.VITRAGE_TYPE) in self.actions: + action = self.actions[data.get(VProps.VITRAGE_TYPE)] if event_type == NotifierEventTypes.ACTIVATE_MARK_DOWN_EVENT: - self._mark_host_down(data.get(VProps.ID), True) + action(data.get(VProps.ID), True) elif event_type == NotifierEventTypes.DEACTIVATE_MARK_DOWN_EVENT: - self._mark_host_down(data.get(VProps.ID), False) + action(data.get(VProps.ID), False) + elif data: + LOG.warning('Unsupport datasource type %s for mark_down action', + data.get(VProps.VITRAGE_TYPE)) def _mark_host_down(self, host_id, is_down): try: @@ -48,3 +58,13 @@ class NovaNotifier(NotifierBase): LOG.info('RESPONSE %s', str(response.to_dict())) except Exception as e: LOG.exception('Failed to services.force_down - %s', e) + + def _reset_instance_state(self, server_id, is_down): + state = InstanceState.ERROR if is_down else InstanceState.ACTIVE + try: + LOG.info('Nova servers.reset_state - server: %s, state: %s', + str(server_id), str(state)) + response = self.client.servers.reset_state(server_id, state) + LOG.info('RESPONSE %s', str(response)) + except Exception as e: + LOG.exception('Failed to execute servers.reset_state - %s', e) diff --git a/vitrage/tests/functional/evaluator/test_action_executor.py b/vitrage/tests/functional/evaluator/test_action_executor.py index fc4d5f829..7b97fc840 100644 --- a/vitrage/tests/functional/evaluator/test_action_executor.py +++ b/vitrage/tests/functional/evaluator/test_action_executor.py @@ -28,6 +28,7 @@ from vitrage.datasources.nagios import NAGIOS_DATASOURCE from vitrage.datasources.nagios.properties import NagiosProperties as NProps from vitrage.datasources.nagios.properties import NagiosTestStatus from vitrage.datasources.nova.host import NOVA_HOST_DATASOURCE +from vitrage.datasources.nova.instance import NOVA_INSTANCE_DATASOURCE from vitrage.entity_graph.mappings.operational_alarm_severity import \ OperationalAlarmSeverity from vitrage.entity_graph.mappings.operational_resource_state import \ @@ -116,6 +117,43 @@ class TestActionExecutor(TestFunctionalBase): self.assertNotIn( VProps.VITRAGE_STATE, host_vertex_after_undo.properties) + def test_execute_mark_instance_down(self): + + # Test Setup + processor = self._create_processor_with_graph(self.conf) + + vertex_attrs = {VProps.VITRAGE_TYPE: NOVA_INSTANCE_DATASOURCE} + instance_vertices = processor.entity_graph.get_vertices( + vertex_attr_filter=vertex_attrs) + instance_vertex_before = instance_vertices[0] + + targets = {TFields.TARGET: instance_vertex_before} + props = {} + action_spec = ActionSpecs(0, ActionType.MARK_DOWN, targets, props) + + event_queue = queue.Queue() + action_executor = ActionExecutor(self.conf, event_queue) + + # Test Action - do + action_executor.execute(action_spec, ActionMode.DO) + processor.process_event(event_queue.get()) + + instance_vertex_after = processor.entity_graph.get_vertex( + instance_vertex_before.vertex_id) + + # Test Assertions + self.assertTrue(instance_vertex_after.get(VProps.IS_MARKED_DOWN)) + + # Test Action - undo + action_executor.execute(action_spec, ActionMode.UNDO) + processor.process_event(event_queue.get()) + + instance_vertex_after_undo = processor.entity_graph.get_vertex( + instance_vertex_before.vertex_id) + + # Test Assertions + self.assertFalse(instance_vertex_after_undo.get(VProps.IS_MARKED_DOWN)) + def test_execute_mark_down(self): # Test Setup