Merge "Lazy-load outputs"
This commit is contained in:
commit
49226daee0
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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), ...]')
|
||||||
|
|
Loading…
Reference in New Issue