Optimize heat.Resource.get_by_node

Use memoization and a dict to cache the node-resource relation.
Also use LookupError instead of http.NotFound, so that we get proper
tracebacks.

Change-Id: Ic71c2fecaaca07ba070d896070efe8b094df8a78
This commit is contained in:
Radomir Dopieralski 2014-11-18 11:49:21 +01:00
parent eba24f6e51
commit fa1a02d811
4 changed files with 24 additions and 27 deletions

View File

@ -16,7 +16,6 @@ import urlparse
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
import heatclient
from horizon import exceptions
from horizon.utils import memoized
from openstack_dashboard.api import base
from openstack_dashboard.api import heat
@ -398,7 +397,15 @@ class Resource(base.APIResourceWrapper):
self._role = kwargs['role']
@classmethod
def get_by_node(cls, request, node, all_resources=None):
@memoized.memoized
def _resources_by_nodes(cls, request):
return dict(
(resource.physical_resource_id, resource)
for resource in cls.list_all_resources(request)
)
@classmethod
def get_by_node(cls, request, node):
"""Return the specified Heat Resource given a Node
:param request: request object
@ -407,22 +414,11 @@ class Resource(base.APIResourceWrapper):
:param node: node to match
:type node: tuskar_ui.api.node.Node
:return: matching Resource, or None if no Resource matches
the Node
:return: matching Resource, or raises LookupError if no
resource matches the node
:rtype: tuskar_ui.api.heat.Resource
"""
# TODO(tzumainn): this is terribly inefficient, but I don't see a
# better way. Maybe if Heat set some node metadata. . . ?
if node.instance_uuid:
if all_resources is None:
resource_list = cls.list_all_resources(request)
else:
resource_list = all_resources
for resource in resource_list:
if resource.physical_resource_id == node.instance_uuid:
return resource
msg = _('Could not find resource matching node "%s"') % node.uuid
raise exceptions.NotFound(msg)
return cls._resources_by_nodes(request)[node.instance_uuid]
@classmethod
def list_all_resources(cls, request):

View File

@ -16,7 +16,6 @@ import itertools
from django.core import urlresolvers
from django.utils.translation import ugettext_lazy as _
from horizon import exceptions
from horizon import tabs
from horizon.utils import functions
from openstack_dashboard.api import base as api_base
@ -242,16 +241,16 @@ class ProvisionedTab(BaseTab):
nodes, prev, more = self._nodes_info
if nodes:
all_resources = api.heat.Resource.list_all_resources(self.request)
for node in nodes:
try:
resource = api.heat.Resource.get_by_node(
self.request, node, all_resources=all_resources)
self.request, node)
except LookupError:
node.role_name = '-'
else:
node.role_name = resource.role.name
node.role_id = resource.role.id
node.stack_id = resource.stack.id
except exceptions.NotFound:
node.role_name = '-'
return nodes
@ -302,10 +301,11 @@ class DetailOverviewTab(tabs.Tab):
context = {'node': node}
try:
resource = api.heat.Resource.get_by_node(self.request, node)
except LookupError:
pass
else:
context['role'] = resource.role
context['stack'] = resource.stack
except exceptions.NotFound:
pass
if node.instance_uuid:
if api_base.is_service_enabled(self.request, 'metering'):
# Meter configuration in the following format:

View File

@ -250,8 +250,8 @@ class NodesTests(test.BaseAdminViewTests, helpers.APITestCase):
}),
patch('tuskar_ui.api.heat.Resource', **{
'spec_set': ['get_by_node'],
'get_by_node.side_effect': (
self._raise_horizon_exception_not_found),
'get_by_node.side_effect': lambda *args, **kwargs: {}[None],
# Raises LookupError
}),
) as (mock_node, mock_heat):
res = self.client.get(

View File

@ -92,11 +92,12 @@ class DetailView(horizon_tables.DataTableView, RoleMixin, StackMixin):
# by getting the resource for all nodes at once
try:
resource = api.heat.Resource.get_by_node(self.request, node)
except LookupError:
node.role_name = '-'
else:
node.role_name = resource.role.name
node.role_id = resource.role.id
node.stack_id = resource.stack.id
except horizon_exceptions.NotFound:
node.role_name = '-'
return nodes