Fix collision with update and update cancel
"openstack update" collides/hides with "openstack update cancel" I discussed a few possible solutions in the bug report. Will change to have a new "openstack stack cancel" command and it will cancel the pending action, for now just supporting update. Blueprint: heat-support-python-openstackclient Change-Id: I7e054ecffea5b03a815f69515651e9c377ff68c2 Closes-Bug: #1545131
This commit is contained in:
@@ -941,7 +941,7 @@ class StackActionBase(lister.Lister):
|
||||
def _take_action(self, parsed_args, action, good_status, bad_status):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
heat_client = self.app.client_manager.orchestration
|
||||
return _stack_action(
|
||||
return _stacks_action(
|
||||
parsed_args,
|
||||
heat_client,
|
||||
action,
|
||||
@@ -950,36 +950,41 @@ class StackActionBase(lister.Lister):
|
||||
)
|
||||
|
||||
|
||||
def _stack_action(parsed_args, heat_client, action, good_status, bad_status):
|
||||
def _stacks_action(parsed_args, heat_client, action, good_status, bad_status):
|
||||
rows = []
|
||||
columns = [
|
||||
'ID',
|
||||
'Stack Name',
|
||||
'Stack Status',
|
||||
'Creation Time',
|
||||
'Updated Time'
|
||||
]
|
||||
for stack in parsed_args.stack:
|
||||
try:
|
||||
action(stack)
|
||||
except heat_exc.HTTPNotFound:
|
||||
msg = _('Stack not found: %s') % stack
|
||||
raise exc.CommandError(msg)
|
||||
|
||||
if parsed_args.wait:
|
||||
if not utils.wait_for_status(heat_client.stacks.get, stack,
|
||||
status_field='stack_status',
|
||||
success_status=good_status,
|
||||
error_status=bad_status):
|
||||
err = _("Error waiting for status from stack %s") % stack
|
||||
raise exc.CommandError(err)
|
||||
|
||||
data = heat_client.stacks.get(stack)
|
||||
columns = [
|
||||
'ID',
|
||||
'Stack Name',
|
||||
'Stack Status',
|
||||
'Creation Time',
|
||||
'Updated Time'
|
||||
]
|
||||
data = _stack_action(stack, parsed_args, heat_client, action,
|
||||
good_status, bad_status)
|
||||
rows += [utils.get_dict_properties(data.to_dict(), columns)]
|
||||
|
||||
return (columns, rows)
|
||||
|
||||
|
||||
def _stack_action(stack, parsed_args, heat_client, action,
|
||||
good_status, bad_status):
|
||||
try:
|
||||
action(stack)
|
||||
except heat_exc.HTTPNotFound:
|
||||
msg = _('Stack not found: %s') % stack
|
||||
raise exc.CommandError(msg)
|
||||
|
||||
if parsed_args.wait:
|
||||
if not utils.wait_for_status(heat_client.stacks.get, stack,
|
||||
status_field='stack_status',
|
||||
success_status=good_status,
|
||||
error_status=bad_status):
|
||||
err = _("Error waiting for status from stack %s") % stack
|
||||
raise exc.CommandError(err)
|
||||
|
||||
return heat_client.stacks.get(stack)
|
||||
|
||||
|
||||
class SuspendStack(StackActionBase):
|
||||
"""Suspend a stack."""
|
||||
|
||||
@@ -1022,27 +1027,6 @@ class ResumeStack(StackActionBase):
|
||||
)
|
||||
|
||||
|
||||
class UpdateCancelStack(StackActionBase):
|
||||
"""Cancel update for a stack."""
|
||||
|
||||
log = logging.getLogger(__name__ + '.UpdateCancelStack')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
return self._get_parser(
|
||||
prog_name,
|
||||
_('Stack(s) to cancel update (name or ID)'),
|
||||
_('Wait for cancel update to complete')
|
||||
)
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
return self._take_action(
|
||||
parsed_args,
|
||||
self.app.client_manager.orchestration.actions.cancel_update,
|
||||
['cancel_update_complete'],
|
||||
['cancel_update_failed']
|
||||
)
|
||||
|
||||
|
||||
class CheckStack(StackActionBase):
|
||||
"""Check a stack."""
|
||||
|
||||
@@ -1064,6 +1048,60 @@ class CheckStack(StackActionBase):
|
||||
)
|
||||
|
||||
|
||||
class CancelStack(StackActionBase):
|
||||
"""Cancel current task for a stack.
|
||||
|
||||
Supported tasks for cancellation:
|
||||
* update
|
||||
"""
|
||||
|
||||
log = logging.getLogger(__name__ + '.CancelStack')
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
return self._get_parser(
|
||||
prog_name,
|
||||
_('Stack(s) to cancel (name or ID)'),
|
||||
_('Wait for check to complete')
|
||||
)
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
self.log.debug("take_action(%s)", parsed_args)
|
||||
rows = []
|
||||
columns = [
|
||||
'ID',
|
||||
'Stack Name',
|
||||
'Stack Status',
|
||||
'Creation Time',
|
||||
'Updated Time'
|
||||
]
|
||||
heat_client = self.app.client_manager.orchestration
|
||||
|
||||
for stack in parsed_args.stack:
|
||||
try:
|
||||
data = heat_client.stacks.get(stack_id=stack)
|
||||
except heat_exc.HTTPNotFound:
|
||||
raise exc.CommandError('Stack not found: %s' % stack)
|
||||
|
||||
status = getattr(data, 'stack_status').lower()
|
||||
if status == 'update_in_progress':
|
||||
data = _stack_action(
|
||||
stack,
|
||||
parsed_args,
|
||||
heat_client,
|
||||
heat_client.actions.cancel_update,
|
||||
['cancel_update_complete'],
|
||||
['cancel_update_failed']
|
||||
)
|
||||
rows += [utils.get_dict_properties(data.to_dict(), columns)]
|
||||
else:
|
||||
err = _("Stack %(id)s with status \'%(status)s\' "
|
||||
"not in cancelable state") % {
|
||||
'id': stack, 'status': status}
|
||||
raise exc.CommandError(err)
|
||||
|
||||
return (columns, rows)
|
||||
|
||||
|
||||
class StackHookPoll(lister.Lister):
|
||||
'''List resources with pending hook for a stack.'''
|
||||
|
||||
|
@@ -921,21 +921,24 @@ class _TestStackCheckBase(object):
|
||||
self.mock_client.stacks.get = mock.Mock(
|
||||
return_value=self.stack)
|
||||
|
||||
def _test_stack_action(self):
|
||||
def _test_stack_action(self, get_call_count=1):
|
||||
arglist = ['my_stack']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, rows = self.cmd.take_action(parsed_args)
|
||||
self.action.assert_called_once_with('my_stack')
|
||||
self.mock_client.stacks.get.assert_called_once_with('my_stack')
|
||||
self.mock_client.stacks.get.assert_called_with('my_stack')
|
||||
self.assertEqual(get_call_count,
|
||||
self.mock_client.stacks.get.call_count)
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(1, len(rows))
|
||||
|
||||
def _test_stack_action_multi(self):
|
||||
def _test_stack_action_multi(self, get_call_count=2):
|
||||
arglist = ['my_stack1', 'my_stack2']
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, rows = self.cmd.take_action(parsed_args)
|
||||
self.assertEqual(2, self.action.call_count)
|
||||
self.assertEqual(2, self.mock_client.stacks.get.call_count)
|
||||
self.assertEqual(get_call_count,
|
||||
self.mock_client.stacks.get.call_count)
|
||||
self.action.assert_called_with('my_stack2')
|
||||
self.mock_client.stacks.get.assert_called_with('my_stack2')
|
||||
self.assertEqual(self.columns, columns)
|
||||
@@ -948,7 +951,7 @@ class _TestStackCheckBase(object):
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
columns, rows = self.cmd.take_action(parsed_args)
|
||||
self.action.assert_called_with('my_stack')
|
||||
self.mock_client.stacks.get.assert_called_once_with('my_stack')
|
||||
self.mock_client.stacks.get.assert_called_with('my_stack')
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(1, len(rows))
|
||||
|
||||
@@ -1026,31 +1029,51 @@ class TestStackResume(_TestStackCheckBase, TestStack):
|
||||
self._test_stack_action_exception()
|
||||
|
||||
|
||||
class TestStackUpdateCancel(_TestStackCheckBase, TestStack):
|
||||
class TestStackCancel(_TestStackCheckBase, TestStack):
|
||||
|
||||
stack_update_in_progress = stacks.Stack(None, {
|
||||
"id": '1234',
|
||||
"stack_name": 'my_stack',
|
||||
"creation_time": "2013-08-04T20:57:55Z",
|
||||
"updated_time": "2013-08-04T20:57:55Z",
|
||||
"stack_status": "UPDATE_IN_PROGRESS"
|
||||
})
|
||||
|
||||
def setUp(self):
|
||||
super(TestStackUpdateCancel, self).setUp()
|
||||
super(TestStackCancel, self).setUp()
|
||||
self.mock_client.actions.cancel_update = mock.Mock()
|
||||
self._setUp(
|
||||
stack.UpdateCancelStack(self.app, None),
|
||||
stack.CancelStack(self.app, None),
|
||||
self.mock_client.actions.cancel_update
|
||||
)
|
||||
self.mock_client.stacks.get = mock.Mock(
|
||||
return_value=self.stack_update_in_progress)
|
||||
|
||||
def test_stack_cancel_update(self):
|
||||
self._test_stack_action()
|
||||
def test_stack_cancel(self):
|
||||
self._test_stack_action(2)
|
||||
|
||||
def test_stack_cancel_update_multi(self):
|
||||
self._test_stack_action_multi()
|
||||
def test_stack_cancel_multi(self):
|
||||
self._test_stack_action_multi(4)
|
||||
|
||||
def test_stack_cancel_update_wait(self):
|
||||
def test_stack_cancel_wait(self):
|
||||
self._test_stack_action_wait()
|
||||
|
||||
def test_stack_cancel_update_wait_error(self):
|
||||
def test_stack_cancel_wait_error(self):
|
||||
self._test_stack_action_wait_error()
|
||||
|
||||
def test_stack_cancel_update_exception(self):
|
||||
def test_stack_cancel_exception(self):
|
||||
self._test_stack_action_exception()
|
||||
|
||||
def test_stack_cancel_unsupported_state(self):
|
||||
self.mock_client.stacks.get = mock.Mock(
|
||||
return_value=self.stack)
|
||||
error = self.assertRaises(exc.CommandError,
|
||||
self._test_stack_action,
|
||||
2)
|
||||
self.assertEqual('Stack my_stack with status \'create_complete\' '
|
||||
'not in cancelable state',
|
||||
str(error))
|
||||
|
||||
|
||||
class TestStackCheck(_TestStackCheckBase, TestStack):
|
||||
|
||||
|
@@ -46,6 +46,7 @@ openstack.orchestration.v1 =
|
||||
software_deployment_show = heatclient.osc.v1.software_deployment:ShowDeployment
|
||||
stack_abandon = heatclient.osc.v1.stack:AbandonStack
|
||||
stack_adopt = heatclient.osc.v1.stack:AdoptStack
|
||||
stack_cancel = heatclient.osc.v1.stack:CancelStack
|
||||
stack_check = heatclient.osc.v1.stack:CheckStack
|
||||
stack_create = heatclient.osc.v1.stack:CreateStack
|
||||
stack_delete = heatclient.osc.v1.stack:DeleteStack
|
||||
@@ -70,7 +71,6 @@ openstack.orchestration.v1 =
|
||||
stack_suspend = heatclient.osc.v1.stack:SuspendStack
|
||||
stack_template_show = heatclient.osc.v1.stack:TemplateShowStack
|
||||
stack_update = heatclient.osc.v1.stack:UpdateStack
|
||||
stack_update_cancel = heatclient.osc.v1.stack:UpdateCancelStack
|
||||
|
||||
[global]
|
||||
setup-hooks =
|
||||
|
Reference in New Issue
Block a user