Merge "Avoid passing templates/files over RPC"

This commit is contained in:
Jenkins 2016-05-16 23:37:17 +00:00 committed by Gerrit Code Review
commit ec05fc909d
2 changed files with 165 additions and 28 deletions

View File

@ -31,6 +31,7 @@ from heat.engine import resource
from heat.engine import scheduler from heat.engine import scheduler
from heat.engine import stack as parser from heat.engine import stack as parser
from heat.engine import template from heat.engine import template
from heat.objects import raw_template
from heat.objects import stack as stack_object from heat.objects import stack as stack_object
from heat.objects import stack_lock from heat.objects import stack_lock
from heat.rpc import api as rpc_api from heat.rpc import api as rpc_api
@ -266,7 +267,7 @@ class StackResource(resource.Resource):
timeout_mins = self.stack.timeout_mins timeout_mins = self.stack.timeout_mins
stack_user_project_id = self.stack.stack_user_project_id stack_user_project_id = self.stack.stack_user_project_id
kwargs = self._stack_kwargs(user_params, child_template) kwargs = self._stack_kwargs(user_params, child_template, adopt_data)
adopt_data_str = None adopt_data_str = None
if adopt_data is not None: if adopt_data is not None:
@ -293,11 +294,18 @@ class StackResource(resource.Resource):
'parent_resource_name': self.name 'parent_resource_name': self.name
}) })
with self.translate_remote_exceptions: with self.translate_remote_exceptions:
result = self.rpc_client()._create_stack(self.context, **kwargs) result = None
try:
result = self.rpc_client()._create_stack(self.context,
**kwargs)
finally:
if adopt_data is None and not result:
raw_template.RawTemplate.delete(self.context,
kwargs['template_id'])
self.resource_id_set(result['stack_id']) self.resource_id_set(result['stack_id'])
def _stack_kwargs(self, user_params, child_template): def _stack_kwargs(self, user_params, child_template, adopt_data=None):
if user_params is None: if user_params is None:
user_params = self.child_params() user_params = self.child_params()
@ -311,11 +319,20 @@ class StackResource(resource.Resource):
parsed_template = self._child_parsed_template(child_template, parsed_template = self._child_parsed_template(child_template,
child_env) child_env)
return { if adopt_data is None:
'template': parsed_template.t, template_id = parsed_template.store(self.context)
'params': child_env.user_env_as_dict(), return {
'files': parsed_template.files 'template_id': template_id,
} 'template': None,
'params': None,
'files': None,
}
else:
return {
'template': parsed_template.t,
'params': child_env.user_env_as_dict(),
'files': parsed_template.files,
}
def raise_local_exception(self, ex): def raise_local_exception(self, ex):
warnings.warn('raise_local_exception() is deprecated. Use the ' warnings.warn('raise_local_exception() is deprecated. Use the '
@ -439,7 +456,14 @@ class StackResource(resource.Resource):
'args': {rpc_api.PARAM_TIMEOUT: timeout_mins} 'args': {rpc_api.PARAM_TIMEOUT: timeout_mins}
}) })
with self.translate_remote_exceptions: with self.translate_remote_exceptions:
self.rpc_client().update_stack(self.context, **kwargs) result = None
try:
result = self.rpc_client()._update_stack(self.context,
**kwargs)
finally:
if not result:
raw_template.RawTemplate.delete(self.context,
kwargs['template_id'])
return cookie return cookie
def check_update_complete(self, cookie=None): def check_update_complete(self, cookie=None):

View File

@ -25,6 +25,7 @@ from heat.common import template_format
from heat.engine.resources import stack_resource from heat.engine.resources import stack_resource
from heat.engine import stack as parser from heat.engine import stack as parser
from heat.engine import template as templatem 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 as stack_object
from heat.objects import stack_lock from heat.objects import stack_lock
from heat.tests import common from heat.tests import common
@ -826,6 +827,16 @@ class WithTemplateTest(StackResourceBaseTest):
adopt_data={'template': 'foo', 'environment': 'eee'})), adopt_data={'template': 'foo', 'environment': 'eee'})),
] ]
class IntegerMatch(object):
def __eq__(self, other):
if getattr(self, 'match', None) is not None:
return other == self.match
if not isinstance(other, six.integer_types):
return False
self.match = other
return True
def test_create_with_template(self): def test_create_with_template(self):
child_env = {'parameter_defaults': {}, child_env = {'parameter_defaults': {},
'event_sinks': [], 'event_sinks': [],
@ -841,15 +852,24 @@ class WithTemplateTest(StackResourceBaseTest):
self.parent_resource.create_with_template( self.parent_resource.create_with_template(
self.empty_temp, user_params=self.params, self.empty_temp, user_params=self.params,
timeout_mins=self.timeout_mins, adopt_data=self.adopt_data) timeout_mins=self.timeout_mins, adopt_data=self.adopt_data)
adopt_data_str = None if self.adopt_data is not None:
if self.adopt_data:
adopt_data_str = json.dumps(self.adopt_data) adopt_data_str = json.dumps(self.adopt_data)
tmpl_args = {
'template': self.empty_temp.t,
'params': child_env,
'files': {},
}
else:
adopt_data_str = None
tmpl_args = {
'template_id': self.IntegerMatch(),
'template': None,
'params': None,
'files': None,
}
rpcc.return_value._create_stack.assert_called_once_with( rpcc.return_value._create_stack.assert_called_once_with(
self.ctx, self.ctx,
stack_name=res_name, stack_name=res_name,
template=self.empty_temp.t,
params=child_env,
files={},
args={'disable_rollback': True, args={'disable_rollback': True,
'adopt_stack_data': adopt_data_str, 'adopt_stack_data': adopt_data_str,
'timeout_mins': self.timeout_mins}, 'timeout_mins': self.timeout_mins},
@ -858,16 +878,12 @@ class WithTemplateTest(StackResourceBaseTest):
parent_resource_name='test', parent_resource_name='test',
user_creds_id='uc123', user_creds_id='uc123',
owner_id=self.parent_stack.id, owner_id=self.parent_stack.id,
nested_depth=1) nested_depth=1,
**tmpl_args)
def test_update_with_template(self): def test_create_with_template_failure(self):
nested = mock.MagicMock() class StackValidationFailed_Remote(exception.StackValidationFailed):
nested.updated_time = 'now_time' pass
nested.state = ('CREATE', 'COMPLETE')
nested.identifier.return_value = {'stack_identifier':
'stack-identifier'}
self.parent_resource.nested = mock.MagicMock(return_value=nested)
self.parent_resource._nested = nested
child_env = {'parameter_defaults': {}, child_env = {'parameter_defaults': {},
'event_sinks': [], 'event_sinks': [],
@ -876,20 +892,117 @@ class WithTemplateTest(StackResourceBaseTest):
'encrypted_param_names': []} 'encrypted_param_names': []}
self.parent_resource.child_params = mock.Mock( self.parent_resource.child_params = mock.Mock(
return_value=self.params) return_value=self.params)
res_name = self.parent_resource.physical_resource_name()
rpcc = mock.Mock() rpcc = mock.Mock()
self.parent_resource.rpc_client = rpcc self.parent_resource.rpc_client = rpcc
rpcc.return_value._create_stack.return_value = {'stack_id': 'pancakes'} remote_exc = StackValidationFailed_Remote(message='oops')
rpcc.return_value._create_stack.side_effect = remote_exc
self.assertRaises(exception.ResourceFailure,
self.parent_resource.create_with_template,
self.empty_temp, user_params=self.params,
timeout_mins=self.timeout_mins,
adopt_data=self.adopt_data)
if self.adopt_data is not None:
adopt_data_str = json.dumps(self.adopt_data)
tmpl_args = {
'template': self.empty_temp.t,
'params': child_env,
'files': {},
}
else:
adopt_data_str = None
tmpl_args = {
'template_id': self.IntegerMatch(),
'template': None,
'params': None,
'files': None,
}
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},
environment_files=None,
stack_user_project_id='aprojectid',
parent_resource_name='test',
user_creds_id='uc123',
owner_id=self.parent_stack.id,
nested_depth=1,
**tmpl_args)
if self.adopt_data is None:
stored_tmpl_id = tmpl_args['template_id'].match
self.assertIsNotNone(stored_tmpl_id)
self.assertRaises(exception.NotFound,
raw_template.RawTemplate.get_by_id,
self.ctx, stored_tmpl_id)
def test_update_with_template(self):
if self.adopt_data is not None:
return
nested = mock.MagicMock()
nested.updated_time = 'now_time'
nested.state = ('CREATE', 'COMPLETE')
nested.identifier.return_value = {'stack_identifier':
'stack-identifier'}
self.parent_resource.nested = mock.MagicMock(return_value=nested)
self.parent_resource._nested = nested
self.parent_resource.child_params = mock.Mock(
return_value=self.params)
rpcc = mock.Mock()
self.parent_resource.rpc_client = rpcc
rpcc.return_value._update_stack.return_value = {'stack_id': 'pancakes'}
self.parent_resource.update_with_template( self.parent_resource.update_with_template(
self.empty_temp, user_params=self.params, self.empty_temp, user_params=self.params,
timeout_mins=self.timeout_mins) timeout_mins=self.timeout_mins)
rpcc.return_value.update_stack.assert_called_once_with( rpcc.return_value._update_stack.assert_called_once_with(
self.ctx, self.ctx,
stack_identity={'stack_identifier': 'stack-identifier'}, stack_identity={'stack_identifier': 'stack-identifier'},
template=self.empty_temp.t, template_id=self.IntegerMatch(),
params=child_env, template=None,
files={}, params=None,
files=None,
args={'timeout_mins': self.timeout_mins}) args={'timeout_mins': self.timeout_mins})
def test_update_with_template_failure(self):
class StackValidationFailed_Remote(exception.StackValidationFailed):
pass
if self.adopt_data is not None:
return
nested = mock.MagicMock()
nested.updated_time = 'now_time'
nested.state = ('CREATE', 'COMPLETE')
nested.identifier.return_value = {'stack_identifier':
'stack-identifier'}
self.parent_resource.nested = mock.MagicMock(return_value=nested)
self.parent_resource._nested = nested
self.parent_resource.child_params = mock.Mock(
return_value=self.params)
rpcc = mock.Mock()
self.parent_resource.rpc_client = rpcc
remote_exc = StackValidationFailed_Remote(message='oops')
rpcc.return_value._update_stack.side_effect = remote_exc
self.assertRaises(exception.ResourceFailure,
self.parent_resource.update_with_template,
self.empty_temp, user_params=self.params,
timeout_mins=self.timeout_mins)
template_id = self.IntegerMatch()
rpcc.return_value._update_stack.assert_called_once_with(
self.ctx,
stack_identity={'stack_identifier': 'stack-identifier'},
template_id=template_id,
template=None,
params=None,
files=None,
args={'timeout_mins': self.timeout_mins})
self.assertIsNotNone(template_id.match)
self.assertRaises(exception.NotFound,
raw_template.RawTemplate.get_by_id,
self.ctx, template_id.match)
class RaiseLocalException(StackResourceBaseTest): class RaiseLocalException(StackResourceBaseTest):