Merge "Refactor watcher API for Action Plan Start"
This commit is contained in:
commit
5107cfa30f
|
@ -326,7 +326,8 @@ class ActionPlansController(rest.RestController):
|
|||
from the top-level resource ActionPlan."""
|
||||
|
||||
_custom_actions = {
|
||||
'detail': ['GET'],
|
||||
'start': ['POST'],
|
||||
'detail': ['GET']
|
||||
}
|
||||
|
||||
def _get_action_plans_collection(self, marker, limit,
|
||||
|
@ -535,7 +536,7 @@ class ActionPlansController(rest.RestController):
|
|||
if action_plan_to_update[field] != patch_val:
|
||||
action_plan_to_update[field] = patch_val
|
||||
|
||||
if (field == 'state'and
|
||||
if (field == 'state' and
|
||||
patch_val == objects.action_plan.State.PENDING):
|
||||
launch_action_plan = True
|
||||
|
||||
|
@ -560,3 +561,33 @@ class ActionPlansController(rest.RestController):
|
|||
pecan.request.context,
|
||||
action_plan_uuid)
|
||||
return ActionPlan.convert_with_links(action_plan_to_update)
|
||||
|
||||
@wsme_pecan.wsexpose(ActionPlan, types.uuid)
|
||||
def start(self, action_plan_uuid, **kwargs):
|
||||
"""Start an action_plan
|
||||
|
||||
:param action_plan_uuid: UUID of an action_plan.
|
||||
"""
|
||||
|
||||
action_plan_to_start = api_utils.get_resource(
|
||||
'ActionPlan', action_plan_uuid, eager=True)
|
||||
context = pecan.request.context
|
||||
|
||||
policy.enforce(context, 'action_plan:start', action_plan_to_start,
|
||||
action='action_plan:start')
|
||||
|
||||
if action_plan_to_start['state'] != \
|
||||
objects.action_plan.State.RECOMMENDED:
|
||||
raise Exception.StartError(
|
||||
state=action_plan_to_start.state)
|
||||
|
||||
action_plan_to_start['state'] = objects.action_plan.State.PENDING
|
||||
action_plan_to_start.save()
|
||||
|
||||
applier_client = rpcapi.ApplierAPI()
|
||||
applier_client.launch_action_plan(pecan.request.context,
|
||||
action_plan_uuid)
|
||||
action_plan_to_start = objects.ActionPlan.get_by_uuid(
|
||||
pecan.request.context, action_plan_uuid)
|
||||
|
||||
return ActionPlan.convert_with_links(action_plan_to_start)
|
||||
|
|
|
@ -336,6 +336,10 @@ class DeleteError(Invalid):
|
|||
msg_fmt = _("Couldn't delete when state is '%(state)s'.")
|
||||
|
||||
|
||||
class StartError(Invalid):
|
||||
msg_fmt = _("Couldn't start when state is '%(state)s'.")
|
||||
|
||||
|
||||
# decision engine
|
||||
|
||||
class WorkflowExecutionException(WatcherException):
|
||||
|
|
|
@ -71,6 +71,17 @@ rules = [
|
|||
'method': 'PATCH'
|
||||
}
|
||||
]
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=ACTION_PLAN % 'start',
|
||||
check_str=base.RULE_ADMIN_API,
|
||||
description='Start an action plans.',
|
||||
operations=[
|
||||
{
|
||||
'path': '/v1/action_plans/{action_plan_uuid}/action',
|
||||
'method': 'POST'
|
||||
}
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
|
|
@ -137,6 +137,12 @@ class FunctionalTest(base.DbTestCase):
|
|||
headers=headers, extra_environ=extra_environ,
|
||||
status=status, method="put")
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
headers = kwargs.pop('headers', {})
|
||||
headers.setdefault('Accept', 'application/json')
|
||||
kwargs['headers'] = headers
|
||||
return self.app.post(*args, **kwargs)
|
||||
|
||||
def post_json(self, path, params, expect_errors=False, headers=None,
|
||||
extra_environ=None, status=None):
|
||||
"""Sends simulated HTTP POST request to Pecan test app.
|
||||
|
|
|
@ -363,6 +363,53 @@ class TestDelete(api_base.FunctionalTest):
|
|||
self.assertTrue(response.json['error_message'])
|
||||
|
||||
|
||||
class TestStart(api_base.FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
super(TestStart, self).setUp()
|
||||
obj_utils.create_test_goal(self.context)
|
||||
obj_utils.create_test_strategy(self.context)
|
||||
obj_utils.create_test_audit(self.context)
|
||||
self.action_plan = obj_utils.create_test_action_plan(
|
||||
self.context, state=objects.action_plan.State.RECOMMENDED)
|
||||
p = mock.patch.object(db_api.BaseConnection, 'update_action_plan')
|
||||
self.mock_action_plan_update = p.start()
|
||||
self.mock_action_plan_update.side_effect = \
|
||||
self._simulate_rpc_action_plan_update
|
||||
self.addCleanup(p.stop)
|
||||
|
||||
def _simulate_rpc_action_plan_update(self, action_plan):
|
||||
action_plan.save()
|
||||
return action_plan
|
||||
|
||||
@mock.patch('watcher.common.policy.enforce')
|
||||
def test_start_action_plan_not_found(self, mock_policy):
|
||||
mock_policy.return_value = True
|
||||
uuid = utils.generate_uuid()
|
||||
response = self.post('/v1/action_plans/%s/%s' %
|
||||
(uuid, 'start'), expect_errors=True)
|
||||
self.assertEqual(404, response.status_int)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertTrue(response.json['error_message'])
|
||||
|
||||
@mock.patch('watcher.common.policy.enforce')
|
||||
def test_start_action_plan(self, mock_policy):
|
||||
mock_policy.return_value = True
|
||||
action = obj_utils.create_test_action(
|
||||
self.context, id=1)
|
||||
self.action_plan.state = objects.action_plan.State.SUCCEEDED
|
||||
response = self.post('/v1/action_plans/%s/%s/'
|
||||
% (self.action_plan.uuid, 'start'),
|
||||
expect_errors=True)
|
||||
self.assertEqual(200, response.status_int)
|
||||
act_response = self.get_json(
|
||||
'/actions/%s' % action.uuid,
|
||||
expect_errors=True)
|
||||
self.assertEqual(200, act_response.status_int)
|
||||
self.assertEqual('PENDING', act_response.json['state'])
|
||||
self.assertEqual('application/json', act_response.content_type)
|
||||
|
||||
|
||||
class TestPatch(api_base.FunctionalTest):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -568,7 +615,6 @@ class TestPatchStateTransitionOk(api_base.FunctionalTest):
|
|||
'/action_plans/%s' % action_plan.uuid,
|
||||
[{'path': '/state', 'value': self.new_state, 'op': 'replace'}])
|
||||
updated_ap = self.get_json('/action_plans/%s' % action_plan.uuid)
|
||||
|
||||
self.assertNotEqual(self.new_state, initial_ap['state'])
|
||||
self.assertEqual(self.new_state, updated_ap['state'])
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
|
@ -642,4 +688,5 @@ class TestActionPlanPolicyEnforcementWithAdminContext(TestListActionPlan,
|
|||
"action_plan:detail": "rule:default",
|
||||
"action_plan:get": "rule:default",
|
||||
"action_plan:get_all": "rule:default",
|
||||
"action_plan:update": "rule:default"})
|
||||
"action_plan:update": "rule:default",
|
||||
"action_plan:start": "rule:default"})
|
||||
|
|
Loading…
Reference in New Issue