185 lines
6.5 KiB
Python
185 lines
6.5 KiB
Python
# 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.
|
|
|
|
import copy
|
|
|
|
from copy import deepcopy
|
|
from oslo_log import log
|
|
from oslo_utils import importutils
|
|
|
|
from vitrage.common.constants import DatasourceAction as AType
|
|
from vitrage.common.constants import DatasourceProperties as DSProps
|
|
from vitrage.common.constants import VertexProperties as VProps
|
|
from vitrage.evaluator.actions.base import ActionMode
|
|
from vitrage.evaluator.actions.base import ActionType
|
|
from vitrage.evaluator.actions.evaluator_event_transformer \
|
|
import VITRAGE_DATASOURCE
|
|
from vitrage.evaluator.actions.notifier import EvaluatorNotifier
|
|
from vitrage.evaluator.actions.recipes.action_steps import ADD_EDGE
|
|
from vitrage.evaluator.actions.recipes.action_steps import ADD_VERTEX
|
|
from vitrage.evaluator.actions.recipes.action_steps import EXECUTE_EXTERNAL
|
|
from vitrage.evaluator.actions.recipes.action_steps import EXECUTION_ENGINE
|
|
from vitrage.evaluator.actions.recipes.action_steps import REMOVE_EDGE
|
|
from vitrage.evaluator.actions.recipes.action_steps import REMOVE_VERTEX
|
|
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.execute_mistral import ExecuteMistral
|
|
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
|
|
from vitrage.utils import datetime as datetime_utils
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
EVALUATOR_EVENT = 'evaluator.event'
|
|
TARGET = 'target'
|
|
SOURCE = 'source'
|
|
|
|
|
|
class ActionExecutor(object):
|
|
|
|
def __init__(self, actions_callback):
|
|
|
|
self.actions_callback = actions_callback
|
|
self.notifier = EvaluatorNotifier()
|
|
self.action_recipes = ActionExecutor._register_action_recipes()
|
|
|
|
self.action_step_defs = {
|
|
ADD_VERTEX: self._add_vertex,
|
|
REMOVE_VERTEX: self._remove_vertex,
|
|
UPDATE_VERTEX: self._update_vertex,
|
|
ADD_EDGE: self._add_edge,
|
|
REMOVE_EDGE: self._remove_edge,
|
|
EXECUTE_EXTERNAL: self._execute_external,
|
|
}
|
|
|
|
def execute(self, actions):
|
|
if not actions:
|
|
return
|
|
|
|
events = []
|
|
for action in actions:
|
|
LOG.info('Action: %s', self._action_str(action))
|
|
events.extend(self._execute(action.specs, action.mode))
|
|
self.actions_callback(EVALUATOR_EVENT, events)
|
|
|
|
def _execute(self, action_spec, action_mode):
|
|
|
|
action_recipe = self.action_recipes[action_spec.type]
|
|
if action_mode == ActionMode.DO:
|
|
steps = action_recipe.get_do_recipe(action_spec)
|
|
else:
|
|
steps = action_recipe.get_undo_recipe(action_spec)
|
|
|
|
events = []
|
|
for step in steps:
|
|
event = self.action_step_defs[step.type](step.params)
|
|
if event:
|
|
events.append(event)
|
|
return events
|
|
|
|
def _add_vertex(self, params):
|
|
|
|
event = copy.deepcopy(params)
|
|
ActionExecutor._add_default_properties(event)
|
|
event[EVALUATOR_EVENT_TYPE] = ADD_VERTEX
|
|
|
|
return event
|
|
|
|
def _update_vertex(self, params):
|
|
|
|
event = copy.deepcopy(params)
|
|
ActionExecutor._add_default_properties(event)
|
|
event[EVALUATOR_EVENT_TYPE] = UPDATE_VERTEX
|
|
|
|
return event
|
|
|
|
def _remove_vertex(self, params):
|
|
event = copy.deepcopy(params)
|
|
ActionExecutor._add_default_properties(event)
|
|
event[EVALUATOR_EVENT_TYPE] = REMOVE_VERTEX
|
|
|
|
return event
|
|
|
|
def _add_edge(self, params):
|
|
|
|
event = copy.deepcopy(params)
|
|
ActionExecutor._add_default_properties(event)
|
|
event[EVALUATOR_EVENT_TYPE] = ADD_EDGE
|
|
|
|
return event
|
|
|
|
def _remove_edge(self, params):
|
|
|
|
event = copy.deepcopy(params)
|
|
ActionExecutor._add_default_properties(event)
|
|
event[EVALUATOR_EVENT_TYPE] = REMOVE_EDGE
|
|
|
|
return event
|
|
|
|
def _execute_external(self, params):
|
|
|
|
# Send a notification to the external engine
|
|
execution_engine = params[EXECUTION_ENGINE]
|
|
payload = deepcopy(params)
|
|
del payload[EXECUTION_ENGINE]
|
|
|
|
LOG.debug('Notifying external engine %s. Properties: %s',
|
|
execution_engine,
|
|
payload)
|
|
self.notifier.notify(execution_engine, payload)
|
|
|
|
@staticmethod
|
|
def _add_default_properties(event):
|
|
|
|
event[DSProps.DATASOURCE_ACTION] = AType.UPDATE
|
|
event[DSProps.ENTITY_TYPE] = VITRAGE_DATASOURCE
|
|
event[VProps.UPDATE_TIMESTAMP] = str(datetime_utils.utcnow(False))
|
|
event[VProps.VITRAGE_SAMPLE_TIMESTAMP] = str(datetime_utils.utcnow())
|
|
|
|
@staticmethod
|
|
def _register_action_recipes():
|
|
|
|
# noinspection PyDictCreation
|
|
recipes = {}
|
|
|
|
recipes[ActionType.SET_STATE] = importutils.import_object(
|
|
"%s.%s" % (SetState.__module__, SetState.__name__))
|
|
|
|
recipes[ActionType.RAISE_ALARM] = importutils.import_object(
|
|
"%s.%s" % (RaiseAlarm.__module__, RaiseAlarm.__name__))
|
|
|
|
recipes[ActionType.ADD_CAUSAL_RELATIONSHIP] = \
|
|
importutils.import_object(
|
|
"%s.%s" % (AddCausalRelationship.__module__,
|
|
AddCausalRelationship.__name__))
|
|
|
|
recipes[ActionType.MARK_DOWN] = importutils.import_object(
|
|
"%s.%s" % (MarkDown.__module__, MarkDown.__name__))
|
|
|
|
recipes[ActionType.EXECUTE_MISTRAL] = importutils.import_object(
|
|
"%s.%s" % (ExecuteMistral.__module__, ExecuteMistral.__name__))
|
|
|
|
return recipes
|
|
|
|
@staticmethod
|
|
def _action_str(action):
|
|
s = action.specs.targets.get(SOURCE, {}).get(VProps.VITRAGE_ID, '')
|
|
t = action.specs.targets.get(TARGET, {}).get(VProps.VITRAGE_ID, '')
|
|
return '%s %s \'%s\' targets (%s,%s)' % (action.mode.upper(),
|
|
action.specs.type,
|
|
action.action_id, s, t)
|