Merge "Load resources from DB for resource list"
This commit is contained in:
commit
d850605da3
|
@ -641,7 +641,12 @@ class Resource(object):
|
||||||
Returns a list of names of resources that depend on this resource
|
Returns a list of names of resources that depend on this resource
|
||||||
directly.
|
directly.
|
||||||
"""
|
"""
|
||||||
return [r.name for r in self.stack.dependencies.required_by(self)]
|
try:
|
||||||
|
return [r.name for r in self.stack.dependencies.required_by(self)]
|
||||||
|
except KeyError:
|
||||||
|
# for convergence, fall back to building from needed_by
|
||||||
|
return [r.name for r in self.stack.resources.values()
|
||||||
|
if r.id in self.needed_by]
|
||||||
|
|
||||||
def client(self, name=None, version=None):
|
def client(self, name=None, version=None):
|
||||||
client_name = name or self.default_client_name
|
client_name = name or self.default_client_name
|
||||||
|
|
|
@ -314,21 +314,21 @@ class Stack(collections.Mapping):
|
||||||
return self._resources
|
return self._resources
|
||||||
|
|
||||||
def _find_filtered_resources(self, filters):
|
def _find_filtered_resources(self, filters):
|
||||||
for rsc in six.itervalues(
|
template_cache = {self.t.id: self.t}
|
||||||
resource_objects.Resource.get_all_by_stack(
|
if filters:
|
||||||
self.context, self.id, filters)):
|
resources = resource_objects.Resource.get_all_by_stack(
|
||||||
yield self.resources[rsc.name]
|
self.context, self.id, filters)
|
||||||
|
else:
|
||||||
|
resources = self._db_resources_get()
|
||||||
|
for rsc in six.itervalues(resources):
|
||||||
|
yield self._resource_from_db_resource(rsc, template_cache)
|
||||||
|
|
||||||
def iter_resources(self, nested_depth=0, filters=None):
|
def iter_resources(self, nested_depth=0, filters=None):
|
||||||
"""Iterates over all the resources in a stack.
|
"""Iterates over all the resources in a stack.
|
||||||
|
|
||||||
Iterating includes nested stacks up to `nested_depth` levels below.
|
Iterating includes nested stacks up to `nested_depth` levels below.
|
||||||
"""
|
"""
|
||||||
if not filters:
|
for res in self._find_filtered_resources(filters):
|
||||||
resources = six.itervalues(self.resources)
|
|
||||||
else:
|
|
||||||
resources = self._find_filtered_resources(filters)
|
|
||||||
for res in resources:
|
|
||||||
yield res
|
yield res
|
||||||
|
|
||||||
for res in six.itervalues(self.resources):
|
for res in six.itervalues(self.resources):
|
||||||
|
@ -350,20 +350,27 @@ class Stack(collections.Mapping):
|
||||||
def db_resource_get(self, name):
|
def db_resource_get(self, name):
|
||||||
if not self.id:
|
if not self.id:
|
||||||
return None
|
return None
|
||||||
|
return self._db_resources_get().get(name)
|
||||||
|
|
||||||
|
def _db_resources_get(self):
|
||||||
if self._db_resources is None:
|
if self._db_resources is None:
|
||||||
_db_resources = resource_objects.Resource.get_all_by_stack(
|
_db_resources = resource_objects.Resource.get_all_by_stack(
|
||||||
self.context, self.id)
|
self.context, self.id)
|
||||||
if not _db_resources:
|
if not _db_resources:
|
||||||
return None
|
return {}
|
||||||
self._db_resources = _db_resources
|
self._db_resources = _db_resources
|
||||||
return self._db_resources.get(name)
|
return self._db_resources
|
||||||
|
|
||||||
def _resource_from_db_resource(self, db_res):
|
def _resource_from_db_resource(self, db_res, template_cache=None):
|
||||||
tid = db_res.current_template_id
|
tid = db_res.current_template_id
|
||||||
if tid == self.t.id:
|
if tid is None or tid == self.t.id:
|
||||||
t = self.t
|
t = self.t
|
||||||
|
elif template_cache and tid in template_cache:
|
||||||
|
t = template_cache[tid]
|
||||||
else:
|
else:
|
||||||
t = tmpl.Template.load(self.context, tid)
|
t = tmpl.Template.load(self.context, tid)
|
||||||
|
if template_cache:
|
||||||
|
template_cache[tid] = t
|
||||||
|
|
||||||
res_defn = t.resource_definitions(self)[db_res.name]
|
res_defn = t.resource_definitions(self)[db_res.name]
|
||||||
return resource.Resource(db_res.name, res_defn, self)
|
return resource.Resource(db_res.name, res_defn, self)
|
||||||
|
|
|
@ -298,11 +298,7 @@ class StackResourcesServiceTest(common.HeatTestCase):
|
||||||
mock_load.return_value = stk
|
mock_load.return_value = stk
|
||||||
tools.clean_up_stack(stk)
|
tools.clean_up_stack(stk)
|
||||||
resources = self.eng.list_stack_resources(self.ctx, stack_id)
|
resources = self.eng.list_stack_resources(self.ctx, stack_id)
|
||||||
self.assertEqual(1, len(resources))
|
self.assertEqual(0, len(resources))
|
||||||
|
|
||||||
res = resources[0]
|
|
||||||
self.assertEqual('DELETE', res['resource_action'])
|
|
||||||
self.assertEqual('COMPLETE', res['resource_status'])
|
|
||||||
|
|
||||||
@mock.patch.object(service.EngineService, '_get_stack')
|
@mock.patch.object(service.EngineService, '_get_stack')
|
||||||
def test_stack_resources_list_nonexist_stack(self, mock_get):
|
def test_stack_resources_list_nonexist_stack(self, mock_get):
|
||||||
|
|
|
@ -264,7 +264,37 @@ class StackTest(common.HeatTestCase):
|
||||||
self.assertEqual('B', self.stack.resource_get('B').name)
|
self.assertEqual('B', self.stack.resource_get('B').name)
|
||||||
self.assertIsNone(self.stack.resource_get('C'))
|
self.assertIsNone(self.stack.resource_get('C'))
|
||||||
|
|
||||||
def test_iter_resources_with_nested(self):
|
@mock.patch.object(resource_objects.Resource, 'get_all_by_stack')
|
||||||
|
def test_iter_resources(self, mock_db_call):
|
||||||
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
|
'Resources':
|
||||||
|
{'A': {'Type': 'GenericResourceType'},
|
||||||
|
'B': {'Type': 'GenericResourceType'}}}
|
||||||
|
self.stack = stack.Stack(self.ctx, 'test_stack',
|
||||||
|
template.Template(tpl),
|
||||||
|
status_reason='blarg')
|
||||||
|
self.stack.store()
|
||||||
|
|
||||||
|
mock_rsc_a = mock.MagicMock(current_template_id=self.stack.t.id)
|
||||||
|
mock_rsc_a.name = 'A'
|
||||||
|
mock_rsc_b = mock.MagicMock(current_template_id=self.stack.t.id)
|
||||||
|
mock_rsc_b.name = 'B'
|
||||||
|
mock_db_call.return_value = {
|
||||||
|
'A': mock_rsc_a,
|
||||||
|
'B': mock_rsc_b
|
||||||
|
}
|
||||||
|
|
||||||
|
all_resources = list(self.stack.iter_resources())
|
||||||
|
|
||||||
|
# Verify, the db query is called with expected filter
|
||||||
|
mock_db_call.assert_called_once_with(self.ctx, self.stack.id)
|
||||||
|
|
||||||
|
# And returns the resources
|
||||||
|
names = sorted([r.name for r in all_resources])
|
||||||
|
self.assertEqual(['A', 'B'], names)
|
||||||
|
|
||||||
|
@mock.patch.object(resource_objects.Resource, 'get_all_by_stack')
|
||||||
|
def test_iter_resources_with_nested(self, mock_db_call):
|
||||||
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
'Resources':
|
'Resources':
|
||||||
{'A': {'Type': 'StackResourceType'},
|
{'A': {'Type': 'StackResourceType'},
|
||||||
|
@ -273,6 +303,17 @@ class StackTest(common.HeatTestCase):
|
||||||
template.Template(tpl),
|
template.Template(tpl),
|
||||||
status_reason='blarg')
|
status_reason='blarg')
|
||||||
|
|
||||||
|
self.stack.store()
|
||||||
|
|
||||||
|
mock_rsc_a = mock.MagicMock(current_template_id=self.stack.t.id)
|
||||||
|
mock_rsc_a.name = 'A'
|
||||||
|
mock_rsc_b = mock.MagicMock(current_template_id=self.stack.t.id)
|
||||||
|
mock_rsc_b.name = 'B'
|
||||||
|
mock_db_call.return_value = {
|
||||||
|
'A': mock_rsc_a,
|
||||||
|
'B': mock_rsc_b
|
||||||
|
}
|
||||||
|
|
||||||
def get_more(nested_depth=0, filters=None):
|
def get_more(nested_depth=0, filters=None):
|
||||||
yield 'X'
|
yield 'X'
|
||||||
yield 'Y'
|
yield 'Y'
|
||||||
|
@ -291,28 +332,31 @@ class StackTest(common.HeatTestCase):
|
||||||
self.assertEqual(5, len(all_resources))
|
self.assertEqual(5, len(all_resources))
|
||||||
|
|
||||||
@mock.patch.object(resource_objects.Resource, 'get_all_by_stack')
|
@mock.patch.object(resource_objects.Resource, 'get_all_by_stack')
|
||||||
@mock.patch('heat.engine.resource.Resource')
|
def test_iter_resources_with_filters(self, mock_db_call):
|
||||||
def test_iter_resources_with_filters(self, mock_resource, mock_db_call):
|
|
||||||
mock_rsc = mock.MagicMock()
|
|
||||||
mock_rsc.name = 'A'
|
|
||||||
mock_db_call.return_value = {'A': mock_rsc}
|
|
||||||
mock_resource.return_value = mock_rsc
|
|
||||||
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
'Resources':
|
'Resources':
|
||||||
{'A': {'Type': 'StackResourceType'},
|
{'A': {'Type': 'GenericResourceType'},
|
||||||
'B': {'Type': 'GenericResourceType'}}}
|
'B': {'Type': 'GenericResourceType'}}}
|
||||||
self.stack = stack.Stack(self.ctx, 'test_stack',
|
self.stack = stack.Stack(self.ctx, 'test_stack',
|
||||||
template.Template(tpl),
|
template.Template(tpl),
|
||||||
status_reason='blarg')
|
status_reason='blarg')
|
||||||
|
self.stack.store()
|
||||||
|
|
||||||
|
mock_rsc = mock.MagicMock()
|
||||||
|
mock_rsc.name = 'A'
|
||||||
|
mock_rsc.current_template_id = self.stack.t.id
|
||||||
|
mock_db_call.return_value = {'A': mock_rsc}
|
||||||
|
|
||||||
all_resources = list(self.stack.iter_resources(
|
all_resources = list(self.stack.iter_resources(
|
||||||
filters=dict(name=['A'])
|
filters=dict(name=['A'])
|
||||||
))
|
))
|
||||||
|
|
||||||
# Verify, the db query is called with expected filter
|
# Verify, the db query is called with expected filter
|
||||||
mock_db_call.assert_called_once_with(self.ctx,
|
mock_db_call.assert_has_calls([
|
||||||
self.stack.id,
|
mock.call(self.ctx, self.stack.id, dict(name=['A'])),
|
||||||
dict(name=['A']))
|
mock.call(self.ctx, self.stack.id),
|
||||||
|
])
|
||||||
|
|
||||||
# Make sure it returns only one resource.
|
# Make sure it returns only one resource.
|
||||||
self.assertEqual(1, len(all_resources))
|
self.assertEqual(1, len(all_resources))
|
||||||
|
|
||||||
|
@ -320,13 +364,7 @@ class StackTest(common.HeatTestCase):
|
||||||
self.assertEqual('A', all_resources[0].name)
|
self.assertEqual('A', all_resources[0].name)
|
||||||
|
|
||||||
@mock.patch.object(resource_objects.Resource, 'get_all_by_stack')
|
@mock.patch.object(resource_objects.Resource, 'get_all_by_stack')
|
||||||
@mock.patch('heat.engine.resource.Resource')
|
def test_iter_resources_nested_with_filters(self, mock_db_call):
|
||||||
def test_iter_resources_nested_with_filters(self, mock_resource,
|
|
||||||
mock_db_call):
|
|
||||||
mock_rsc = mock.Mock()
|
|
||||||
mock_rsc.name = 'A'
|
|
||||||
mock_db_call.return_value = {'A': mock_rsc}
|
|
||||||
mock_resource.return_value = mock_rsc
|
|
||||||
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
||||||
'Resources':
|
'Resources':
|
||||||
{'A': {'Type': 'StackResourceType'},
|
{'A': {'Type': 'StackResourceType'},
|
||||||
|
@ -335,6 +373,17 @@ class StackTest(common.HeatTestCase):
|
||||||
template.Template(tpl),
|
template.Template(tpl),
|
||||||
status_reason='blarg')
|
status_reason='blarg')
|
||||||
|
|
||||||
|
self.stack.store()
|
||||||
|
|
||||||
|
mock_rsc_a = mock.MagicMock(current_template_id=self.stack.t.id)
|
||||||
|
mock_rsc_a.name = 'A'
|
||||||
|
mock_rsc_b = mock.MagicMock(current_template_id=self.stack.t.id)
|
||||||
|
mock_rsc_b.name = 'B'
|
||||||
|
mock_db_call.return_value = {
|
||||||
|
'A': mock_rsc_a,
|
||||||
|
'B': mock_rsc_b
|
||||||
|
}
|
||||||
|
|
||||||
def get_more(nested_depth=0, filters=None):
|
def get_more(nested_depth=0, filters=None):
|
||||||
if filters:
|
if filters:
|
||||||
yield 'X'
|
yield 'X'
|
||||||
|
@ -352,51 +401,14 @@ class StackTest(common.HeatTestCase):
|
||||||
))
|
))
|
||||||
|
|
||||||
# Verify, the db query is called with expected filter
|
# Verify, the db query is called with expected filter
|
||||||
mock_db_call.assert_called_once_with(self.ctx,
|
mock_db_call.assert_has_calls([
|
||||||
self.stack.id,
|
mock.call(self.ctx, self.stack.id),
|
||||||
dict(name=['A']))
|
mock.call(self.ctx, self.stack.id, dict(name=['A'])),
|
||||||
|
])
|
||||||
|
|
||||||
# Returns three resources (1 first level + 2 second level)
|
# Returns three resources (1 first level + 2 second level)
|
||||||
self.assertEqual(3, len(all_resources))
|
self.assertEqual(3, len(all_resources))
|
||||||
|
|
||||||
@mock.patch.object(stack.Stack, 'db_resource_get')
|
|
||||||
def test_iter_resources_cached(self, mock_drg):
|
|
||||||
tpl = {'HeatTemplateFormatVersion': '2012-12-12',
|
|
||||||
'Resources':
|
|
||||||
{'A': {'Type': 'StackResourceType'},
|
|
||||||
'B': {'Type': 'GenericResourceType'}}}
|
|
||||||
|
|
||||||
cache_data = {'A': {'reference_id': 'A-id', 'uuid': mock.ANY,
|
|
||||||
'id': mock.ANY, 'action': 'CREATE',
|
|
||||||
'status': 'COMPLETE'},
|
|
||||||
'B': {'reference_id': 'B-id', 'uuid': mock.ANY,
|
|
||||||
'id': mock.ANY, 'action': 'CREATE',
|
|
||||||
'status': 'COMPLETE'}}
|
|
||||||
|
|
||||||
self.stack = stack.Stack(self.ctx, 'test_stack',
|
|
||||||
template.Template(tpl),
|
|
||||||
status_reason='blarg',
|
|
||||||
cache_data=cache_data)
|
|
||||||
|
|
||||||
def get_more(nested_depth=0, filters=None):
|
|
||||||
yield 'X'
|
|
||||||
yield 'Y'
|
|
||||||
yield 'Z'
|
|
||||||
|
|
||||||
self.stack['A'].nested = mock.MagicMock()
|
|
||||||
self.stack['A'].nested.return_value.iter_resources = mock.MagicMock(
|
|
||||||
side_effect=get_more)
|
|
||||||
|
|
||||||
resource_generator = self.stack.iter_resources()
|
|
||||||
self.assertIsNot(resource_generator, list)
|
|
||||||
|
|
||||||
first_level_resources = list(resource_generator)
|
|
||||||
self.assertEqual(2, len(first_level_resources))
|
|
||||||
all_resources = list(self.stack.iter_resources(1))
|
|
||||||
self.assertEqual(5, len(all_resources))
|
|
||||||
|
|
||||||
# A cache supplied means we should never query the database.
|
|
||||||
self.assertFalse(mock_drg.called)
|
|
||||||
|
|
||||||
def test_load_parent_resource(self):
|
def test_load_parent_resource(self):
|
||||||
self.stack = stack.Stack(self.ctx, 'load_parent_resource', self.tmpl,
|
self.stack = stack.Stack(self.ctx, 'load_parent_resource', self.tmpl,
|
||||||
parent_resource='parent')
|
parent_resource='parent')
|
||||||
|
|
Loading…
Reference in New Issue