stale the action plan
Check the creation time of the actionplan, and set the state to SUPERSEDED if it has expired. Change-Id: I900e8dc5011dec4cffd58913b9c5083a6131d70d Implements: blueprint stale-action-plan
This commit is contained in:
parent
03a2c0142a
commit
38e4b48d70
@ -1,4 +1,4 @@
|
|||||||
---
|
---
|
||||||
features:
|
features:
|
||||||
- Add superseded state for an action plan if the cluster data model has
|
- Check the creation time of the action plan,
|
||||||
changed after it has been created.
|
and set its state to SUPERSEDED if it has expired.
|
||||||
|
@ -42,6 +42,15 @@ WATCHER_DECISION_ENGINE_OPTS = [
|
|||||||
required=True,
|
required=True,
|
||||||
help='The maximum number of threads that can be used to '
|
help='The maximum number of threads that can be used to '
|
||||||
'execute strategies'),
|
'execute strategies'),
|
||||||
|
cfg.IntOpt('action_plan_expiry',
|
||||||
|
default=24,
|
||||||
|
help='An expiry timespan(hours). Watcher invalidates any '
|
||||||
|
'action plan for which its creation time '
|
||||||
|
'-whose number of hours has been offset by this value-'
|
||||||
|
' is older that the current time.'),
|
||||||
|
cfg.IntOpt('check_periodic_interval',
|
||||||
|
default=30*60,
|
||||||
|
help='Interval (in seconds) for checking action plan expiry.')
|
||||||
]
|
]
|
||||||
|
|
||||||
WATCHER_CONTINUOUS_OPTS = [
|
WATCHER_CONTINUOUS_OPTS = [
|
||||||
|
@ -19,12 +19,17 @@ import datetime
|
|||||||
import eventlet
|
import eventlet
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
|
from watcher.common import context
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common import scheduling
|
from watcher.common import scheduling
|
||||||
|
|
||||||
from watcher.decision_engine.model.collector import manager
|
from watcher.decision_engine.model.collector import manager
|
||||||
|
from watcher import objects
|
||||||
|
|
||||||
|
from watcher import conf
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
class DecisionEngineSchedulingService(scheduling.BackgroundSchedulerService):
|
class DecisionEngineSchedulingService(scheduling.BackgroundSchedulerService):
|
||||||
@ -73,9 +78,20 @@ class DecisionEngineSchedulingService(scheduling.BackgroundSchedulerService):
|
|||||||
|
|
||||||
return _sync
|
return _sync
|
||||||
|
|
||||||
|
def add_checkstate_job(self):
|
||||||
|
# 30 minutes interval
|
||||||
|
interval = CONF.watcher_decision_engine.check_periodic_interval
|
||||||
|
ap_manager = objects.action_plan.StateManager()
|
||||||
|
if CONF.watcher_decision_engine.action_plan_expiry != 0:
|
||||||
|
self.add_job(ap_manager.check_expired, 'interval',
|
||||||
|
args=[context.make_context()],
|
||||||
|
seconds=interval,
|
||||||
|
next_run_time=datetime.datetime.now())
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start service."""
|
"""Start service."""
|
||||||
self.add_sync_jobs()
|
self.add_sync_jobs()
|
||||||
|
self.add_checkstate_job()
|
||||||
super(DecisionEngineSchedulingService, self).start()
|
super(DecisionEngineSchedulingService, self).start()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
|
@ -71,15 +71,19 @@ state may be one of the following:
|
|||||||
**RECOMMENDED** state and was superseded by the
|
**RECOMMENDED** state and was superseded by the
|
||||||
:ref:`Administrator <administrator_definition>`
|
:ref:`Administrator <administrator_definition>`
|
||||||
"""
|
"""
|
||||||
|
import datetime
|
||||||
|
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.common import utils
|
from watcher.common import utils
|
||||||
|
from watcher import conf
|
||||||
from watcher.db import api as db_api
|
from watcher.db import api as db_api
|
||||||
from watcher import notifications
|
from watcher import notifications
|
||||||
from watcher import objects
|
from watcher import objects
|
||||||
from watcher.objects import base
|
from watcher.objects import base
|
||||||
from watcher.objects import fields as wfields
|
from watcher.objects import fields as wfields
|
||||||
|
|
||||||
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
class State(object):
|
class State(object):
|
||||||
RECOMMENDED = 'RECOMMENDED'
|
RECOMMENDED = 'RECOMMENDED'
|
||||||
@ -317,3 +321,18 @@ class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
|
|||||||
notifications.action_plan.send_delete(self._context, self)
|
notifications.action_plan.send_delete(self._context, self)
|
||||||
|
|
||||||
_notify()
|
_notify()
|
||||||
|
|
||||||
|
|
||||||
|
class StateManager(object):
|
||||||
|
def check_expired(self, context):
|
||||||
|
action_plan_expiry = (
|
||||||
|
CONF.watcher_decision_engine.action_plan_expiry)
|
||||||
|
date_created = datetime.datetime.utcnow() - datetime.timedelta(
|
||||||
|
hours=action_plan_expiry)
|
||||||
|
filters = {'state__eq': State.RECOMMENDED,
|
||||||
|
'created_at__lt': date_created}
|
||||||
|
action_plans = objects.ActionPlan.list(
|
||||||
|
context, filters=filters, eager=True)
|
||||||
|
for action_plan in action_plans:
|
||||||
|
action_plan.state = State.SUPERSEDED
|
||||||
|
action_plan.save()
|
||||||
|
@ -48,7 +48,7 @@ class TestDecisionEngineSchedulingService(base.TestCase):
|
|||||||
|
|
||||||
m_start.assert_called_once_with(scheduler)
|
m_start.assert_called_once_with(scheduler)
|
||||||
jobs = scheduler.get_jobs()
|
jobs = scheduler.get_jobs()
|
||||||
self.assertEqual(1, len(jobs))
|
self.assertEqual(2, len(jobs))
|
||||||
|
|
||||||
job = jobs[0]
|
job = jobs[0]
|
||||||
self.assertTrue(bool(fake_collector.cluster_data_model))
|
self.assertTrue(bool(fake_collector.cluster_data_model))
|
||||||
@ -77,7 +77,7 @@ class TestDecisionEngineSchedulingService(base.TestCase):
|
|||||||
|
|
||||||
m_start.assert_called_once_with(scheduler)
|
m_start.assert_called_once_with(scheduler)
|
||||||
jobs = scheduler.get_jobs()
|
jobs = scheduler.get_jobs()
|
||||||
self.assertEqual(1, len(jobs))
|
self.assertEqual(2, len(jobs))
|
||||||
|
|
||||||
job = jobs[0]
|
job = jobs[0]
|
||||||
job.func()
|
job.func()
|
||||||
|
@ -19,12 +19,16 @@ import iso8601
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
|
from watcher.common import utils as common_utils
|
||||||
|
from watcher import conf
|
||||||
from watcher.db.sqlalchemy import api as db_api
|
from watcher.db.sqlalchemy import api as db_api
|
||||||
from watcher import notifications
|
from watcher import notifications
|
||||||
from watcher import objects
|
from watcher import objects
|
||||||
from watcher.tests.db import base
|
from watcher.tests.db import base
|
||||||
from watcher.tests.db import utils
|
from watcher.tests.db import utils
|
||||||
|
|
||||||
|
CONF = conf.CONF
|
||||||
|
|
||||||
|
|
||||||
class TestActionPlanObject(base.DbTestCase):
|
class TestActionPlanObject(base.DbTestCase):
|
||||||
|
|
||||||
@ -290,3 +294,31 @@ class TestCreateDeleteActionPlanObject(base.DbTestCase):
|
|||||||
m_destroy_efficacy_indicator.assert_called_once_with(
|
m_destroy_efficacy_indicator.assert_called_once_with(
|
||||||
efficacy_indicator['uuid'])
|
efficacy_indicator['uuid'])
|
||||||
self.assertEqual(self.context, action_plan._context)
|
self.assertEqual(self.context, action_plan._context)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.object(notifications.action_plan, 'send_update', mock.Mock())
|
||||||
|
class TestStateManager(base.DbTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestStateManager, self).setUp()
|
||||||
|
self.state_manager = objects.action_plan.StateManager()
|
||||||
|
|
||||||
|
def test_check_expired(self):
|
||||||
|
CONF.set_default('action_plan_expiry', 0,
|
||||||
|
group='watcher_decision_engine')
|
||||||
|
strategy_1 = utils.create_test_strategy(
|
||||||
|
uuid=common_utils.generate_uuid())
|
||||||
|
audit_1 = utils.create_test_audit(
|
||||||
|
uuid=common_utils.generate_uuid())
|
||||||
|
action_plan_1 = utils.create_test_action_plan(
|
||||||
|
state=objects.action_plan.State.RECOMMENDED,
|
||||||
|
uuid=common_utils.generate_uuid(),
|
||||||
|
audit_id=audit_1.id,
|
||||||
|
strategy_id=strategy_1.id)
|
||||||
|
|
||||||
|
self.state_manager.check_expired(self.context)
|
||||||
|
|
||||||
|
action_plan = objects.action_plan.ActionPlan.get_by_uuid(
|
||||||
|
self.context, action_plan_1.uuid)
|
||||||
|
self.assertEqual(objects.action_plan.State.SUPERSEDED,
|
||||||
|
action_plan.state)
|
||||||
|
Loading…
Reference in New Issue
Block a user