Merge "Added strategy ID + Action Plan syncing"
This commit is contained in:
@@ -74,8 +74,8 @@ class ContinuousAuditHandler(base.AuditHandler):
|
||||
|
||||
def do_execute(self, audit, request_context):
|
||||
# execute the strategy
|
||||
solution = self.strategy_context.execute_strategy(audit.uuid,
|
||||
request_context)
|
||||
solution = self.strategy_context.execute_strategy(
|
||||
audit, request_context)
|
||||
|
||||
if audit.audit_type == audit_objects.AuditType.CONTINUOUS.value:
|
||||
a_plan_filters = {'audit_uuid': audit.uuid,
|
||||
|
||||
@@ -20,7 +20,7 @@ from watcher.decision_engine.audit import base
|
||||
class OneShotAuditHandler(base.AuditHandler):
|
||||
def do_execute(self, audit, request_context):
|
||||
# execute the strategy
|
||||
solution = self.strategy_context.execute_strategy(audit.uuid,
|
||||
request_context)
|
||||
solution = self.strategy_context.execute_strategy(
|
||||
audit, request_context)
|
||||
|
||||
return solution
|
||||
|
||||
@@ -48,10 +48,11 @@ class DefaultPlanner(base.BasePlanner):
|
||||
|
||||
@classmethod
|
||||
def get_config_opts(cls):
|
||||
return [cfg.DictOpt(
|
||||
'weights',
|
||||
help="These weights are used to schedule the actions",
|
||||
default=cls.weights_dict),
|
||||
return [
|
||||
cfg.DictOpt(
|
||||
'weights',
|
||||
help="These weights are used to schedule the actions",
|
||||
default=cls.weights_dict),
|
||||
]
|
||||
|
||||
def create_action(self,
|
||||
@@ -113,9 +114,13 @@ class DefaultPlanner(base.BasePlanner):
|
||||
return action_plan
|
||||
|
||||
def _create_action_plan(self, context, audit_id, solution):
|
||||
strategy = objects.Strategy.get_by_name(
|
||||
context, solution.strategy.name)
|
||||
|
||||
action_plan_dict = {
|
||||
'uuid': utils.generate_uuid(),
|
||||
'audit_id': audit_id,
|
||||
'strategy_id': strategy.id,
|
||||
'first_action_id': None,
|
||||
'state': objects.action_plan.State.RECOMMENDED,
|
||||
'global_efficacy': solution.global_efficacy,
|
||||
|
||||
@@ -22,6 +22,16 @@ import six
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class BaseStrategyContext(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def execute_strategy(self, audit_uuid, request_context):
|
||||
def execute_strategy(self, audit, request_context):
|
||||
"""Execute the strategy for the given an audit
|
||||
|
||||
:param audit: Audit object
|
||||
:type audit: :py:class:`~.objects.audit.Audit` instance
|
||||
:param request_context: Current request context
|
||||
:type request_context: :py:class:`~.RequestContext` instance
|
||||
:returns: The computed solution
|
||||
:rtype: :py:class:`~.BaseSolution` instance
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@@ -30,9 +30,7 @@ class DefaultStrategyContext(base.BaseStrategyContext):
|
||||
super(DefaultStrategyContext, self).__init__()
|
||||
LOG.debug("Initializing Strategy Context")
|
||||
|
||||
def execute_strategy(self, audit_uuid, request_context):
|
||||
audit = objects.Audit.get_by_uuid(request_context, audit_uuid)
|
||||
|
||||
def execute_strategy(self, audit, request_context):
|
||||
osc = clients.OpenStackClients()
|
||||
# todo(jed) retrieve in audit parameters (threshold,...)
|
||||
# todo(jed) create ActionPlan
|
||||
|
||||
@@ -22,6 +22,8 @@ from watcher._i18n import _LI, _LW
|
||||
from watcher.common import context
|
||||
from watcher.decision_engine.loading import default
|
||||
from watcher import objects
|
||||
from watcher.objects import action_plan as apobjects
|
||||
from watcher.objects import audit as auditobjects
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
@@ -54,6 +56,8 @@ class Syncer(object):
|
||||
self.strategy_mapping = dict()
|
||||
|
||||
self.stale_audit_templates_map = {}
|
||||
self.stale_audits_map = {}
|
||||
self.stale_action_plans_map = {}
|
||||
|
||||
@property
|
||||
def available_goals(self):
|
||||
@@ -118,7 +122,7 @@ class Syncer(object):
|
||||
|
||||
self.strategy_mapping.update(self._sync_strategy(strategy_map))
|
||||
|
||||
self._sync_audit_templates()
|
||||
self._sync_objects()
|
||||
|
||||
def _sync_goal(self, goal_map):
|
||||
goal_name = goal_map.name
|
||||
@@ -177,25 +181,45 @@ class Syncer(object):
|
||||
|
||||
return strategy_mapping
|
||||
|
||||
def _sync_audit_templates(self):
|
||||
# First we find audit templates that are stale because their associated
|
||||
# goal or strategy has been modified and we update them in-memory
|
||||
def _sync_objects(self):
|
||||
# First we find audit templates, audits and action plans that are stale
|
||||
# because their associated goal or strategy has been modified and we
|
||||
# update them in-memory
|
||||
self._find_stale_audit_templates_due_to_goal()
|
||||
self._find_stale_audit_templates_due_to_strategy()
|
||||
|
||||
# Then we handle the case where an audit template became
|
||||
# stale because its related goal does not exist anymore.
|
||||
self._find_stale_audits_due_to_goal()
|
||||
self._find_stale_audits_due_to_strategy()
|
||||
|
||||
self._find_stale_action_plans_due_to_strategy()
|
||||
self._find_stale_action_plans_due_to_audit()
|
||||
|
||||
# Then we handle the case where an audit template, an audit or an
|
||||
# action plan becomes stale because its related goal does not
|
||||
# exist anymore.
|
||||
self._soft_delete_removed_goals()
|
||||
# Then we handle the case where an audit template became
|
||||
# stale because its related strategy does not exist anymore.
|
||||
# Then we handle the case where an audit template, an audit or an
|
||||
# action plan becomes stale because its related strategy does not
|
||||
# exist anymore.
|
||||
self._soft_delete_removed_strategies()
|
||||
|
||||
# Finally, we save into the DB the updated stale audit templates
|
||||
# and soft delete stale audits and action plans
|
||||
for stale_audit_template in self.stale_audit_templates_map.values():
|
||||
stale_audit_template.save()
|
||||
LOG.info(_LI("Audit Template '%s' synced"),
|
||||
stale_audit_template.name)
|
||||
|
||||
for stale_audit in self.stale_audits_map.values():
|
||||
stale_audit.save()
|
||||
LOG.info(_LI("Stale audit '%s' synced and cancelled"),
|
||||
stale_audit.uuid)
|
||||
|
||||
for stale_action_plan in self.stale_action_plans_map.values():
|
||||
stale_action_plan.save()
|
||||
LOG.info(_LI("Stale action plan '%s' synced and cancelled"),
|
||||
stale_action_plan.uuid)
|
||||
|
||||
def _find_stale_audit_templates_due_to_goal(self):
|
||||
for goal_id, synced_goal in self.goal_mapping.items():
|
||||
filters = {"goal_id": goal_id}
|
||||
@@ -228,6 +252,72 @@ class Syncer(object):
|
||||
self.stale_audit_templates_map[
|
||||
audit_template.id].strategy_id = synced_strategy.id
|
||||
|
||||
def _find_stale_audits_due_to_goal(self):
|
||||
for goal_id, synced_goal in self.goal_mapping.items():
|
||||
filters = {"goal_id": goal_id}
|
||||
stale_audits = objects.Audit.list(
|
||||
self.ctx, filters=filters)
|
||||
|
||||
# Update the goal ID for the stale audits (w/o saving)
|
||||
for audit in stale_audits:
|
||||
if audit.id not in self.stale_audits_map:
|
||||
audit.goal_id = synced_goal.id
|
||||
self.stale_audits_map[audit.id] = audit
|
||||
else:
|
||||
self.stale_audits_map[audit.id].goal_id = synced_goal.id
|
||||
|
||||
def _find_stale_audits_due_to_strategy(self):
|
||||
for strategy_id, synced_strategy in self.strategy_mapping.items():
|
||||
filters = {"strategy_id": strategy_id}
|
||||
stale_audits = objects.Audit.list(self.ctx, filters=filters)
|
||||
# Update strategy IDs for all stale audits (w/o saving)
|
||||
for audit in stale_audits:
|
||||
if audit.id not in self.stale_audits_map:
|
||||
audit.strategy_id = synced_strategy.id
|
||||
audit.state = auditobjects.State.CANCELLED
|
||||
self.stale_audits_map[audit.id] = audit
|
||||
else:
|
||||
self.stale_audits_map[
|
||||
audit.id].strategy_id = synced_strategy.id
|
||||
self.stale_audits_map[
|
||||
audit.id].state = auditobjects.State.CANCELLED
|
||||
|
||||
def _find_stale_action_plans_due_to_strategy(self):
|
||||
for strategy_id, synced_strategy in self.strategy_mapping.items():
|
||||
filters = {"strategy_id": strategy_id}
|
||||
stale_action_plans = objects.ActionPlan.list(
|
||||
self.ctx, filters=filters)
|
||||
|
||||
# Update strategy IDs for all stale action plans (w/o saving)
|
||||
for action_plan in stale_action_plans:
|
||||
if action_plan.id not in self.stale_action_plans_map:
|
||||
action_plan.strategy_id = synced_strategy.id
|
||||
action_plan.state = apobjects.State.CANCELLED
|
||||
self.stale_action_plans_map[action_plan.id] = action_plan
|
||||
else:
|
||||
self.stale_action_plans_map[
|
||||
action_plan.id].strategy_id = synced_strategy.id
|
||||
self.stale_action_plans_map[
|
||||
action_plan.id].state = apobjects.State.CANCELLED
|
||||
|
||||
def _find_stale_action_plans_due_to_audit(self):
|
||||
for audit_id, synced_audit in self.stale_audits_map.items():
|
||||
filters = {"audit_id": audit_id}
|
||||
stale_action_plans = objects.ActionPlan.list(
|
||||
self.ctx, filters=filters)
|
||||
|
||||
# Update audit IDs for all stale action plans (w/o saving)
|
||||
for action_plan in stale_action_plans:
|
||||
if action_plan.id not in self.stale_action_plans_map:
|
||||
action_plan.audit_id = synced_audit.id
|
||||
action_plan.state = apobjects.State.CANCELLED
|
||||
self.stale_action_plans_map[action_plan.id] = action_plan
|
||||
else:
|
||||
self.stale_action_plans_map[
|
||||
action_plan.id].audit_id = synced_audit.id
|
||||
self.stale_action_plans_map[
|
||||
action_plan.id].state = apobjects.State.CANCELLED
|
||||
|
||||
def _soft_delete_removed_goals(self):
|
||||
removed_goals = [
|
||||
g for g in self.available_goals
|
||||
@@ -235,12 +325,24 @@ class Syncer(object):
|
||||
for removed_goal in removed_goals:
|
||||
removed_goal.soft_delete()
|
||||
filters = {"goal_id": removed_goal.id}
|
||||
|
||||
invalid_ats = objects.AuditTemplate.list(self.ctx, filters=filters)
|
||||
for at in invalid_ats:
|
||||
LOG.warning(
|
||||
_LW("Audit Template '%(audit_template)s' references a "
|
||||
"goal that does not exist"),
|
||||
audit_template=at.uuid)
|
||||
"goal that does not exist"), audit_template=at.uuid)
|
||||
|
||||
stale_audits = objects.Audit.list(self.ctx, filters=filters)
|
||||
for audit in stale_audits:
|
||||
LOG.warning(
|
||||
_LW("Audit '%(audit)s' references a "
|
||||
"goal that does not exist"), audit=audit.uuid)
|
||||
if audit.id not in self.stale_audits_map:
|
||||
audit.state = auditobjects.State.CANCELLED
|
||||
self.stale_audits_map[audit.id] = audit
|
||||
else:
|
||||
self.stale_audits_map[
|
||||
audit.id].state = auditobjects.State.CANCELLED
|
||||
|
||||
def _soft_delete_removed_strategies(self):
|
||||
removed_strategies = [
|
||||
@@ -265,6 +367,32 @@ class Syncer(object):
|
||||
else:
|
||||
self.stale_audit_templates_map[at.id].strategy_id = None
|
||||
|
||||
stale_audits = objects.Audit.list(self.ctx, filters=filters)
|
||||
for audit in stale_audits:
|
||||
LOG.warning(
|
||||
_LW("Audit '%(audit)s' references a "
|
||||
"strategy that does not exist"), audit=audit.uuid)
|
||||
if audit.id not in self.stale_audits_map:
|
||||
audit.state = auditobjects.State.CANCELLED
|
||||
self.stale_audits_map[audit.id] = audit
|
||||
else:
|
||||
self.stale_audits_map[
|
||||
audit.id].state = auditobjects.State.CANCELLED
|
||||
|
||||
stale_action_plans = objects.ActionPlan.list(
|
||||
self.ctx, filters=filters)
|
||||
for action_plan in stale_action_plans:
|
||||
LOG.warning(
|
||||
_LW("Action Plan '%(action_plan)s' references a "
|
||||
"strategy that does not exist"),
|
||||
action_plan=action_plan.uuid)
|
||||
if action_plan.id not in self.stale_action_plans_map:
|
||||
action_plan.state = apobjects.State.CANCELLED
|
||||
self.stale_action_plans_map[action_plan.id] = action_plan
|
||||
else:
|
||||
self.stale_action_plans_map[
|
||||
action_plan.id].state = apobjects.State.CANCELLED
|
||||
|
||||
def _discover(self):
|
||||
strategies_map = {}
|
||||
goals_map = {}
|
||||
|
||||
Reference in New Issue
Block a user