Support "--pre-delete" argument for hook-clear

This changes:
1. Add "--pre-delete" argument for cmd "heat hook-clear" to
clear pre-delete hooks.
2. Add "--pre-delete" argument for osc cmd
"openstack stack hook clear" to clear pre-delete hooks.
3. Support to poll pre-delete hooks for "heat hook-poll" and
"openstack stack hook poll".

Change-Id: Ic5a6e1b7588e3f9ad49eaaf8085f18ec74fc629e
Closes-Bug: #1567814
This commit is contained in:
huangtianhua
2016-04-08 17:25:48 +08:00
parent 4763d5d8fc
commit 726415e43c
7 changed files with 62 additions and 5 deletions

View File

@@ -31,6 +31,10 @@ def get_hook_events(hc, stack_id, event_args, nested_depth=0,
stack_action_reason = 'Stack UPDATE started'
hook_event_reason = 'UPDATE paused until Hook pre-update is cleared'
hook_clear_event_reason = 'Hook pre-update is cleared'
elif hook_type == 'pre-delete':
stack_action_reason = 'Stack DELETE started'
hook_event_reason = 'DELETE paused until Hook pre-delete is cleared'
hook_clear_event_reason = 'Hook pre-delete is cleared'
else:
raise exc.CommandError(_('Unexpected hook type %s') % hook_type)

View File

@@ -56,8 +56,9 @@ def clear_wildcard_hooks(hc, stack_id, stack_patterns, hook_type,
def get_hook_type_via_status(hc, stack_id):
# Figure out if the hook should be pre-create or pre-update based
# on the stack status, also sanity assertions that we're in-progress.
# Figure out if the hook should be pre-create, pre-update or
# pre-delete based on the stack status, also sanity assertions
# that we're in-progress.
try:
stack = hc.stacks.get(stack_id=stack_id)
except exc.HTTPNotFound:
@@ -71,8 +72,10 @@ def get_hook_type_via_status(hc, stack_id):
hook_type = 'pre-create'
elif 'UPDATE' in stack.stack_status:
hook_type = 'pre-update'
elif 'DELETE' in stack.stack_status:
hook_type = 'pre-delete'
else:
raise exc.CommandError(_('Unexpected stack status %s, '
'only create/update supported')
'only create, update and delete supported')
% stack.stack_status)
return hook_type

View File

@@ -1219,6 +1219,11 @@ class StackHookClear(command.Command):
action='store_true',
help=_('Clear the pre-update hooks')
)
parser.add_argument(
'--pre-delete',
action='store_true',
help=_('Clear the pre-delete hooks')
)
parser.add_argument(
'hook',
metavar='<resource>',
@@ -1246,6 +1251,8 @@ def _hook_clear(args, heat_client):
hook_type = 'pre-create'
elif args.pre_update:
hook_type = 'pre-update'
elif args.pre_delete:
hook_type = 'pre-delete'
else:
hook_type = hook_utils.get_hook_type_via_status(heat_client,
args.stack)

View File

@@ -1299,3 +1299,12 @@ class TestStackHookClear(TestStack):
data={'unset_hook': 'pre-update'},
resource_name='resource',
stack_id='my_stack')
def test_hook_clear_pre_delete(self):
arglist = ['my_stack', 'resource', '--pre-delete']
parsed_args = self.check_parser(self.cmd, arglist, [])
self.cmd.take_action(parsed_args)
self.mock_client.resources.signal.assert_called_once_with(
data={'unset_hook': 'pre-delete'},
resource_name='resource',
stack_id='my_stack')

View File

@@ -3718,6 +3718,21 @@ class ShellTestHookFunctions(ShellBase):
self.assertNotRegexpMatches(list_text, 'n_eventid1')
self.assertNotRegexpMatches(list_text, 'n_eventid2')
def test_hook_poll_pre_delete(self):
self.register_keystone_auth_fixture()
stack_id = 'teststack/1'
nested_id = 'nested/2'
self._stub_responses(stack_id, nested_id, 'DELETE')
self.m.ReplayAll()
list_text = self.shell('hook-poll %s --nested-depth 1' % stack_id)
hook_reason = 'DELETE paused until Hook pre-delete is cleared'
required = ['id', 'p_eventid2', 'stack_name', 'teststack', hook_reason]
for r in required:
self.assertRegex(list_text, r)
self.assertNotRegexpMatches(list_text, 'p_eventid1')
self.assertNotRegexpMatches(list_text, 'n_eventid1')
self.assertNotRegexpMatches(list_text, 'n_eventid2')
def test_hook_poll_bad_status(self):
self.register_keystone_auth_fixture()
stack_id = 'teststack/1'
@@ -3752,12 +3767,12 @@ class ShellTestHookFunctions(ShellBase):
def test_hook_poll_clear_bad_action(self):
self.register_keystone_auth_fixture()
stack_id = 'teststack/1'
self._stub_stack_response(stack_id, action='DELETE')
self._stub_stack_response(stack_id, action='BADACTION')
self.m.ReplayAll()
error = self.assertRaises(
exc.CommandError, self.shell,
'hook-clear %s aresource' % stack_id)
self.assertIn('Unexpected stack status DELETE_IN_PROGRESS',
self.assertIn('Unexpected stack status BADACTION_IN_PROGRESS',
str(error))

View File

@@ -269,6 +269,21 @@ class TestHooks(testtools.TestCase):
self.assertEqual('bp', payload['resource_name'])
self.assertEqual('mystack', payload['stack_id'])
def test_clear_pre_delete_hooks(self):
type(self.args).hook = mock.PropertyMock(
return_value=['bp'])
type(self.args).pre_delete = mock.PropertyMock(return_value=True)
bp = mock.Mock()
type(bp).resource_name = 'bp'
self.client.resources.list = mock.Mock(return_value=[bp])
shell.do_hook_clear(self.client, self.args)
self.assertEqual(1, self.client.resources.signal.call_count)
payload = self.client.resources.signal.call_args_list[0][1]
self.assertEqual({'unset_hook': 'pre-delete'}, payload['data'])
self.assertEqual('bp', payload['resource_name'])
self.assertEqual('mystack', payload['stack_id'])
def test_clear_nested_hook(self):
type(self.args).hook = mock.PropertyMock(
return_value=['a/b/bp'])

View File

@@ -1104,6 +1104,8 @@ def do_resource_mark_unhealthy(hc, args):
help=_('Clear the pre-create hooks (optional)'))
@utils.arg('--pre-update', action='store_true', default=False,
help=_('Clear the pre-update hooks (optional)'))
@utils.arg('--pre-delete', action='store_true', default=False,
help=_('Clear the pre-delete hooks (optional)'))
@utils.arg('hook', metavar='<RESOURCE>', nargs='+',
help=_('Resource names with hooks to clear. Resources '
'in nested stacks can be set using slash as a separator: '
@@ -1118,6 +1120,8 @@ def do_hook_clear(hc, args):
hook_type = 'pre-create'
elif args.pre_update:
hook_type = 'pre-update'
elif args.pre_delete:
hook_type = 'pre-delete'
else:
hook_type = hook_utils.get_hook_type_via_status(hc, args.id)