Merge "Cancel traversal of nested stack" into stable/newton
This commit is contained in:
commit
71a8d63479
|
@ -28,6 +28,7 @@ from heat.common.i18n import _LW
|
||||||
from heat.common import messaging as rpc_messaging
|
from heat.common import messaging as rpc_messaging
|
||||||
from heat.db import api as db_api
|
from heat.db import api as db_api
|
||||||
from heat.engine import check_resource
|
from heat.engine import check_resource
|
||||||
|
from heat.engine import stack as parser
|
||||||
from heat.engine import sync_point
|
from heat.engine import sync_point
|
||||||
from heat.objects import stack as stack_objects
|
from heat.objects import stack as stack_objects
|
||||||
from heat.rpc import api as rpc_api
|
from heat.rpc import api as rpc_api
|
||||||
|
@ -104,24 +105,17 @@ class WorkerService(service.Service):
|
||||||
in_progress resources to complete normally; no worker is stopped
|
in_progress resources to complete normally; no worker is stopped
|
||||||
abruptly.
|
abruptly.
|
||||||
"""
|
"""
|
||||||
old_trvsl = stack.current_traversal
|
_stop_traversal(stack)
|
||||||
updated = _update_current_traversal(stack)
|
|
||||||
if not updated:
|
|
||||||
LOG.warning(_LW("Failed to update stack %(name)s with new "
|
|
||||||
"traversal, aborting stack cancel"),
|
|
||||||
{'name': stack.name})
|
|
||||||
return
|
|
||||||
|
|
||||||
reason = 'User cancelled stack %s ' % stack.action
|
db_child_stacks = stack_objects.Stack.get_all_by_root_owner_id(
|
||||||
updated = stack.state_set(stack.action, stack.FAILED, reason)
|
stack.context, stack.id)
|
||||||
if not updated:
|
|
||||||
LOG.warning(_LW("Failed to update stack %(name)s status"
|
|
||||||
" to %(action)_%(state)"),
|
|
||||||
{'name': stack.name, 'action': stack.action,
|
|
||||||
'state': stack.FAILED})
|
|
||||||
return
|
|
||||||
|
|
||||||
sync_point.delete_all(stack.context, stack.id, old_trvsl)
|
for db_child in db_child_stacks:
|
||||||
|
if db_child.status == parser.Stack.IN_PROGRESS:
|
||||||
|
child = parser.Stack.load(stack.context,
|
||||||
|
stack_id=db_child.id,
|
||||||
|
stack=db_child)
|
||||||
|
_stop_traversal(child)
|
||||||
|
|
||||||
def stop_all_workers(self, stack):
|
def stop_all_workers(self, stack):
|
||||||
# stop the traversal
|
# stop the traversal
|
||||||
|
@ -184,6 +178,27 @@ class WorkerService(service.Service):
|
||||||
_cancel_check_resource(stack_id, self.engine_id, self.thread_group_mgr)
|
_cancel_check_resource(stack_id, self.engine_id, self.thread_group_mgr)
|
||||||
|
|
||||||
|
|
||||||
|
def _stop_traversal(stack):
|
||||||
|
old_trvsl = stack.current_traversal
|
||||||
|
updated = _update_current_traversal(stack)
|
||||||
|
if not updated:
|
||||||
|
LOG.warning(_LW("Failed to update stack %(name)s with new "
|
||||||
|
"traversal, aborting stack cancel"),
|
||||||
|
{'name': stack.name})
|
||||||
|
return
|
||||||
|
|
||||||
|
reason = 'Stack %(action)s cancelled' % {'action': stack.action}
|
||||||
|
updated = stack.state_set(stack.action, stack.FAILED, reason)
|
||||||
|
if not updated:
|
||||||
|
LOG.warning(_LW("Failed to update stack %(name)s status"
|
||||||
|
" to %(action)_%(state)"),
|
||||||
|
{'name': stack.name, 'action': stack.action,
|
||||||
|
'state': stack.FAILED})
|
||||||
|
return
|
||||||
|
|
||||||
|
sync_point.delete_all(stack.context, stack.id, old_trvsl)
|
||||||
|
|
||||||
|
|
||||||
def _update_current_traversal(stack):
|
def _update_current_traversal(stack):
|
||||||
previous_traversal = stack.current_traversal
|
previous_traversal = stack.current_traversal
|
||||||
stack.current_traversal = uuidutils.generate_uuid()
|
stack.current_traversal = uuidutils.generate_uuid()
|
||||||
|
|
|
@ -17,6 +17,8 @@ import mock
|
||||||
|
|
||||||
from heat.db import api as db_api
|
from heat.db import api as db_api
|
||||||
from heat.engine import check_resource
|
from heat.engine import check_resource
|
||||||
|
from heat.engine import stack as parser
|
||||||
|
from heat.engine import template as templatem
|
||||||
from heat.engine import worker
|
from heat.engine import worker
|
||||||
from heat.objects import stack as stack_objects
|
from heat.objects import stack as stack_objects
|
||||||
from heat.rpc import worker_client as wc
|
from heat.rpc import worker_client as wc
|
||||||
|
@ -178,6 +180,26 @@ class WorkerServiceTest(common.HeatTestCase):
|
||||||
mock_ccr.assert_has_calls(calls, any_order=True)
|
mock_ccr.assert_has_calls(calls, any_order=True)
|
||||||
self.assertTrue(mock_wc.called)
|
self.assertTrue(mock_wc.called)
|
||||||
|
|
||||||
|
@mock.patch.object(worker, '_stop_traversal')
|
||||||
|
def test_stop_traversal_stops_nested_stack(self, mock_st):
|
||||||
|
mock_tgm = mock.Mock()
|
||||||
|
ctx = utils.dummy_context()
|
||||||
|
tmpl = templatem.Template.create_empty_template()
|
||||||
|
stack1 = parser.Stack(ctx, 'stack1', tmpl,
|
||||||
|
current_traversal='123')
|
||||||
|
stack1.store()
|
||||||
|
stack2 = parser.Stack(ctx, 'stack2', tmpl,
|
||||||
|
owner_id=stack1.id, current_traversal='456')
|
||||||
|
stack2.store()
|
||||||
|
_worker = worker.WorkerService('host-1', 'topic-1', 'engine-001',
|
||||||
|
mock_tgm)
|
||||||
|
_worker.stop_traversal(stack1)
|
||||||
|
self.assertEqual(2, mock_st.call_count)
|
||||||
|
call1, call2 = mock_st.call_args_list
|
||||||
|
call_args1, call_args2 = call1[0][0], call2[0][0]
|
||||||
|
self.assertEqual('stack1', call_args1.name)
|
||||||
|
self.assertEqual('stack2', call_args2.name)
|
||||||
|
|
||||||
@mock.patch.object(worker, '_cancel_workers')
|
@mock.patch.object(worker, '_cancel_workers')
|
||||||
@mock.patch.object(worker.WorkerService, 'stop_traversal')
|
@mock.patch.object(worker.WorkerService, 'stop_traversal')
|
||||||
def test_stop_all_workers_when_stack_in_progress(self, mock_st, mock_cw):
|
def test_stop_all_workers_when_stack_in_progress(self, mock_st, mock_cw):
|
||||||
|
|
Loading…
Reference in New Issue