Merge "Watcher Planner Selector"

This commit is contained in:
Zuul 2019-09-17 07:42:44 +00:00 committed by Gerrit Code Review
commit 62020cac30
7 changed files with 47 additions and 27 deletions

View File

@ -26,7 +26,7 @@ from oslo_log import log
from watcher.applier import rpcapi from watcher.applier import rpcapi
from watcher.common import exception from watcher.common import exception
from watcher.common import service from watcher.common import service
from watcher.decision_engine.planner import manager as planner_manager from watcher.decision_engine.loading import default as loader
from watcher.decision_engine.strategy.context import default as default_context from watcher.decision_engine.strategy.context import default as default_context
from watcher import notifications from watcher import notifications
from watcher import objects from watcher import objects
@ -41,11 +41,11 @@ LOG = log.getLogger(__name__)
class BaseAuditHandler(object): class BaseAuditHandler(object):
@abc.abstractmethod @abc.abstractmethod
def execute(self, audit_uuid, request_context): def execute(self, audit, request_context):
raise NotImplementedError() raise NotImplementedError()
@abc.abstractmethod @abc.abstractmethod
def pre_execute(self, audit_uuid, request_context): def pre_execute(self, audit, request_context):
raise NotImplementedError() raise NotImplementedError()
@abc.abstractmethod @abc.abstractmethod
@ -63,15 +63,18 @@ class AuditHandler(BaseAuditHandler):
def __init__(self): def __init__(self):
super(AuditHandler, self).__init__() super(AuditHandler, self).__init__()
self._strategy_context = default_context.DefaultStrategyContext() self._strategy_context = default_context.DefaultStrategyContext()
self._planner_manager = planner_manager.PlannerManager() self._planner_loader = loader.DefaultPlannerLoader()
self._planner = None
self.applier_client = rpcapi.ApplierAPI() self.applier_client = rpcapi.ApplierAPI()
@property def get_planner(self, audit, request_context):
def planner(self): # because AuditHandler is a singletone we need to avoid race condition.
if self._planner is None: # thus we need to load planner every time
self._planner = self._planner_manager.load() strategy = self.strategy_context.select_strategy(
return self._planner audit, request_context)
planner_name = strategy.planner
LOG.debug("Loading %s", planner_name)
planner = self._planner_loader.load(name=planner_name)
return planner
@property @property
def strategy_context(self): def strategy_context(self):
@ -90,8 +93,8 @@ class AuditHandler(BaseAuditHandler):
request_context, audit, request_context, audit,
action=fields.NotificationAction.PLANNER, action=fields.NotificationAction.PLANNER,
phase=fields.NotificationPhase.START) phase=fields.NotificationPhase.START)
action_plan = self.planner.schedule(request_context, audit.id, planner = self.get_planner(audit, request_context)
solution) action_plan = planner.schedule(request_context, audit.id, solution)
notifications.audit.send_action_notification( notifications.audit.send_action_notification(
request_context, audit, request_context, audit,
action=fields.NotificationAction.PLANNER, action=fields.NotificationAction.PLANNER,
@ -105,13 +108,15 @@ class AuditHandler(BaseAuditHandler):
phase=fields.NotificationPhase.ERROR) phase=fields.NotificationPhase.ERROR)
raise raise
def update_audit_state(self, audit, state): @staticmethod
def update_audit_state(audit, state):
if audit.state != state: if audit.state != state:
LOG.debug("Update audit state: %s", state) LOG.debug("Update audit state: %s", state)
audit.state = state audit.state = state
audit.save() audit.save()
def check_ongoing_action_plans(self, request_context): @staticmethod
def check_ongoing_action_plans(request_context):
a_plan_filters = {'state': objects.action_plan.State.ONGOING} a_plan_filters = {'state': objects.action_plan.State.ONGOING}
ongoing_action_plans = objects.ActionPlan.list( ongoing_action_plans = objects.ActionPlan.list(
request_context, filters=a_plan_filters) request_context, filters=a_plan_filters)

View File

@ -94,7 +94,8 @@ class ContinuousAuditHandler(base.AuditHandler):
plan.save() plan.save()
return solution return solution
def _next_cron_time(self, audit): @staticmethod
def _next_cron_time(audit):
if utils.is_cron_like(audit.interval): if utils.is_cron_like(audit.interval):
return croniter(audit.interval, datetime.datetime.utcnow() return croniter(audit.interval, datetime.datetime.utcnow()
).get_next(datetime.datetime) ).get_next(datetime.datetime)

View File

@ -19,10 +19,7 @@ from oslo_log import log
from watcher.decision_engine.loading import default as loader from watcher.decision_engine.loading import default as loader
from watcher import conf
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
CONF = conf.CONF
class PlannerManager(object): class PlannerManager(object):
@ -33,7 +30,6 @@ class PlannerManager(object):
def loader(self): def loader(self):
return self._loader return self._loader
def load(self): def load(self, planner_name):
selected_planner = CONF.watcher_planner.planner LOG.debug("Loading %s", planner_name)
LOG.debug("Loading %s", selected_planner) return self.loader.load(name=planner_name)
return self.loader.load(name=selected_planner)

View File

@ -30,7 +30,8 @@ class DefaultStrategyContext(base.StrategyContext):
super(DefaultStrategyContext, self).__init__() super(DefaultStrategyContext, self).__init__()
LOG.debug("Initializing Strategy Context") LOG.debug("Initializing Strategy Context")
def do_execute_strategy(self, audit, request_context): @staticmethod
def select_strategy(audit, request_context):
osc = clients.OpenStackClients() osc = clients.OpenStackClients()
# todo(jed) retrieve in audit parameters (threshold,...) # todo(jed) retrieve in audit parameters (threshold,...)
# todo(jed) create ActionPlan # todo(jed) create ActionPlan
@ -50,9 +51,10 @@ class DefaultStrategyContext(base.StrategyContext):
goal_name=goal.name, goal_name=goal.name,
strategy_name=strategy_name, strategy_name=strategy_name,
osc=osc) osc=osc)
return strategy_selector.select()
selected_strategy = strategy_selector.select() def do_execute_strategy(self, audit, request_context):
selected_strategy = self.select_strategy(audit, request_context)
selected_strategy.audit_scope = audit.scope selected_strategy.audit_scope = audit.scope
schema = selected_strategy.get_schema() schema = selected_strategy.get_schema()

View File

@ -161,6 +161,7 @@ class BaseStrategy(loadable.Loadable):
self._input_parameters = utils.Struct() self._input_parameters = utils.Struct()
self._audit_scope = None self._audit_scope = None
self._datasource_backend = None self._datasource_backend = None
self._planner = 'weight'
@classmethod @classmethod
@abc.abstractmethod @abc.abstractmethod
@ -432,6 +433,14 @@ class BaseStrategy(loadable.Loadable):
def state_collector(self, s): def state_collector(self, s):
self._cluster_state_collector = s self._cluster_state_collector = s
@property
def planner(self):
return self._planner
@planner.setter
def planner(self, s):
self._planner = s
def filter_instances_by_audit_tag(self, instances): def filter_instances_by_audit_tag(self, instances):
if not self.config.check_optimize_metadata: if not self.config.check_optimize_metadata:
return instances return instances
@ -512,6 +521,11 @@ class ThermalOptimizationBaseStrategy(BaseStrategy):
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class WorkloadStabilizationBaseStrategy(BaseStrategy): class WorkloadStabilizationBaseStrategy(BaseStrategy):
def __init__(self, *args, **kwargs):
super(WorkloadStabilizationBaseStrategy, self
).__init__(*args, **kwargs)
self._planner = 'workload_stabilization'
@classmethod @classmethod
def get_goal_name(cls): def get_goal_name(cls):
return "workload_balancing" return "workload_balancing"

View File

@ -439,7 +439,7 @@ class TestContinuousAuditHandler(base.DbTestCase):
audit_handler.launch_audits_periodically() audit_handler.launch_audits_periodically()
m_remove_job.assert_called() m_remove_job.assert_called()
@mock.patch.object(continuous.ContinuousAuditHandler, 'planner', @mock.patch.object(continuous.ContinuousAuditHandler, 'get_planner',
mock.Mock()) mock.Mock())
@mock.patch.object(base_strategy.BaseStrategy, "compute_model", @mock.patch.object(base_strategy.BaseStrategy, "compute_model",
mock.Mock(stale=False)) mock.Mock(stale=False))

View File

@ -25,4 +25,6 @@ class TestPlannerManager(base.TestCase):
def test_load(self): def test_load(self):
cfg.CONF.set_override('planner', "weight", group='watcher_planner') cfg.CONF.set_override('planner', "weight", group='watcher_planner')
manager = planner.PlannerManager() manager = planner.PlannerManager()
self.assertIsInstance(manager.load(), weight.WeightPlanner) selected_planner = cfg.CONF.watcher_planner.planner
self.assertIsInstance(manager.load(selected_planner),
weight.WeightPlanner)