Merge "Add mark-down action"
This commit is contained in:
commit
eab092aa8b
@ -312,9 +312,62 @@ Common parameters and their acceptable values - for writing templates
|
||||
| action | action_type | raise_alarm, | |
|
||||
| | | set_state, | |
|
||||
| | | add_causal_relationship | |
|
||||
| | | mark_down | |
|
||||
+-------------------+---------------+-------------------------+------------------------------------+
|
||||
|
||||
|
||||
Supported Actions
|
||||
-----------------
|
||||
|
||||
raise_alarm
|
||||
^^^^^^^^^^^
|
||||
Raise a deduced alarm on a target entity
|
||||
::
|
||||
|
||||
action:
|
||||
action_type : raise_alarm
|
||||
properties:
|
||||
alarm_name: some problem # mandatory; string that is valid variable name
|
||||
severity: critical # mandatory; should match values in "vitrage.yaml"
|
||||
action_target:
|
||||
target: instance # mandatory. entity (from the definitions section) to raise an alarm on. Should not be an alarm.
|
||||
|
||||
set_state
|
||||
^^^^^^^^^^^
|
||||
Set state of specified entity. This will directly affect the state as seen in vitrage, but will not impact the state at the relevant datasource of this entity.
|
||||
::
|
||||
|
||||
action:
|
||||
action_type : set_state
|
||||
properties:
|
||||
state: error # mandatory; should match values in the relevant datasource_values YAML file for this entity.
|
||||
action_target:
|
||||
target: host # mandatory. entity (from the definitions section) to change state
|
||||
|
||||
|
||||
add_causal_relationship
|
||||
^^^^^^^^^^^
|
||||
Add a causal relationship between alarms.
|
||||
::
|
||||
|
||||
action:
|
||||
action_type : add_causal_relationship
|
||||
action_target:
|
||||
source: host_alarm # mandatory. the alarm that caused the target alarm (name from the definitions section)
|
||||
target: instance_alarm # mandatory. the alarm that was caused by the source alarm (name from the definitions section)
|
||||
|
||||
|
||||
mark_down
|
||||
^^^^^^^^^
|
||||
Set an entity marked_down field.
|
||||
This can be used along with nova notifier to call force_down for a host
|
||||
::
|
||||
|
||||
action:
|
||||
action_type : mark_down
|
||||
action_target:
|
||||
target: instance # mandatory. entity (from the definitions section) to be marked as down
|
||||
|
||||
Future support & Open Issues
|
||||
============================
|
||||
|
||||
|
@ -32,6 +32,7 @@ class VertexProperties(object):
|
||||
AGGREGATED_SEVERITY = 'aggregated_severity'
|
||||
OPERATIONAL_SEVERITY = 'operational_severity'
|
||||
VITRAGE_ID = 'vitrage_id'
|
||||
IS_MARKED_DOWN = 'is_marked_down'
|
||||
INFO = 'info'
|
||||
GRAPH_INDEX = 'graph_index'
|
||||
|
||||
@ -93,3 +94,5 @@ class EventAction(object):
|
||||
class NotifierEventTypes(object):
|
||||
ACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.activate'
|
||||
DEACTIVATE_DEDUCED_ALARM_EVENT = 'vitrage.deduced_alarm.deactivate'
|
||||
ACTIVATE_MARK_DOWN_EVENT = 'vitrage.mark_down.activate'
|
||||
DEACTIVATE_MARK_DOWN_EVENT = 'vitrage.mark_down.deactivate'
|
||||
|
@ -32,6 +32,7 @@ from vitrage.evaluator.actions.recipes.action_steps import UPDATE_VERTEX
|
||||
from vitrage.evaluator.actions.recipes.add_causal_relationship import \
|
||||
AddCausalRelationship
|
||||
from vitrage.evaluator.actions.recipes.base import EVALUATOR_EVENT_TYPE
|
||||
from vitrage.evaluator.actions.recipes.mark_down import MarkDown
|
||||
from vitrage.evaluator.actions.recipes.raise_alarm import RaiseAlarm
|
||||
from vitrage.evaluator.actions.recipes.set_state import SetState
|
||||
|
||||
@ -128,4 +129,7 @@ class ActionExecutor(object):
|
||||
"%s.%s" % (AddCausalRelationship.__module__,
|
||||
AddCausalRelationship.__name__))
|
||||
|
||||
recipes[ActionType.MARK_DOWN] = importutils.import_object(
|
||||
"%s.%s" % (MarkDown.__module__, MarkDown.__name__))
|
||||
|
||||
return recipes
|
||||
|
@ -18,10 +18,12 @@ class ActionType(object):
|
||||
SET_STATE = 'set_state'
|
||||
RAISE_ALARM = 'raise_alarm'
|
||||
ADD_CAUSAL_RELATIONSHIP = 'add_causal_relationship'
|
||||
MARK_DOWN = 'mark_down'
|
||||
|
||||
action_types = [ActionType.SET_STATE,
|
||||
ActionType.RAISE_ALARM,
|
||||
ActionType.ADD_CAUSAL_RELATIONSHIP]
|
||||
ActionType.ADD_CAUSAL_RELATIONSHIP,
|
||||
ActionType.MARK_DOWN]
|
||||
|
||||
|
||||
class ActionMode(object):
|
||||
|
@ -62,7 +62,8 @@ class EvaluatorEventTransformer(transformer_base.TransformerBase):
|
||||
|
||||
if event_type == UPDATE_VERTEX:
|
||||
properties = {
|
||||
VProps.VITRAGE_STATE: event[VProps.VITRAGE_STATE],
|
||||
VProps.VITRAGE_STATE: event.get(VProps.VITRAGE_STATE),
|
||||
VProps.IS_MARKED_DOWN: event.get(VProps.IS_MARKED_DOWN),
|
||||
VProps.UPDATE_TIMESTAMP: update_timestamp,
|
||||
VProps.SAMPLE_TIMESTAMP: event[VProps.SAMPLE_TIMESTAMP],
|
||||
VProps.IS_PLACEHOLDER: False
|
||||
|
@ -16,7 +16,7 @@ from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.evaluator.template_fields import TemplateFields
|
||||
|
||||
|
||||
class CausalTools(object):
|
||||
class BaselineTools(object):
|
||||
@staticmethod
|
||||
def get_score(action_info):
|
||||
return 1 # no priorities
|
||||
|
61
vitrage/evaluator/actions/recipes/mark_down.py
Normal file
61
vitrage/evaluator/actions/recipes/mark_down.py
Normal file
@ -0,0 +1,61 @@
|
||||
# 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 VertexProperties as VProps
|
||||
from vitrage.evaluator.actions.recipes.action_steps import UPDATE_VERTEX
|
||||
from vitrage.evaluator.actions.recipes import base
|
||||
from vitrage.evaluator.actions.recipes.base import ActionStepWrapper
|
||||
from vitrage.evaluator.template_fields import TemplateFields as TFields
|
||||
|
||||
|
||||
class MarkDown(base.Recipe):
|
||||
"""Mark A host as down.
|
||||
|
||||
The 'get_do_recipe' and 'get_undo_recipe' receive action_spec as input.
|
||||
The action_spec contains the following fields: type, targets and
|
||||
properties. example input:
|
||||
|
||||
action_spec = ActionSpecs('type'= {'set_state'},
|
||||
'targets'= {target: Vertex},
|
||||
'properties' = {is_marked_down : True}
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_do_recipe(action_spec):
|
||||
|
||||
update_vertex_step = MarkDown._get_update_vertex_step(
|
||||
action_spec.targets[TFields.TARGET].vertex_id,
|
||||
True)
|
||||
|
||||
return [update_vertex_step]
|
||||
|
||||
@staticmethod
|
||||
def get_undo_recipe(action_spec):
|
||||
|
||||
update_vertex_step = MarkDown._get_update_vertex_step(
|
||||
action_spec.targets[TFields.TARGET].vertex_id,
|
||||
False)
|
||||
|
||||
return [update_vertex_step]
|
||||
|
||||
@staticmethod
|
||||
def _get_update_vertex_step(target_id, is_marked_down):
|
||||
|
||||
update_vertex_params = {
|
||||
VProps.VITRAGE_ID: target_id,
|
||||
VProps.IS_MARKED_DOWN: is_marked_down
|
||||
}
|
||||
update_vertex_step = ActionStepWrapper(UPDATE_VERTEX,
|
||||
update_vertex_params)
|
||||
|
||||
return update_vertex_step
|
@ -281,7 +281,8 @@ class ActionTracker(object):
|
||||
self._action_tools = {
|
||||
ActionType.SET_STATE: pt.SetStateTools(all_scores),
|
||||
ActionType.RAISE_ALARM: pt.RaiseAlarmTools(alarms_score),
|
||||
ActionType.ADD_CAUSAL_RELATIONSHIP: pt.CausalTools
|
||||
ActionType.ADD_CAUSAL_RELATIONSHIP: pt.BaselineTools,
|
||||
ActionType.MARK_DOWN: pt.BaselineTools
|
||||
}
|
||||
|
||||
def get_key(self, action_specs):
|
||||
|
@ -68,7 +68,10 @@ status_msgs = {
|
||||
126: 'raise_alarm action must contain severity field in properties block.',
|
||||
127: 'raise_alarm action must contain target field in target_action block',
|
||||
128: 'set_state action must contain state field in properties block.',
|
||||
129: 'set_state action must contain target field in target_action block',
|
||||
129: 'set_state action must contain target field in target_action block.',
|
||||
130: 'add_causal_relationship action must contain target and source field '
|
||||
'in target_action block',
|
||||
'in target_action block.',
|
||||
131: 'mark_down action must contain \'target\' field in'
|
||||
' \'target_action\' block.',
|
||||
|
||||
}
|
||||
|
@ -168,17 +168,20 @@ def validate_scenario_actions(actions, entities_ids):
|
||||
def validate_scenario_action(action, entities_ids):
|
||||
|
||||
action_type = action[TemplateFields.ACTION_TYPE]
|
||||
actions = {
|
||||
ActionType.RAISE_ALARM: validate_raise_alarm_action,
|
||||
ActionType.SET_STATE: validate_set_state_action,
|
||||
ActionType.ADD_CAUSAL_RELATIONSHIP:
|
||||
validate_add_causal_relationship_action,
|
||||
ActionType.MARK_DOWN: validate_mark_down_action,
|
||||
}
|
||||
|
||||
if action_type == ActionType.RAISE_ALARM:
|
||||
return validate_raise_alarm_action(action, entities_ids)
|
||||
elif action_type == ActionType.SET_STATE:
|
||||
return validate_set_state_action(action, entities_ids)
|
||||
elif action_type == ActionType.ADD_CAUSAL_RELATIONSHIP:
|
||||
return validate_add_causal_relationship_action(action, entities_ids)
|
||||
else:
|
||||
if action_type not in actions.keys():
|
||||
LOG.error('%s status code: %s' % (status_msgs[120], 120))
|
||||
return get_fault_result(RESULT_DESCRIPTION, 120)
|
||||
|
||||
return actions[action_type](action, entities_ids)
|
||||
|
||||
|
||||
def validate_raise_alarm_action(action, entities_ids):
|
||||
|
||||
@ -240,6 +243,17 @@ def validate_add_causal_relationship_action(action, entities_ids):
|
||||
return _validate_template_id(entities_ids, source)
|
||||
|
||||
|
||||
def validate_mark_down_action(action, entities_ids):
|
||||
|
||||
action_target = action[TemplateFields.ACTION_TARGET]
|
||||
if TemplateFields.TARGET not in action_target:
|
||||
LOG.error('%s status code: %s' % (status_msgs[131], 131))
|
||||
return get_fault_result(RESULT_DESCRIPTION, 131)
|
||||
|
||||
target = action_target[TemplateFields.TARGET]
|
||||
return _validate_template_id(entities_ids, target)
|
||||
|
||||
|
||||
def _validate_template_id(ids, id_to_check):
|
||||
|
||||
if id_to_check not in ids:
|
||||
|
@ -246,7 +246,7 @@ def _validate_dict_schema(schema, value):
|
||||
msg = status_msgs[4] % e
|
||||
|
||||
LOG.error('%s status code: %s' % (msg, status_code))
|
||||
return get_fault_result(RESULT_DESCRIPTION, status_code)
|
||||
return get_fault_result(RESULT_DESCRIPTION, status_code, msg)
|
||||
|
||||
return get_correct_result(RESULT_DESCRIPTION)
|
||||
|
||||
|
78
vitrage/tests/unit/evaluator/recipes/test_mark_down.py
Normal file
78
vitrage/tests/unit/evaluator/recipes/test_mark_down.py
Normal file
@ -0,0 +1,78 @@
|
||||
# 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 VertexProperties as VProps
|
||||
from vitrage.evaluator.actions.base import ActionType
|
||||
from vitrage.evaluator.actions.recipes.action_steps import UPDATE_VERTEX
|
||||
from vitrage.evaluator.actions.recipes.mark_down import MarkDown
|
||||
from vitrage.evaluator.template_data import ActionSpecs
|
||||
from vitrage.evaluator.template_fields import TemplateFields as TFields
|
||||
from vitrage.graph import Vertex
|
||||
from vitrage.tests import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MarkDownRecipeTest(base.BaseTest):
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
|
||||
cls.target_vertex = Vertex('RESOURCE:nova.host:test1')
|
||||
|
||||
targets = {TFields.TARGET: cls.target_vertex}
|
||||
cls.action_spec = ActionSpecs(ActionType.MARK_DOWN, targets, None)
|
||||
|
||||
def test_get_do_recipe(self):
|
||||
|
||||
# Test Action
|
||||
action_steps = MarkDown.get_do_recipe(self.action_spec)
|
||||
|
||||
# Test Assertions
|
||||
|
||||
# expecting for one step: [update_vertex]
|
||||
self.assertEqual(1, len(action_steps))
|
||||
|
||||
self.assertEqual(UPDATE_VERTEX, action_steps[0].type)
|
||||
update_vertex_step_params = action_steps[0].params
|
||||
self.assertEqual(2, len(update_vertex_step_params))
|
||||
|
||||
is_marked_down = update_vertex_step_params[VProps.IS_MARKED_DOWN]
|
||||
self.assertTrue(is_marked_down)
|
||||
|
||||
vitrage_id = update_vertex_step_params[VProps.VITRAGE_ID]
|
||||
self.assertEqual(self.target_vertex.vertex_id, vitrage_id)
|
||||
|
||||
def test_get_undo_recipe(self):
|
||||
|
||||
# Test Action
|
||||
action_steps = MarkDown.get_undo_recipe(self.action_spec)
|
||||
|
||||
# Test Assertions
|
||||
|
||||
# expecting for one step: [update_vertex]
|
||||
self.assertEqual(1, len(action_steps))
|
||||
|
||||
self.assertEqual(UPDATE_VERTEX, action_steps[0].type)
|
||||
update_vertex_step_params = action_steps[0].params
|
||||
self.assertEqual(2, len(update_vertex_step_params))
|
||||
|
||||
is_marked_down = update_vertex_step_params[VProps.IS_MARKED_DOWN]
|
||||
self.assertFalse(is_marked_down)
|
||||
|
||||
vitrage_id = update_vertex_step_params[VProps.VITRAGE_ID]
|
||||
self.assertEqual(self.target_vertex.vertex_id, vitrage_id)
|
@ -228,6 +228,43 @@ class TemplateContentValidatorTest(base.BaseTest):
|
||||
# Test assertions
|
||||
self._test_assert_with_fault_result(result, 128)
|
||||
|
||||
def test_validate_mark_down_action(self):
|
||||
|
||||
# Test setup
|
||||
ids = ['123', '456', '789']
|
||||
action = self._create_mark_down_action('123')
|
||||
|
||||
# Test action and assertions
|
||||
result = validator.validate_mark_down_action(action, ids)
|
||||
|
||||
# Test Assertions
|
||||
self._test_assert_with_correct_result(result)
|
||||
|
||||
def test_validate_mark_down_action_with_invalid_target_id(self):
|
||||
|
||||
# Test setup
|
||||
ids = ['123', '456', '789']
|
||||
action = self._create_mark_down_action('unknown')
|
||||
|
||||
# Test action
|
||||
result = validator.validate_mark_down_action(action, ids)
|
||||
|
||||
# Test assertions
|
||||
self._test_assert_with_fault_result(result, 3)
|
||||
|
||||
def test_validate_mark_down_action_without_target_id(self):
|
||||
|
||||
# Test setup
|
||||
ids = ['123', '456', '789']
|
||||
action = self._create_mark_down_action('123')
|
||||
action[TemplateFields.ACTION_TARGET].pop(TemplateFields.TARGET)
|
||||
|
||||
# Test action
|
||||
result = validator.validate_mark_down_action(action, ids)
|
||||
|
||||
# Test assertions
|
||||
self._test_assert_with_fault_result(result, 131)
|
||||
|
||||
def test_validate_add_causal_relationship_action(self):
|
||||
|
||||
# Test setup
|
||||
@ -323,6 +360,9 @@ class TemplateContentValidatorTest(base.BaseTest):
|
||||
set_state_action = self._create_set_state_action(target)
|
||||
actions.append({TemplateFields.ACTION: set_state_action})
|
||||
|
||||
mark_host_down_action = self._create_mark_down_action(target)
|
||||
actions.append({TemplateFields.ACTION: mark_host_down_action})
|
||||
|
||||
causal_action = self._create_add_causal_relationship_action(target,
|
||||
source)
|
||||
actions.append({TemplateFields.ACTION: causal_action})
|
||||
@ -343,6 +383,18 @@ class TemplateContentValidatorTest(base.BaseTest):
|
||||
|
||||
return action
|
||||
|
||||
@staticmethod
|
||||
def _create_mark_down_action(target):
|
||||
|
||||
action_target = {
|
||||
TemplateFields.TARGET: target
|
||||
}
|
||||
action = {
|
||||
TemplateFields.ACTION_TYPE: ActionType.MARK_DOWN,
|
||||
TemplateFields.ACTION_TARGET: action_target,
|
||||
}
|
||||
return action
|
||||
|
||||
@staticmethod
|
||||
def _create_set_state_action(target):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user