Merge "Lazy-load outputs"

This commit is contained in:
Jenkins 2016-09-07 00:21:57 +00:00 committed by Gerrit Code Review
commit 49226daee0
6 changed files with 31 additions and 43 deletions

View File

@ -510,10 +510,9 @@ class EngineService(service.Service):
""" """
if stack_identity is not None: if stack_identity is not None:
db_stack = self._get_stack(cnxt, stack_identity, show_deleted=True) db_stack = self._get_stack(cnxt, stack_identity, show_deleted=True)
stacks = [parser.Stack.load(cnxt, stack=db_stack, stacks = [parser.Stack.load(cnxt, stack=db_stack)]
resolve_data=resolve_outputs)]
else: else:
stacks = parser.Stack.load_all(cnxt, resolve_data=resolve_outputs) stacks = parser.Stack.load_all(cnxt)
return [api.format_stack( return [api.format_stack(
stack, resolve_outputs=resolve_outputs) for stack in stacks] stack, resolve_outputs=resolve_outputs) for stack in stacks]
@ -1307,7 +1306,7 @@ class EngineService(service.Service):
:return: list of stack outputs in defined format. :return: list of stack outputs in defined format.
""" """
s = self._get_stack(cntx, stack_identity) s = self._get_stack(cntx, stack_identity)
stack = parser.Stack.load(cntx, stack=s, resolve_data=False) stack = parser.Stack.load(cntx, stack=s)
return api.format_stack_outputs(stack, stack.t[stack.t.OUTPUTS]) return api.format_stack_outputs(stack, stack.t[stack.t.OUTPUTS])
@ -1321,7 +1320,7 @@ class EngineService(service.Service):
:return: dict with output key, value and description in defined format. :return: dict with output key, value and description in defined format.
""" """
s = self._get_stack(cntx, stack_identity) s = self._get_stack(cntx, stack_identity)
stack = parser.Stack.load(cntx, stack=s, resolve_data=False) stack = parser.Stack.load(cntx, stack=s)
outputs = stack.t[stack.t.OUTPUTS] outputs = stack.t[stack.t.OUTPUTS]
@ -1330,9 +1329,6 @@ class EngineService(service.Service):
'found.') % output_key) 'found.') % output_key)
output = stack.resolve_outputs_data({output_key: outputs[output_key]}) output = stack.resolve_outputs_data({output_key: outputs[output_key]})
if not stack.outputs:
stack.outputs.update(output)
return api.format_stack_output(stack, output, output_key) return api.format_stack_output(stack, output, output_key)
def _remote_call(self, cnxt, lock_engine_id, call, **kwargs): def _remote_call(self, cnxt, lock_engine_id, call, **kwargs):
@ -2332,8 +2328,7 @@ class EngineService(service.Service):
stk = parser.Stack.load(cnxt, stack=s, stk = parser.Stack.load(cnxt, stack=s,
service_check_defer=True, service_check_defer=True,
resource_validate=False, resource_validate=False)
resolve_data=False)
LOG.info(_LI('Engine %(engine)s went down when stack ' LOG.info(_LI('Engine %(engine)s went down when stack '
'%(stack_id)s was in action %(action)s'), '%(stack_id)s was in action %(action)s'),
{'engine': engine_id, 'action': stk.action, {'engine': engine_id, 'action': stk.action,

View File

@ -118,7 +118,7 @@ class Stack(collections.Mapping):
def __init__(self, context, stack_name, tmpl, def __init__(self, context, stack_name, tmpl,
stack_id=None, action=None, status=None, stack_id=None, action=None, status=None,
status_reason='', timeout_mins=None, resolve_data=True, status_reason='', timeout_mins=None,
disable_rollback=True, parent_resource=None, owner_id=None, disable_rollback=True, parent_resource=None, owner_id=None,
adopt_stack_data=None, stack_user_project_id=None, adopt_stack_data=None, stack_user_project_id=None,
created_time=None, updated_time=None, created_time=None, updated_time=None,
@ -168,6 +168,7 @@ class Stack(collections.Mapping):
self.disable_rollback = disable_rollback self.disable_rollback = disable_rollback
self.parent_resource_name = parent_resource self.parent_resource_name = parent_resource
self._parent_stack = None self._parent_stack = None
self._outputs = None
self._resources = None self._resources = None
self._dependencies = None self._dependencies = None
self._access_allowed_handlers = {} self._access_allowed_handlers = {}
@ -227,12 +228,6 @@ class Stack(collections.Mapping):
param_defaults=self.env.param_defaults) param_defaults=self.env.param_defaults)
self._set_param_stackid() self._set_param_stackid()
if resolve_data:
self.outputs = self.resolve_outputs_data(
self.t[self.t.OUTPUTS], path=self.t.OUTPUTS)
else:
self.outputs = {}
@property @property
def tags(self): def tags(self):
if self._tags is None: if self._tags is None:
@ -299,6 +294,13 @@ class Stack(collections.Mapping):
msg = _("Attempt to use stored_context with no user_creds") msg = _("Attempt to use stored_context with no user_creds")
raise exception.Error(msg) raise exception.Error(msg)
@property
def outputs(self):
if self._outputs is None:
self._outputs = self.resolve_outputs_data(self.t[self.t.OUTPUTS],
path=self.t.OUTPUTS)
return self._outputs
@property @property
def resources(self): def resources(self):
if self._resources is None: if self._resources is None:
@ -484,7 +486,7 @@ class Stack(collections.Mapping):
@classmethod @classmethod
def load(cls, context, stack_id=None, stack=None, show_deleted=True, def load(cls, context, stack_id=None, stack=None, show_deleted=True,
use_stored_context=False, force_reload=False, cache_data=None, use_stored_context=False, force_reload=False, cache_data=None,
resolve_data=True, service_check_defer=False, service_check_defer=False,
resource_validate=True): resource_validate=True):
"""Retrieve a Stack from the database.""" """Retrieve a Stack from the database."""
if stack is None: if stack is None:
@ -501,14 +503,14 @@ class Stack(collections.Mapping):
return cls._from_db(context, stack, return cls._from_db(context, stack,
use_stored_context=use_stored_context, use_stored_context=use_stored_context,
cache_data=cache_data, resolve_data=resolve_data, cache_data=cache_data,
service_check_defer=service_check_defer, service_check_defer=service_check_defer,
resource_validate=resource_validate) resource_validate=resource_validate)
@classmethod @classmethod
def load_all(cls, context, limit=None, marker=None, sort_keys=None, def load_all(cls, context, limit=None, marker=None, sort_keys=None,
sort_dir=None, filters=None, sort_dir=None, filters=None,
show_deleted=False, resolve_data=True, show_deleted=False,
show_nested=False, show_hidden=False, tags=None, show_nested=False, show_hidden=False, tags=None,
tags_any=None, not_tags=None, not_tags_any=None): tags_any=None, not_tags=None, not_tags_any=None):
stacks = stack_object.Stack.get_all( stacks = stack_object.Stack.get_all(
@ -527,14 +529,14 @@ class Stack(collections.Mapping):
not_tags_any=not_tags_any) not_tags_any=not_tags_any)
for stack in stacks: for stack in stacks:
try: try:
yield cls._from_db(context, stack, resolve_data=resolve_data) yield cls._from_db(context, stack)
except exception.NotFound: except exception.NotFound:
# We're in a different transaction than the get_all, so a stack # We're in a different transaction than the get_all, so a stack
# returned above can be deleted by the time we try to load it. # returned above can be deleted by the time we try to load it.
pass pass
@classmethod @classmethod
def _from_db(cls, context, stack, resolve_data=True, def _from_db(cls, context, stack,
use_stored_context=False, cache_data=None, use_stored_context=False, cache_data=None,
service_check_defer=False, resource_validate=True): service_check_defer=False, resource_validate=True):
template = tmpl.Template.load( template = tmpl.Template.load(
@ -544,7 +546,6 @@ class Stack(collections.Mapping):
action=stack.action, status=stack.status, action=stack.action, status=stack.status,
status_reason=stack.status_reason, status_reason=stack.status_reason,
timeout_mins=stack.timeout, timeout_mins=stack.timeout,
resolve_data=resolve_data,
disable_rollback=stack.disable_rollback, disable_rollback=stack.disable_rollback,
parent_resource=stack.parent_resource_name, parent_resource=stack.parent_resource_name,
owner_id=stack.owner_id, owner_id=stack.owner_id,
@ -1517,9 +1518,7 @@ class Stack(collections.Mapping):
# flip the template to the newstack values # flip the template to the newstack values
previous_template_id = self.t.id previous_template_id = self.t.id
self.t = newstack.t self.t = newstack.t
template_outputs = self.t[self.t.OUTPUTS] self._outputs = None
self.outputs = self.resolve_outputs_data(
template_outputs, path=self.t.OUTPUTS)
finally: finally:
if should_rollback: if should_rollback:
# Already handled in rollback task # Already handled in rollback task

View File

@ -1027,8 +1027,7 @@ class StackServiceTest(common.HeatTestCase):
t['outputs'] = {'test': {'value': 'first', 'description': 'sec'}, t['outputs'] = {'test': {'value': 'first', 'description': 'sec'},
'test2': {'value': 'sec'}} 'test2': {'value': 'sec'}}
tmpl = templatem.Template(t) tmpl = templatem.Template(t)
stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl, stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl)
resolve_data=False)
self.patchobject(self.eng, '_get_stack') self.patchobject(self.eng, '_get_stack')
self.patchobject(parser.Stack, 'load', return_value=stack) self.patchobject(parser.Stack, 'load', return_value=stack)
@ -1050,8 +1049,7 @@ class StackServiceTest(common.HeatTestCase):
t = template_format.parse(tools.wp_template) t = template_format.parse(tools.wp_template)
t['outputs'] = {'test': {'value': 'first', 'description': 'sec'}} t['outputs'] = {'test': {'value': 'first', 'description': 'sec'}}
tmpl = templatem.Template(t) tmpl = templatem.Template(t)
stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl, stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl)
resolve_data=False)
self.patchobject(self.eng, '_get_stack') self.patchobject(self.eng, '_get_stack')
self.patchobject(parser.Stack, 'load', return_value=stack) self.patchobject(parser.Stack, 'load', return_value=stack)
@ -1311,8 +1309,7 @@ class StackServiceTest(common.HeatTestCase):
mock_stack_load.assert_called_once_with(self.ctx, mock_stack_load.assert_called_once_with(self.ctx,
stack=db_stack, stack=db_stack,
service_check_defer=True, service_check_defer=True,
resource_validate=False, resource_validate=False)
resolve_data=False)
self.assertTrue(lock2.release.called) self.assertTrue(lock2.release.called)
mock_thread.start_with_acquired_lock.assert_called_once_with( mock_thread.start_with_acquired_lock.assert_called_once_with(
fake_stack, lock1, fake_stack, lock1,

View File

@ -425,7 +425,7 @@ class StackTest(common.HeatTestCase):
stack.Stack.__init__(self.ctx, stk.name, t, stack_id=stk.id, stack.Stack.__init__(self.ctx, stk.name, t, stack_id=stk.id,
action=stk.action, status=stk.status, action=stk.action, status=stk.status,
status_reason=stk.status_reason, status_reason=stk.status_reason,
timeout_mins=stk.timeout, resolve_data=True, timeout_mins=stk.timeout,
disable_rollback=stk.disable_rollback, disable_rollback=stk.disable_rollback,
parent_resource='parent', owner_id=None, parent_resource='parent', owner_id=None,
stack_user_project_id=None, stack_user_project_id=None,
@ -2717,7 +2717,7 @@ class StackTest(common.HeatTestCase):
mock_dependency.validate.assert_called_once_with() mock_dependency.validate.assert_called_once_with()
stc = stack.Stack(self.ctx, utils.random_name(), self.tmpl) stc = stack.Stack(self.ctx, utils.random_name(), self.tmpl)
stc.outputs = {'foo': {'Value': 'bar'}} stc._outputs = {'foo': {'Value': 'bar'}}
func_val.side_effect = AssertionError(expected_msg) func_val.side_effect = AssertionError(expected_msg)
expected_exception = self.assertRaises(AssertionError, stc.validate) expected_exception = self.assertRaises(AssertionError, stc.validate)
self.assertEqual(expected_msg, six.text_type(expected_exception)) self.assertEqual(expected_msg, six.text_type(expected_exception))
@ -2727,8 +2727,7 @@ class StackTest(common.HeatTestCase):
expected_message = 'Expected Assertion Error' expected_message = 'Expected Assertion Error'
tmpl.parse.side_effect = AssertionError(expected_message) tmpl.parse.side_effect = AssertionError(expected_message)
stc = stack.Stack(self.ctx, utils.random_name(), stc = stack.Stack(self.ctx, utils.random_name(), tmpl)
tmpl, resolve_data=False)
expected_exception = self.assertRaises(AssertionError, expected_exception = self.assertRaises(AssertionError,
stc.resolve_outputs_data, stc.resolve_outputs_data,
None) None)

View File

@ -320,8 +320,7 @@ class TestTemplateConditionParser(common.HeatTestCase):
{'get_attr': [None, 'att']}]}}} {'get_attr': [None, 'att']}]}}}
# test with get_attr in equals # test with get_attr in equals
tmpl = template.Template(t) tmpl = template.Template(t)
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl, stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
resolve_data=False)
ex = self.assertRaises(exception.InvalidConditionFunction, ex = self.assertRaises(exception.InvalidConditionFunction,
tmpl._resolve_conditions, stk) tmpl._resolve_conditions, stk)
self.assertIn('The function is not supported in condition: get_attr', self.assertIn('The function is not supported in condition: get_attr',
@ -329,8 +328,7 @@ class TestTemplateConditionParser(common.HeatTestCase):
# test with get_resource in top level of a condition # test with get_resource in top level of a condition
tmpl.t['conditions']['prod_env'] = {'get_resource': 'R1'} tmpl.t['conditions']['prod_env'] = {'get_resource': 'R1'}
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl, stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
resolve_data=False)
ex = self.assertRaises(exception.InvalidConditionFunction, ex = self.assertRaises(exception.InvalidConditionFunction,
tmpl._resolve_conditions, stk) tmpl._resolve_conditions, stk)
self.assertIn('The function is not supported in condition: ' self.assertIn('The function is not supported in condition: '
@ -338,8 +336,7 @@ class TestTemplateConditionParser(common.HeatTestCase):
# test with get_attr in top level of a condition # test with get_attr in top level of a condition
tmpl.t['conditions']['prod_env'] = {'get_attr': [None, 'att']} tmpl.t['conditions']['prod_env'] = {'get_attr': [None, 'att']}
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl, stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
resolve_data=False)
ex = self.assertRaises(exception.InvalidConditionFunction, ex = self.assertRaises(exception.InvalidConditionFunction,
tmpl._resolve_conditions, stk) tmpl._resolve_conditions, stk)
self.assertIn('The function is not supported in condition: get_attr', self.assertIn('The function is not supported in condition: get_attr',

View File

@ -1622,8 +1622,9 @@ class ValidateTest(common.HeatTestCase):
def test_validate_invalid_outputs(self): def test_validate_invalid_outputs(self):
t = template_format.parse(test_template_invalid_outputs) t = template_format.parse(test_template_invalid_outputs)
template = tmpl.Template(t) template = tmpl.Template(t)
stack = parser.Stack(self.ctx, 'test_stack', template)
err = self.assertRaises(exception.StackValidationFailed, err = self.assertRaises(exception.StackValidationFailed,
parser.Stack, self.ctx, 'test_stack', template) stack.validate)
error_message = ('outputs.string.value.get_attr: Arguments to ' error_message = ('outputs.string.value.get_attr: Arguments to '
'"get_attr" must be of the form ' '"get_attr" must be of the form '
'[resource_name, attribute, (path), ...]') '[resource_name, attribute, (path), ...]')