Enable strategy parameters

Strategy provides parameters to customize algorithm behavior. End user
could query then specify parameters for their requirements.

Change-Id: Id097db5f6e79c94b57674c8e5d55b06098abf18c
Implements-bp: optimization-threshold
This commit is contained in:
Edwin Zhai
2016-03-17 01:50:39 +00:00
parent ec64203bee
commit 0b29a8394b
16 changed files with 209 additions and 13 deletions

View File

@@ -16,6 +16,7 @@
from oslo_log import log
from watcher.common import clients
from watcher.common import utils
from watcher.decision_engine.strategy.context import base
from watcher.decision_engine.strategy.selection import default
@@ -58,4 +59,14 @@ class DefaultStrategyContext(base.BaseStrategyContext):
selected_strategy = strategy_selector.select()
schema = selected_strategy.get_schema()
if not audit.parameters and schema:
# Default value feedback if no predefined strategy
utils.DefaultValidatingDraft4Validator(schema).validate(
audit.parameters)
selected_strategy.input_parameters.update({
name: value for name, value in audit.parameters.items()
})
return selected_strategy.execute()

View File

@@ -41,6 +41,7 @@ import six
from watcher.common import clients
from watcher.common.loader import loadable
from watcher.common import utils
from watcher.decision_engine.loading import default as loading
from watcher.decision_engine.solution import default
from watcher.decision_engine.strategy.common import level
@@ -76,6 +77,7 @@ class BaseStrategy(loadable.Loadable):
self._collector_manager = None
self._model = None
self._goal = None
self._input_parameters = utils.Struct()
@classmethod
@abc.abstractmethod
@@ -176,6 +178,23 @@ class BaseStrategy(loadable.Loadable):
return self._model
@classmethod
def get_schema(cls):
"""Defines a Schema that the input parameters shall comply to
:return: A jsonschema format (mandatory default setting)
:rtype: dict
"""
return {}
@property
def input_parameters(self):
return self._input_parameters
@input_parameters.setter
def input_parameters(self, p):
self._input_parameters = p
@property
def osc(self):
if not self._osc:

View File

@@ -54,7 +54,10 @@ class DummyStrategy(base.DummyBaseStrategy):
raise exception.ClusterStateNotDefined()
def do_execute(self):
LOG.debug("Executing Dummy strategy")
para1 = self.input_parameters.para1
para2 = self.input_parameters.para2
LOG.debug("Executing Dummy strategy with para1=%(p1)f, para2=%(p2)s",
{'p1': para1, 'p2': para2})
parameters = {'message': 'hello World'}
self.solution.add_action(action_type=self.NOP,
input_parameters=parameters)
@@ -80,3 +83,23 @@ class DummyStrategy(base.DummyBaseStrategy):
@classmethod
def get_translatable_display_name(cls):
return "Dummy strategy"
@classmethod
def get_schema(cls):
# Mandatory default setting for each element
return {
"properties": {
"para1": {
"description": "number parameter example",
"type": "number",
"default": 3.2,
"minimum": 1.0,
"maximum": 10.2,
},
"para2": {
"description": "string parameter example",
"type": "string",
"default": "hello"
},
},
}

View File

@@ -73,8 +73,6 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
# The meter to report outlet temperature in ceilometer
METER_NAME = "hardware.ipmi.node.outlet_temperature"
# Unit: degree C
THRESHOLD = 35.0
MIGRATION = "migrate"
@@ -87,10 +85,6 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
:type osc: :py:class:`~.OpenStackClients` instance, optional
"""
super(OutletTempControl, self).__init__(config, osc)
# the migration plan will be triggered when the outlet temperature
# reaches threshold
# TODO(zhenzanz): Threshold should be configurable for each audit
self.threshold = self.THRESHOLD
self._meter = self.METER_NAME
self._ceilometer = None
@@ -106,6 +100,19 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
def get_translatable_display_name(cls):
return "Outlet temperature based strategy"
@classmethod
def get_schema(cls):
# Mandatory default setting for each element
return {
"properties": {
"threshold": {
"description": "temperature threshold for migration",
"type": "number",
"default": 35.0
},
},
}
@property
def ceilometer(self):
if self._ceilometer is None:
@@ -224,6 +231,11 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
raise wexc.ClusterStateNotDefined()
def do_execute(self):
# the migration plan will be triggered when the outlet temperature
# reaches threshold
self.threshold = self.input_parameters.threshold
LOG.debug("Initializing Outlet temperature strategy with threshold=%d",
self.threshold)
hosts_need_release, hosts_target = self.group_hosts_by_outlet_temp()
if len(hosts_need_release) == 0:

View File

@@ -28,7 +28,8 @@ LOG = log.getLogger(__name__)
GoalMapping = collections.namedtuple(
'GoalMapping', ['name', 'display_name', 'efficacy_specification'])
StrategyMapping = collections.namedtuple(
'StrategyMapping', ['name', 'goal_name', 'display_name'])
'StrategyMapping',
['name', 'goal_name', 'display_name', 'parameters_spec'])
IndicatorSpec = collections.namedtuple(
'IndicatorSpec', ['name', 'description', 'unit', 'schema'])
@@ -90,7 +91,8 @@ class Syncer(object):
self._available_strategies_map = {
StrategyMapping(
name=s.name, goal_name=goals_map[s.goal_id],
display_name=s.display_name): s
display_name=s.display_name,
parameters_spec=str(s.parameters_spec)): s
for s in self.available_strategies
}
return self._available_strategies_map
@@ -148,6 +150,7 @@ class Syncer(object):
strategy_name = strategy_map.name
strategy_display_name = strategy_map.display_name
goal_name = strategy_map.goal_name
parameters_spec = strategy_map.parameters_spec
strategy_mapping = dict()
# Strategies that are matching by name with the given
@@ -162,6 +165,7 @@ class Syncer(object):
strategy.name = strategy_name
strategy.display_name = strategy_display_name
strategy.goal_id = objects.Goal.get_by_name(self.ctx, goal_name).id
strategy.parameters_spec = parameters_spec
strategy.create()
LOG.info(_LI("Strategy %s created"), strategy_name)
@@ -284,7 +288,8 @@ class Syncer(object):
strategies_map[strategy_cls.get_name()] = StrategyMapping(
name=strategy_cls.get_name(),
goal_name=strategy_cls.get_goal_name(),
display_name=strategy_cls.get_translatable_display_name())
display_name=strategy_cls.get_translatable_display_name(),
parameters_spec=str(strategy_cls.get_schema()))
return discovered_map