Added efficacy indicators to /action_plans

I this changeset, I added the efficacy indicators both at the DB
and at the API level alongside the associated logic.

Partially Implements: blueprint efficacy-indicator

Change-Id: I824553637621da67966103c1b0c01348b09bd836
This commit is contained in:
Vincent Françoise
2016-05-20 16:16:33 +02:00
parent 2b95a4cbc4
commit 442512cd71
23 changed files with 380 additions and 103 deletions

View File

@@ -37,59 +37,62 @@ applied.
Two approaches to dealing with this can be envisaged:
- **fully automated mode**: only the :ref:`Solution <solution_definition>`
with the highest ranking (i.e., the highest
:ref:`Optimization Efficiency <efficiency_definition>`)
will be sent to the :ref:`Watcher Planner <watcher_planner_definition>` and
translated into concrete :ref:`Actions <action_definition>`.
- **manual mode**: several :ref:`Solutions <solution_definition>` are proposed
to the :ref:`Administrator <administrator_definition>` with a detailed
measurement of the estimated
:ref:`Optimization Efficiency <efficiency_definition>` and he/she decides
which one will be launched.
- **fully automated mode**: only the :ref:`Solution <solution_definition>`
with the highest ranking (i.e., the highest
:ref:`Optimization Efficacy <efficacy_definition>`) will be sent to the
:ref:`Watcher Planner <watcher_planner_definition>` and translated into
concrete :ref:`Actions <action_definition>`.
- **manual mode**: several :ref:`Solutions <solution_definition>` are proposed
to the :ref:`Administrator <administrator_definition>` with a detailed
measurement of the estimated :ref:`Optimization Efficacy
<efficacy_definition>` and he/she decides which one will be launched.
"""
import abc
import six
from watcher.decision_engine.solution import efficacy
@six.add_metaclass(abc.ABCMeta)
class BaseSolution(object):
def __init__(self):
self._origin = None
self._model = None
self._efficacy = 0
def __init__(self, goal, strategy):
"""Base Solution constructor
:param goal: Goal associated to this solution
:type goal: :py:class:`~.base.Goal` instance
:param strategy: Strategy associated to this solution
:type strategy: :py:class:`~.BaseStrategy` instance
"""
self.goal = goal
self.strategy = strategy
self.origin = None
self.model = None
self.efficacy = efficacy.Efficacy(self.goal, self.strategy)
@property
def efficacy(self):
return self._efficacy
@efficacy.setter
def efficacy(self, e):
self._efficacy = e
def global_efficacy(self):
return self.efficacy.global_efficacy
@property
def model(self):
return self._model
def efficacy_indicators(self):
return self.efficacy.indicators
@model.setter
def model(self, m):
self._model = m
def compute_global_efficacy(self):
"""Compute the global efficacy given a map of efficacy indicators"""
self.efficacy.compute_global_efficacy()
@property
def origin(self):
return self._origin
def set_efficacy_indicators(self, **indicators_map):
"""Set the efficacy indicators mapping (no validation)
@origin.setter
def origin(self, m):
self._origin = m
:param indicators_map: mapping between the indicator name and its value
:type indicators_map: dict {`str`: `object`}
"""
self.efficacy.set_efficacy_indicators(**indicators_map)
@abc.abstractmethod
def add_action(self,
action_type,
resource_id,
input_parameters=None):
"""Add a new Action in the Action Plan
def add_action(self, action_type, resource_id, input_parameters=None):
"""Add a new Action in the Solution
:param action_type: the unique id of an action type defined in
entry point 'watcher_actions'

View File

@@ -22,19 +22,21 @@ from watcher.decision_engine.solution import base
class DefaultSolution(base.BaseSolution):
def __init__(self):
def __init__(self, goal, strategy):
"""Stores a set of actions generated by a strategy
The DefaultSolution class store a set of actions generated by a
strategy in order to achieve the goal.
:param goal: Goal associated to this solution
:type goal: :py:class:`~.base.Goal` instance
:param strategy: Strategy associated to this solution
:type strategy: :py:class:`~.BaseStrategy` instance
"""
super(DefaultSolution, self).__init__()
super(DefaultSolution, self).__init__(goal, strategy)
self._actions = []
def add_action(self, action_type,
input_parameters=None,
resource_id=None):
def add_action(self, action_type, input_parameters=None, resource_id=None):
if input_parameters is not None:
if baction.BaseAction.RESOURCE_ID in input_parameters.keys():
raise exception.ReservedWord(name=baction.BaseAction.

View File

@@ -14,8 +14,20 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import numbers
from oslo_log import log as logging
from watcher._i18n import _
from watcher.common import exception
from watcher.common import utils
LOG = logging.getLogger(__name__)
class IndicatorsMap(utils.Struct):
pass
class Indicator(utils.Struct):
@@ -24,4 +36,70 @@ class Indicator(utils.Struct):
self.name = name
self.description = description
self.unit = unit
if not isinstance(value, numbers.Number):
raise exception.InvalidIndicatorValue(
_("An indicator value should be a number"))
self.value = value
class Efficacy(object):
"""Solution efficacy"""
def __init__(self, goal, strategy):
"""Solution efficacy
:param goal: Goal associated to this solution
:type goal: :py:class:`~.base.Goal` instance
:param strategy: Strategy associated to this solution
:type strategy: :py:class:`~.BaseStrategy` instance
"""
self.goal = goal
self.strategy = strategy
self._efficacy_spec = self.goal.efficacy_specification
# Used to store in DB the info related to the efficacy indicators
self.indicators = []
# Used to compute the global efficacy
self._indicators_mapping = IndicatorsMap()
self.global_efficacy = None
def set_efficacy_indicators(self, **indicators_map):
"""Set the efficacy indicators
:param indicators_map: kwargs where the key is the name of the efficacy
indicator as defined in the associated
:py:class:`~.IndicatorSpecification` and the
value is a number.
:type indicators_map: dict {str: numerical value}
"""
self._indicators_mapping.update(indicators_map)
def compute_global_efficacy(self):
self._efficacy_spec.validate_efficacy_indicators(
self._indicators_mapping)
try:
self.global_efficacy = (
self._efficacy_spec.get_global_efficacy_indicator(
self._indicators_mapping))
indicators_specs_map = {
indicator_spec.name: indicator_spec
for indicator_spec in self._efficacy_spec.indicators_specs}
indicators = []
for indicator_name, value in self._indicators_mapping.items():
related_indicator_spec = indicators_specs_map[indicator_name]
indicators.append(
Indicator(
name=related_indicator_spec.name,
description=related_indicator_spec.description,
unit=related_indicator_spec.unit,
value=value))
self.indicators = indicators
except Exception as exc:
LOG.exception(exc)
raise exception.GlobalEfficacyComputationError(
goal=self.goal.name,
strategy=self.strategy.name)