Add converge flag in stack update for observing on reality
Add converge parameter for stack update API and RPC call, that allow triggering observe on reality. This will be triggered by API call with converge argument (with True or False value) within. This flag also works for resources within nested stack. Implements bp get-reality-for-resources Change-Id: I151b575b714dcc9a5971a1573c126152ecd7ea93
This commit is contained in:
parent
d5f78c2b28
commit
552f94b928
@ -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
Block a user