Merge "Add converge flag in stack update for observing on reality"
This commit is contained in:
commit
bef2455080
|
@ -476,6 +476,14 @@ config_name:
|
|||
in: body
|
||||
required: true
|
||||
type: string
|
||||
converge:
|
||||
description: |
|
||||
Set to ``true`` to force the stack to observe the reality
|
||||
before update.
|
||||
in: body
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
created_at:
|
||||
description: |
|
||||
The date and time when the service engine was created.
|
||||
|
|
|
@ -374,6 +374,7 @@ Request Parameters
|
|||
- template: template
|
||||
- template_url: template_url
|
||||
- timeout_mins: timeout_mins
|
||||
- converge: converge
|
||||
|
||||
Request Example
|
||||
---------------
|
||||
|
@ -440,6 +441,7 @@ Request Parameters
|
|||
- template: template
|
||||
- template_url: template_url
|
||||
- timeout_mins: timeout_mins
|
||||
- converge: converge
|
||||
|
||||
Request Example
|
||||
---------------
|
||||
|
@ -505,6 +507,7 @@ Request Parameters
|
|||
- template: template
|
||||
- template_url: template_url
|
||||
- timeout_mins: timeout_mins
|
||||
- converge: converge
|
||||
|
||||
Request Example
|
||||
---------------
|
||||
|
@ -575,6 +578,7 @@ Request Parameters
|
|||
- template: template
|
||||
- template_url: template_url
|
||||
- timeout_mins: timeout_mins
|
||||
- converge: converge
|
||||
|
||||
Request Example
|
||||
---------------
|
||||
|
|
|
@ -374,7 +374,7 @@ class StackController(object):
|
|||
formatted_stack = stacks_view.format_stack(req, result)
|
||||
return {'stack': formatted_stack}
|
||||
|
||||
def prepare_args(self, data):
|
||||
def prepare_args(self, data, is_update=False):
|
||||
args = data.args()
|
||||
key = rpc_api.PARAM_TIMEOUT
|
||||
if key in args:
|
||||
|
@ -382,6 +382,11 @@ class StackController(object):
|
|||
key = rpc_api.PARAM_TAGS
|
||||
if args.get(key) is not None:
|
||||
args[key] = self._extract_tags_param(args[key])
|
||||
key = rpc_api.PARAM_CONVERGE
|
||||
if not is_update and key in args:
|
||||
msg = _("%s flag only supported in stack update (or update "
|
||||
"preview) request.") % key
|
||||
raise exc.HTTPBadRequest(six.text_type(msg))
|
||||
return args
|
||||
|
||||
@util.policy_enforce
|
||||
|
@ -472,7 +477,7 @@ class StackController(object):
|
|||
"""Update an existing stack with a new template and/or parameters."""
|
||||
data = InstantiationData(body)
|
||||
|
||||
args = self.prepare_args(data)
|
||||
args = self.prepare_args(data, is_update=True)
|
||||
self.rpc_client.update_stack(
|
||||
req.context,
|
||||
identity,
|
||||
|
@ -493,7 +498,7 @@ class StackController(object):
|
|||
"""
|
||||
data = InstantiationData(body, patch=True)
|
||||
|
||||
args = self.prepare_args(data)
|
||||
args = self.prepare_args(data, is_update=True)
|
||||
self.rpc_client.update_stack(
|
||||
req.context,
|
||||
identity,
|
||||
|
@ -518,7 +523,7 @@ class StackController(object):
|
|||
"""Preview update for existing stack with a new template/parameters."""
|
||||
data = InstantiationData(body)
|
||||
|
||||
args = self.prepare_args(data)
|
||||
args = self.prepare_args(data, is_update=True)
|
||||
show_nested = self._param_show_nested(req)
|
||||
if show_nested is not None:
|
||||
args[rpc_api.PARAM_SHOW_NESTED] = show_nested
|
||||
|
@ -538,7 +543,7 @@ class StackController(object):
|
|||
"""Preview PATCH update for existing stack."""
|
||||
data = InstantiationData(body, patch=True)
|
||||
|
||||
args = self.prepare_args(data)
|
||||
args = self.prepare_args(data, is_update=True)
|
||||
show_nested = self._param_show_nested(req)
|
||||
if show_nested is not None:
|
||||
args['show_nested'] = show_nested
|
||||
|
|
|
@ -46,11 +46,10 @@ def extract_args(params):
|
|||
kwargs[rpc_api.PARAM_TIMEOUT] = timeout
|
||||
else:
|
||||
raise ValueError(_('Invalid timeout value %s') % timeout)
|
||||
|
||||
name = rpc_api.PARAM_DISABLE_ROLLBACK
|
||||
if name in params:
|
||||
disable_rollback = param_utils.extract_bool(name, params[name])
|
||||
kwargs[name] = disable_rollback
|
||||
for name in [rpc_api.PARAM_CONVERGE, rpc_api.PARAM_DISABLE_ROLLBACK]:
|
||||
if name in params:
|
||||
bool_value = param_utils.extract_bool(name, params[name])
|
||||
kwargs[name] = bool_value
|
||||
|
||||
name = rpc_api.PARAM_SHOW_DELETED
|
||||
if name in params:
|
||||
|
|
|
@ -247,6 +247,7 @@ class Resource(status.ResourceStatus):
|
|||
self.root_stack_id = None
|
||||
self._calling_engine_id = None
|
||||
self._atomic_key = None
|
||||
self.converge = False
|
||||
|
||||
if not self.stack.in_convergence_check:
|
||||
resource = stack.db_resource_get(name)
|
||||
|
@ -1438,7 +1439,7 @@ class Resource(status.ResourceStatus):
|
|||
self.translate_properties(after_props)
|
||||
self.translate_properties(before_props)
|
||||
|
||||
if cfg.CONF.observe_on_update and before_props:
|
||||
if (cfg.CONF.observe_on_update or self.converge) and before_props:
|
||||
if not self.resource_id:
|
||||
raise UpdateReplace(self)
|
||||
|
||||
|
|
|
@ -497,7 +497,8 @@ class StackResource(resource.Resource):
|
|||
|
||||
kwargs.update({
|
||||
'stack_identity': dict(self.nested_identifier()),
|
||||
'args': {rpc_api.PARAM_TIMEOUT: timeout_mins}
|
||||
'args': {rpc_api.PARAM_TIMEOUT: timeout_mins,
|
||||
rpc_api.PARAM_CONVERGE: self.converge}
|
||||
})
|
||||
with self.translate_remote_exceptions:
|
||||
try:
|
||||
|
|
|
@ -874,7 +874,7 @@ class EngineService(service.ServiceBase):
|
|||
"""
|
||||
|
||||
# Now parse the template and any parameters for the updated
|
||||
# stack definition. If PARAM_EXISTING is specified, we merge
|
||||
# stack definition. If PARAM_EXISTING is specified, we merge
|
||||
# any environment provided into the existing one and attempt
|
||||
# to use the existing stack template, if one is not provided.
|
||||
if args.get(rpc_api.PARAM_EXISTING):
|
||||
|
@ -947,6 +947,8 @@ class EngineService(service.ServiceBase):
|
|||
current_stack.timeout_mins)
|
||||
common_params.setdefault(rpc_api.PARAM_DISABLE_ROLLBACK,
|
||||
current_stack.disable_rollback)
|
||||
common_params.setdefault(rpc_api.PARAM_CONVERGE,
|
||||
current_stack.converge)
|
||||
|
||||
if args.get(rpc_api.PARAM_EXISTING):
|
||||
common_params.setdefault(rpc_api.STACK_TAGS,
|
||||
|
|
|
@ -121,7 +121,7 @@ class Stack(collections.Mapping):
|
|||
nested_depth=0, strict_validate=True, convergence=False,
|
||||
current_traversal=None, tags=None, prev_raw_template_id=None,
|
||||
current_deps=None, cache_data=None,
|
||||
deleted_time=None):
|
||||
deleted_time=None, converge=False):
|
||||
|
||||
"""Initialise the Stack.
|
||||
|
||||
|
@ -181,6 +181,7 @@ class Stack(collections.Mapping):
|
|||
self._worker_client = None
|
||||
self._convg_deps = None
|
||||
self.thread_group_mgr = None
|
||||
self.converge = converge
|
||||
|
||||
# strict_validate can be used to disable value validation
|
||||
# in the resource properties schema, this is useful when
|
||||
|
@ -1266,6 +1267,7 @@ class Stack(collections.Mapping):
|
|||
if new_stack is not None:
|
||||
self.disable_rollback = new_stack.disable_rollback
|
||||
self.timeout_mins = new_stack.timeout_mins
|
||||
self.converge = new_stack.converge
|
||||
|
||||
self.defn = new_stack.defn
|
||||
self._set_param_stackid()
|
||||
|
@ -1345,7 +1347,8 @@ class Stack(collections.Mapping):
|
|||
self.worker_client.check_resource(self.context, rsrc_id,
|
||||
self.current_traversal,
|
||||
input_data, is_update,
|
||||
self.adopt_stack_data)
|
||||
self.adopt_stack_data,
|
||||
self.converge)
|
||||
if scheduler.ENABLE_SLEEP:
|
||||
eventlet.sleep(1)
|
||||
|
||||
|
|
|
@ -213,6 +213,7 @@ class StackUpdate(object):
|
|||
existing_res.stack)
|
||||
existing_res.stack.resources[existing_res.name] = substitute
|
||||
existing_res = substitute
|
||||
existing_res.converge = self.new_stack.converge
|
||||
return existing_res.update(new_snippet, existing_snippet,
|
||||
prev_resource=prev_res)
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class WorkerService(object):
|
|||
or expect replies from these messages.
|
||||
"""
|
||||
|
||||
RPC_API_VERSION = '1.3'
|
||||
RPC_API_VERSION = '1.4'
|
||||
|
||||
def __init__(self,
|
||||
host,
|
||||
|
@ -161,7 +161,7 @@ class WorkerService(object):
|
|||
@context.request_context
|
||||
@log_exceptions
|
||||
def check_resource(self, cnxt, resource_id, current_traversal, data,
|
||||
is_update, adopt_stack_data):
|
||||
is_update, adopt_stack_data, converge=False):
|
||||
"""Process a node in the dependency graph.
|
||||
|
||||
The node may be associated with either an update or a cleanup of its
|
||||
|
@ -176,6 +176,8 @@ class WorkerService(object):
|
|||
if rsrc is None:
|
||||
return
|
||||
|
||||
rsrc.converge = converge
|
||||
|
||||
msg_queue = eventlet.queue.LightQueue()
|
||||
try:
|
||||
self.thread_group_mgr.add_msg_queue(stack.id, msg_queue)
|
||||
|
|
|
@ -20,14 +20,14 @@ PARAM_KEYS = (
|
|||
PARAM_CLEAR_PARAMETERS, PARAM_GLOBAL_TENANT, PARAM_LIMIT,
|
||||
PARAM_NESTED_DEPTH, PARAM_TAGS, PARAM_SHOW_HIDDEN, PARAM_TAGS_ANY,
|
||||
PARAM_NOT_TAGS, PARAM_NOT_TAGS_ANY, TEMPLATE_TYPE, PARAM_WITH_DETAIL,
|
||||
RESOLVE_OUTPUTS, PARAM_IGNORE_ERRORS
|
||||
RESOLVE_OUTPUTS, PARAM_IGNORE_ERRORS, PARAM_CONVERGE
|
||||
) = (
|
||||
'timeout_mins', 'disable_rollback', 'adopt_stack_data',
|
||||
'show_deleted', 'show_nested', 'existing',
|
||||
'clear_parameters', 'global_tenant', 'limit',
|
||||
'nested_depth', 'tags', 'show_hidden', 'tags_any',
|
||||
'not_tags', 'not_tags_any', 'template_type', 'with_detail',
|
||||
'resolve_outputs', 'ignore_errors'
|
||||
'resolve_outputs', 'ignore_errors', 'converge'
|
||||
)
|
||||
|
||||
STACK_KEYS = (
|
||||
|
|
|
@ -28,6 +28,7 @@ class WorkerClient(object):
|
|||
1.1 - Added check_resource.
|
||||
1.2 - Add adopt data argument to check_resource.
|
||||
1.3 - Added cancel_check_resource API.
|
||||
1.4 - Add converge argument to check_resource
|
||||
"""
|
||||
|
||||
BASE_RPC_API_VERSION = '1.0'
|
||||
|
@ -50,13 +51,16 @@ class WorkerClient(object):
|
|||
client.cast(ctxt, method, **kwargs)
|
||||
|
||||
def check_resource(self, ctxt, resource_id,
|
||||
current_traversal, data, is_update, adopt_stack_data):
|
||||
current_traversal, data, is_update, adopt_stack_data,
|
||||
converge=False):
|
||||
self.cast(ctxt,
|
||||
self.make_msg(
|
||||
'check_resource', resource_id=resource_id,
|
||||
current_traversal=current_traversal, data=data,
|
||||
is_update=is_update, adopt_stack_data=adopt_stack_data),
|
||||
version='1.2')
|
||||
is_update=is_update, adopt_stack_data=adopt_stack_data,
|
||||
converge=converge
|
||||
),
|
||||
version='1.4')
|
||||
|
||||
def cancel_check_resource(self, ctxt, stack_id, engine_id):
|
||||
"""Send check-resource cancel message.
|
||||
|
|
|
@ -28,13 +28,14 @@ class Worker(message_processor.MessageProcessor):
|
|||
@message_processor.asynchronous
|
||||
def check_resource(self, ctxt, resource_id,
|
||||
current_traversal, data,
|
||||
is_update, adopt_stack_data):
|
||||
is_update, adopt_stack_data, converge=False):
|
||||
worker.WorkerService("fake_host", "fake_topic",
|
||||
"fake_engine", mock.Mock()).check_resource(
|
||||
ctxt, resource_id,
|
||||
current_traversal,
|
||||
data, is_update,
|
||||
adopt_stack_data)
|
||||
adopt_stack_data,
|
||||
converge)
|
||||
|
||||
def stop_all_workers(self, current_stack):
|
||||
pass
|
||||
|
|
|
@ -71,7 +71,7 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
|||
self.patchobject(eventlet.queue, 'LightQueue', return_value=msgq_mock)
|
||||
|
||||
# do update
|
||||
api_args = {'timeout_mins': 60}
|
||||
api_args = {'timeout_mins': 60, rpc_api.PARAM_CONVERGE: True}
|
||||
result = self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
template, params, None, api_args)
|
||||
|
||||
|
@ -97,7 +97,9 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
|||
tenant_id='test_tenant_id',
|
||||
timeout_mins=60,
|
||||
user_creds_id=u'1',
|
||||
username='test_username')
|
||||
username='test_username',
|
||||
converge=True
|
||||
)
|
||||
mock_load.assert_called_once_with(self.ctx, stack=s)
|
||||
mock_validate.assert_called_once_with()
|
||||
|
||||
|
@ -127,7 +129,8 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
|||
# Test
|
||||
environment_files = ['env_1']
|
||||
self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
template, params, None, {},
|
||||
template, params, None,
|
||||
{rpc_api.PARAM_CONVERGE: False},
|
||||
environment_files=environment_files)
|
||||
|
||||
# Verify
|
||||
|
@ -160,7 +163,7 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
|||
self.patchobject(eventlet.queue, 'LightQueue', return_value=msgq_mock)
|
||||
|
||||
# do update
|
||||
api_args = {'timeout_mins': 60}
|
||||
api_args = {'timeout_mins': 60, rpc_api.PARAM_CONVERGE: False}
|
||||
result = self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
None, None, None, api_args,
|
||||
template_id=tmpl_id)
|
||||
|
@ -186,7 +189,9 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
|||
tenant_id='test_tenant_id',
|
||||
timeout_mins=60,
|
||||
user_creds_id=u'1',
|
||||
username='test_username')
|
||||
username='test_username',
|
||||
converge=False
|
||||
)
|
||||
mock_load.assert_called_once_with(self.ctx, stack=s)
|
||||
mock_validate.assert_called_once_with()
|
||||
|
||||
|
@ -202,7 +207,8 @@ class ServiceStackUpdateTest(common.HeatTestCase):
|
|||
'parameters': {'newparam': 123},
|
||||
'resource_registry': {'resources': {}}}
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True}
|
||||
rpc_api.PARAM_EXISTING: True,
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
t = template_format.parse(tools.wp_template)
|
||||
|
||||
stk = tools.get_stack(stack_name, self.ctx, with_params=True)
|
||||
|
@ -265,7 +271,8 @@ resources:
|
|||
'parameters': {},
|
||||
'resource_registry': {'resources': {}}}
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True}
|
||||
rpc_api.PARAM_EXISTING: True,
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
|
||||
with mock.patch('heat.engine.stack.Stack') as mock_stack:
|
||||
stk.update = mock.Mock()
|
||||
|
@ -297,7 +304,8 @@ resources:
|
|||
'resource_registry': {'resources': {}}}
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True,
|
||||
rpc_api.PARAM_CLEAR_PARAMETERS: ['removeme']}
|
||||
rpc_api.PARAM_CLEAR_PARAMETERS: ['removeme'],
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
t = template_format.parse(tools.wp_template)
|
||||
t['parameters']['removeme'] = {'type': 'string'}
|
||||
|
||||
|
@ -383,7 +391,8 @@ resources:
|
|||
update_files = {'newfoo2.yaml': 'newfoo',
|
||||
'myother.yaml': 'myother'}
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True}
|
||||
rpc_api.PARAM_EXISTING: True,
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
t = template_format.parse(tools.wp_template)
|
||||
|
||||
stk = utils.parse_stack(t, stack_name=stack_name, params=intial_params,
|
||||
|
@ -439,7 +448,8 @@ resources:
|
|||
'parameters': {},
|
||||
'resource_registry': {}}
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True}
|
||||
rpc_api.PARAM_EXISTING: True,
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
t = template_format.parse(tools.wp_template)
|
||||
|
||||
stk = utils.parse_stack(t, stack_name=stack_name, params=intial_params)
|
||||
|
@ -489,7 +499,8 @@ resources:
|
|||
|
||||
# do update
|
||||
result = self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
template, params, None, {})
|
||||
template, params, None,
|
||||
{rpc_api.PARAM_CONVERGE: False})
|
||||
|
||||
# assertions
|
||||
self.assertEqual(old_stack.identifier(), result)
|
||||
|
@ -511,7 +522,9 @@ resources:
|
|||
strict_validate=True,
|
||||
tenant_id='test_tenant_id', timeout_mins=1,
|
||||
user_creds_id=u'1',
|
||||
username='test_username')
|
||||
username='test_username',
|
||||
converge=False
|
||||
)
|
||||
|
||||
def test_stack_cancel_update_same_engine(self):
|
||||
stack_name = 'service_update_stack_test_cancel_same_engine'
|
||||
|
@ -619,7 +632,7 @@ resources:
|
|||
# do update
|
||||
cfg.CONF.set_override('max_resources_per_stack', 3)
|
||||
|
||||
api_args = {'timeout_mins': 60}
|
||||
api_args = {'timeout_mins': 60, rpc_api.PARAM_CONVERGE: False}
|
||||
result = self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
template, params, None, api_args)
|
||||
|
||||
|
@ -642,7 +655,9 @@ resources:
|
|||
stack_user_project_id='1234', strict_validate=True,
|
||||
tenant_id='test_tenant_id',
|
||||
timeout_mins=60, user_creds_id=u'1',
|
||||
username='test_username')
|
||||
username='test_username',
|
||||
converge=False
|
||||
)
|
||||
mock_load.assert_called_once_with(self.ctx, stack=s)
|
||||
mock_validate.assert_called_once_with()
|
||||
|
||||
|
@ -678,7 +693,8 @@ resources:
|
|||
return_value=old_stack)
|
||||
|
||||
result = self.man.update_stack(self.ctx, create_stack.identifier(),
|
||||
tpl, {}, None, {})
|
||||
tpl, {}, None,
|
||||
{rpc_api.PARAM_CONVERGE: False})
|
||||
|
||||
old_stack._persist_state()
|
||||
self.assertEqual((old_stack.UPDATE, old_stack.COMPLETE),
|
||||
|
@ -710,7 +726,7 @@ resources:
|
|||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.man.update_stack, self.ctx,
|
||||
old_stack.identifier(), tpl, params,
|
||||
None, {})
|
||||
None, {rpc_api.PARAM_CONVERGE: False})
|
||||
self.assertEqual(exception.RequestLimitExceeded, ex.exc_info[0])
|
||||
self.assertIn(exception.StackResourceLimitExceeded.msg_fmt,
|
||||
six.text_type(ex.exc_info[1]))
|
||||
|
@ -738,7 +754,7 @@ resources:
|
|||
mock_validate = self.patchobject(stk, 'validate',
|
||||
side_effect=ex_expected)
|
||||
# do update
|
||||
api_args = {'timeout_mins': 60}
|
||||
api_args = {'timeout_mins': 60, rpc_api.PARAM_CONVERGE: False}
|
||||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.man.update_stack,
|
||||
self.ctx, old_stack.identifier(),
|
||||
|
@ -758,7 +774,9 @@ resources:
|
|||
stack_user_project_id='1234', strict_validate=True,
|
||||
tenant_id='test_tenant_id',
|
||||
timeout_mins=60, user_creds_id=u'1',
|
||||
username='test_username')
|
||||
username='test_username',
|
||||
converge=False
|
||||
)
|
||||
mock_load.assert_called_once_with(self.ctx, stack=s)
|
||||
mock_validate.assert_called_once_with()
|
||||
|
||||
|
@ -771,7 +789,7 @@ resources:
|
|||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.man.update_stack,
|
||||
self.ctx, stk.identifier(), template,
|
||||
params, None, {})
|
||||
params, None, {rpc_api.PARAM_CONVERGE: False})
|
||||
self.assertEqual(exception.EntityNotFound, ex.exc_info[0])
|
||||
|
||||
def test_stack_update_no_credentials(self):
|
||||
|
@ -798,7 +816,7 @@ resources:
|
|||
mock_env = self.patchobject(environment, 'Environment',
|
||||
return_value=stk.env)
|
||||
|
||||
api_args = {'timeout_mins': 60}
|
||||
api_args = {'timeout_mins': 60, rpc_api.PARAM_CONVERGE: False}
|
||||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.man.update_stack, self.ctx,
|
||||
stk.identifier(),
|
||||
|
@ -820,14 +838,17 @@ resources:
|
|||
stack_user_project_id='1234',
|
||||
strict_validate=True,
|
||||
tenant_id='test_tenant_id', timeout_mins=60,
|
||||
user_creds_id=u'1', username='test_username')
|
||||
user_creds_id=u'1', username='test_username',
|
||||
converge=False
|
||||
)
|
||||
mock_load.assert_called_once_with(self.ctx, stack=s)
|
||||
|
||||
def test_stack_update_existing_template(self):
|
||||
'''Update a stack using the same template.'''
|
||||
stack_name = 'service_update_test_stack_existing_template'
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True}
|
||||
rpc_api.PARAM_EXISTING: True,
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
t = template_format.parse(tools.wp_template)
|
||||
# Don't actually run the update as the mocking breaks it, instead
|
||||
# we just ensure the expected template is passed in to the updated
|
||||
|
@ -859,7 +880,8 @@ resources:
|
|||
'''Update a stack using the same template doesn't work when FAILED.'''
|
||||
stack_name = 'service_update_test_stack_existing_template'
|
||||
api_args = {rpc_api.PARAM_TIMEOUT: 60,
|
||||
rpc_api.PARAM_EXISTING: True}
|
||||
rpc_api.PARAM_EXISTING: True,
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
t = template_format.parse(tools.wp_template)
|
||||
# Don't actually run the update as the mocking breaks it, instead
|
||||
# we just ensure the expected template is passed in to the updated
|
||||
|
@ -912,7 +934,7 @@ parameters:
|
|||
self.man.update_stack,
|
||||
self.ctx, old_stack.identifier(),
|
||||
old_stack.t.t, params,
|
||||
None, {})
|
||||
None, {rpc_api.PARAM_CONVERGE: False})
|
||||
self.assertEqual(exception.ImmutableParameterModified, exc.exc_info[0])
|
||||
self.assertEqual('The following parameters are immutable and may not '
|
||||
'be updated: param1', exc.exc_info[1].message)
|
||||
|
@ -948,7 +970,7 @@ parameters:
|
|||
params = {'param1': 'bar'}
|
||||
result = self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
templatem.Template(template), params,
|
||||
None, {})
|
||||
None, {rpc_api.PARAM_CONVERGE: False})
|
||||
self.assertEqual(s.id, result['stack_id'])
|
||||
|
||||
def test_update_immutable_parameter_same_value(self):
|
||||
|
@ -982,7 +1004,7 @@ parameters:
|
|||
params = {'param1': 'foo'}
|
||||
result = self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
templatem.Template(template), params,
|
||||
None, {})
|
||||
None, {rpc_api.PARAM_CONVERGE: False})
|
||||
self.assertEqual(s.id, result['stack_id'])
|
||||
|
||||
|
||||
|
@ -1057,7 +1079,7 @@ resources:
|
|||
return_value=None)
|
||||
|
||||
# do preview_update_stack
|
||||
api_args = {'timeout_mins': 60}
|
||||
api_args = {'timeout_mins': 60, rpc_api.PARAM_CONVERGE: False}
|
||||
result = self.man.preview_update_stack(
|
||||
self.ctx,
|
||||
old_stack.identifier(),
|
||||
|
@ -1073,7 +1095,9 @@ resources:
|
|||
disable_rollback=True, nested_depth=0, owner_id=None,
|
||||
parent_resource=None, stack_user_project_id='1234',
|
||||
strict_validate=True, tenant_id='test_tenant_id', timeout_mins=60,
|
||||
user_creds_id=u'1', username='test_username')
|
||||
user_creds_id=u'1', username='test_username',
|
||||
converge=False
|
||||
)
|
||||
mock_load.assert_called_once_with(self.ctx, stack=s)
|
||||
mock_tmpl.assert_called_once_with(new_template, files=None)
|
||||
mock_env.assert_called_once_with(params)
|
||||
|
|
|
@ -29,7 +29,7 @@ from heat.tests import utils
|
|||
class WorkerServiceTest(common.HeatTestCase):
|
||||
def test_make_sure_rpc_version(self):
|
||||
self.assertEqual(
|
||||
'1.3',
|
||||
'1.4',
|
||||
worker.WorkerService.RPC_API_VERSION,
|
||||
('RPC version is changed, please update this test to new version '
|
||||
'and make sure additional test cases are added for RPC APIs '
|
||||
|
|
|
@ -72,7 +72,7 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
|
|||
mock.call.worker_client.WorkerClient.check_resource(
|
||||
stack.context, rsrc_id, stack.current_traversal,
|
||||
{'input_data': {}},
|
||||
is_update, None))
|
||||
is_update, None, False))
|
||||
self.assertEqual(expected_calls, mock_cr.mock_calls)
|
||||
|
||||
def test_conv_string_five_instance_stack_create(self, mock_cr):
|
||||
|
@ -129,7 +129,7 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
|
|||
mock.call.worker_client.WorkerClient.check_resource(
|
||||
stack.context, rsrc_id, stack.current_traversal,
|
||||
{'input_data': {}},
|
||||
is_update, None))
|
||||
is_update, None, False))
|
||||
self.assertEqual(expected_calls, mock_cr.mock_calls)
|
||||
|
||||
def _mock_convg_db_update_requires(self):
|
||||
|
@ -269,7 +269,7 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
|
|||
mock.call.worker_client.WorkerClient.check_resource(
|
||||
stack.context, rsrc_id, stack.current_traversal,
|
||||
{'input_data': {}},
|
||||
is_update, None))
|
||||
is_update, None, False))
|
||||
|
||||
leaves = curr_stack.convergence_dependencies.leaves()
|
||||
for rsrc_id, is_update in leaves:
|
||||
|
@ -277,7 +277,7 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
|
|||
mock.call.worker_client.WorkerClient.check_resource(
|
||||
curr_stack.context, rsrc_id, curr_stack.current_traversal,
|
||||
{'input_data': {}},
|
||||
is_update, None))
|
||||
is_update, None, False))
|
||||
self.assertEqual(expected_calls, mock_cr.mock_calls)
|
||||
|
||||
def test_conv_empty_template_stack_update_delete(self, mock_cr):
|
||||
|
@ -352,7 +352,7 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
|
|||
mock.call.worker_client.WorkerClient.check_resource(
|
||||
stack.context, rsrc_id, stack.current_traversal,
|
||||
{'input_data': {}},
|
||||
is_update, None))
|
||||
is_update, None, False))
|
||||
|
||||
leaves = curr_stack.convergence_dependencies.leaves()
|
||||
for rsrc_id, is_update in leaves:
|
||||
|
@ -360,7 +360,7 @@ class StackConvergenceCreateUpdateDeleteTest(common.HeatTestCase):
|
|||
mock.call.worker_client.WorkerClient.check_resource(
|
||||
curr_stack.context, rsrc_id, curr_stack.current_traversal,
|
||||
{'input_data': {}},
|
||||
is_update, None))
|
||||
is_update, None, False))
|
||||
self.assertEqual(expected_calls, mock_cr.mock_calls)
|
||||
|
||||
def test_mark_complete_purges_db(self, mock_cr):
|
||||
|
|
|
@ -35,6 +35,7 @@ from heat.engine import service
|
|||
from heat.engine import stack as parser
|
||||
from heat.engine import template as templatem
|
||||
from heat.objects import stack as stack_object
|
||||
from heat.rpc import api as rpc_api
|
||||
from heat.tests import common
|
||||
from heat.tests.engine import tools
|
||||
from heat.tests import generic_resource as generic_rsrc
|
||||
|
@ -230,6 +231,7 @@ class StackConvergenceServiceCreateUpdateTest(common.HeatTestCase):
|
|||
template=tools.string_template_five,
|
||||
convergence=True)
|
||||
|
||||
stack.converge = None
|
||||
self.m.StubOutWithMock(templatem, 'Template')
|
||||
self.m.StubOutWithMock(environment, 'Environment')
|
||||
self.m.StubOutWithMock(parser, 'Stack')
|
||||
|
@ -295,14 +297,16 @@ class StackConvergenceServiceCreateUpdateTest(common.HeatTestCase):
|
|||
convergence=old_stack.convergence,
|
||||
current_traversal=old_stack.current_traversal,
|
||||
prev_raw_template_id=old_stack.prev_raw_template_id,
|
||||
current_deps=old_stack.current_deps).AndReturn(stack)
|
||||
current_deps=old_stack.current_deps,
|
||||
converge=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndReturn(None)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
api_args = {'timeout_mins': 60, 'disable_rollback': False}
|
||||
api_args = {'timeout_mins': 60, 'disable_rollback': False,
|
||||
rpc_api.PARAM_CONVERGE: False}
|
||||
result = self.man.update_stack(self.ctx, old_stack.identifier(),
|
||||
template, params, None, api_args)
|
||||
self.assertTrue(old_stack.convergence)
|
||||
|
|
|
@ -32,6 +32,7 @@ from heat.engine import template as templatem
|
|||
from heat.objects import raw_template
|
||||
from heat.objects import stack as stack_object
|
||||
from heat.objects import stack_lock
|
||||
from heat.rpc import api as rpc_api
|
||||
from heat.tests import common
|
||||
from heat.tests import generic_resource as generic_rsrc
|
||||
from heat.tests import utils
|
||||
|
@ -931,9 +932,9 @@ class WithTemplateTest(StackResourceBaseTest):
|
|||
rpcc.return_value._create_stack.assert_called_once_with(
|
||||
self.ctx,
|
||||
stack_name=res_name,
|
||||
args={'disable_rollback': True,
|
||||
'adopt_stack_data': adopt_data_str,
|
||||
'timeout_mins': self.timeout_mins},
|
||||
args={rpc_api.PARAM_DISABLE_ROLLBACK: True,
|
||||
rpc_api.PARAM_ADOPT_STACK_DATA: adopt_data_str,
|
||||
rpc_api.PARAM_TIMEOUT: self.timeout_mins},
|
||||
environment_files=None,
|
||||
stack_user_project_id='aprojectid',
|
||||
parent_resource_name='test',
|
||||
|
@ -980,9 +981,9 @@ class WithTemplateTest(StackResourceBaseTest):
|
|||
rpcc.return_value._create_stack.assert_called_once_with(
|
||||
self.ctx,
|
||||
stack_name=res_name,
|
||||
args={'disable_rollback': True,
|
||||
'adopt_stack_data': adopt_data_str,
|
||||
'timeout_mins': self.timeout_mins},
|
||||
args={rpc_api.PARAM_DISABLE_ROLLBACK: True,
|
||||
rpc_api.PARAM_ADOPT_STACK_DATA: adopt_data_str,
|
||||
rpc_api.PARAM_TIMEOUT: self.timeout_mins},
|
||||
environment_files=None,
|
||||
stack_user_project_id='aprojectid',
|
||||
parent_resource_name='test',
|
||||
|
@ -1025,7 +1026,8 @@ class WithTemplateTest(StackResourceBaseTest):
|
|||
template=None,
|
||||
params=None,
|
||||
files=None,
|
||||
args={'timeout_mins': self.timeout_mins})
|
||||
args={rpc_api.PARAM_TIMEOUT: self.timeout_mins,
|
||||
rpc_api.PARAM_CONVERGE: False})
|
||||
|
||||
def test_update_with_template_failure(self):
|
||||
class StackValidationFailed_Remote(exception.StackValidationFailed):
|
||||
|
@ -1061,7 +1063,8 @@ class WithTemplateTest(StackResourceBaseTest):
|
|||
template=None,
|
||||
params=None,
|
||||
files=None,
|
||||
args={'timeout_mins': self.timeout_mins})
|
||||
args={rpc_api.PARAM_TIMEOUT: self.timeout_mins,
|
||||
rpc_api.PARAM_CONVERGE: False})
|
||||
self.assertIsNotNone(template_id.match)
|
||||
self.assertRaises(exception.NotFound,
|
||||
raw_template.RawTemplate.get_by_id,
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
features:
|
||||
- Add `converge` parameter for stack update (and update preview) API.
|
||||
This parameter will force resources to observe the reality of resources
|
||||
before actually update it. The value of this parameter can be any
|
||||
boolean value. This will replace config flag `observe_on_update` in
|
||||
near future.
|
Loading…
Reference in New Issue