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:
db_stack = self._get_stack(cnxt, stack_identity, show_deleted=True)
stacks = [parser.Stack.load(cnxt, stack=db_stack,
resolve_data=resolve_outputs)]
stacks = [parser.Stack.load(cnxt, stack=db_stack)]
else:
stacks = parser.Stack.load_all(cnxt, resolve_data=resolve_outputs)
stacks = parser.Stack.load_all(cnxt)
return [api.format_stack(
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.
"""
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])
@ -1321,7 +1320,7 @@ class EngineService(service.Service):
:return: dict with output key, value and description in defined format.
"""
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]
@ -1330,9 +1329,6 @@ class EngineService(service.Service):
'found.') % 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)
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,
service_check_defer=True,
resource_validate=False,
resolve_data=False)
resource_validate=False)
LOG.info(_LI('Engine %(engine)s went down when stack '
'%(stack_id)s was in action %(action)s'),
{'engine': engine_id, 'action': stk.action,

View File

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

View File

@ -1027,8 +1027,7 @@ class StackServiceTest(common.HeatTestCase):
t['outputs'] = {'test': {'value': 'first', 'description': 'sec'},
'test2': {'value': 'sec'}}
tmpl = templatem.Template(t)
stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl,
resolve_data=False)
stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl)
self.patchobject(self.eng, '_get_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['outputs'] = {'test': {'value': 'first', 'description': 'sec'}}
tmpl = templatem.Template(t)
stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl,
resolve_data=False)
stack = parser.Stack(self.ctx, 'service_list_outputs_stack', tmpl)
self.patchobject(self.eng, '_get_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,
stack=db_stack,
service_check_defer=True,
resource_validate=False,
resolve_data=False)
resource_validate=False)
self.assertTrue(lock2.release.called)
mock_thread.start_with_acquired_lock.assert_called_once_with(
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,
action=stk.action, status=stk.status,
status_reason=stk.status_reason,
timeout_mins=stk.timeout, resolve_data=True,
timeout_mins=stk.timeout,
disable_rollback=stk.disable_rollback,
parent_resource='parent', owner_id=None,
stack_user_project_id=None,
@ -2717,7 +2717,7 @@ class StackTest(common.HeatTestCase):
mock_dependency.validate.assert_called_once_with()
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)
expected_exception = self.assertRaises(AssertionError, stc.validate)
self.assertEqual(expected_msg, six.text_type(expected_exception))
@ -2727,8 +2727,7 @@ class StackTest(common.HeatTestCase):
expected_message = 'Expected Assertion Error'
tmpl.parse.side_effect = AssertionError(expected_message)
stc = stack.Stack(self.ctx, utils.random_name(),
tmpl, resolve_data=False)
stc = stack.Stack(self.ctx, utils.random_name(), tmpl)
expected_exception = self.assertRaises(AssertionError,
stc.resolve_outputs_data,
None)

View File

@ -320,8 +320,7 @@ class TestTemplateConditionParser(common.HeatTestCase):
{'get_attr': [None, 'att']}]}}}
# test with get_attr in equals
tmpl = template.Template(t)
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl,
resolve_data=False)
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
ex = self.assertRaises(exception.InvalidConditionFunction,
tmpl._resolve_conditions, stk)
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
tmpl.t['conditions']['prod_env'] = {'get_resource': 'R1'}
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl,
resolve_data=False)
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
ex = self.assertRaises(exception.InvalidConditionFunction,
tmpl._resolve_conditions, stk)
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
tmpl.t['conditions']['prod_env'] = {'get_attr': [None, 'att']}
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl,
resolve_data=False)
stk = stack.Stack(self.ctx, 'test_condition_with_get_attr_func', tmpl)
ex = self.assertRaises(exception.InvalidConditionFunction,
tmpl._resolve_conditions, stk)
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):
t = template_format.parse(test_template_invalid_outputs)
template = tmpl.Template(t)
stack = parser.Stack(self.ctx, 'test_stack', template)
err = self.assertRaises(exception.StackValidationFailed,
parser.Stack, self.ctx, 'test_stack', template)
stack.validate)
error_message = ('outputs.string.value.get_attr: Arguments to '
'"get_attr" must be of the form '
'[resource_name, attribute, (path), ...]')