Skip to content

Commit

Permalink
Use cached volumes in REST API extensions
Browse files Browse the repository at this point in the history
This patch caches db volumes in the core volumes API so that they can be
used in the host and tenant attribute API extensions in order to lower
the response time by avoiding costly individual db queries for each
volume in the REST API contributions.

Change-Id: Ie0cbe929379df32fddbdce1953f13b6f26208bff
Partial-Bug: #1197612
(cherry picked from commit 9ed0f39)
  • Loading branch information
Luis A. Garcia authored and Jay S. Bryant committed Nov 18, 2013
1 parent 7f4f083 commit 1126044
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 21 deletions.
17 changes: 7 additions & 10 deletions cinder/api/contrib/volume_host_attribute.py
Expand Up @@ -29,29 +29,26 @@ def __init__(self, *args, **kwargs):
super(VolumeHostAttributeController, self).__init__(*args, **kwargs)
self.volume_api = volume.API()

def _add_volume_host_attribute(self, context, resp_volume):
try:
db_volume = self.volume_api.get(context, resp_volume['id'])
except Exception:
return
else:
key = "%s:host" % Volume_host_attribute.alias
resp_volume[key] = db_volume['host']
def _add_volume_host_attribute(self, context, req, resp_volume):
db_volume = req.cached_resource_by_id(resp_volume['id'])
key = "%s:host" % Volume_host_attribute.alias
resp_volume[key] = db_volume['host']

@wsgi.extends
def show(self, req, resp_obj, id):
context = req.environ['cinder.context']
if authorize(context):
resp_obj.attach(xml=VolumeHostAttributeTemplate())
self._add_volume_host_attribute(context, resp_obj.obj['volume'])
volume = resp_obj.obj['volume']
self._add_volume_host_attribute(context, req, volume)

@wsgi.extends
def detail(self, req, resp_obj):
context = req.environ['cinder.context']
if authorize(context):
resp_obj.attach(xml=VolumeListHostAttributeTemplate())
for volume in list(resp_obj.obj['volumes']):
self._add_volume_host_attribute(context, volume)
self._add_volume_host_attribute(context, req, volume)


class Volume_host_attribute(extensions.ExtensionDescriptor):
Expand Down
17 changes: 7 additions & 10 deletions cinder/api/contrib/volume_tenant_attribute.py
Expand Up @@ -27,29 +27,26 @@ def __init__(self, *args, **kwargs):
super(VolumeTenantAttributeController, self).__init__(*args, **kwargs)
self.volume_api = volume.API()

def _add_volume_tenant_attribute(self, context, resp_volume):
try:
db_volume = self.volume_api.get(context, resp_volume['id'])
except Exception:
return
else:
key = "%s:tenant_id" % Volume_tenant_attribute.alias
resp_volume[key] = db_volume['project_id']
def _add_volume_tenant_attribute(self, context, req, resp_volume):
db_volume = req.cached_resource_by_id(resp_volume['id'])
key = "%s:tenant_id" % Volume_tenant_attribute.alias
resp_volume[key] = db_volume['project_id']

@wsgi.extends
def show(self, req, resp_obj, id):
context = req.environ['cinder.context']
if authorize(context):
resp_obj.attach(xml=VolumeTenantAttributeTemplate())
self._add_volume_tenant_attribute(context, resp_obj.obj['volume'])
volume = resp_obj.obj['volume']
self._add_volume_tenant_attribute(context, req, volume)

@wsgi.extends
def detail(self, req, resp_obj):
context = req.environ['cinder.context']
if authorize(context):
resp_obj.attach(xml=VolumeListTenantAttributeTemplate())
for volume in list(resp_obj.obj['volumes']):
self._add_volume_tenant_attribute(context, volume)
self._add_volume_tenant_attribute(context, req, volume)


class Volume_tenant_attribute(extensions.ExtensionDescriptor):
Expand Down
2 changes: 2 additions & 0 deletions cinder/api/v1/volumes.py
Expand Up @@ -275,6 +275,7 @@ def show(self, req, id):

try:
vol = self.volume_api.get(context, id)
req.cache_resource(vol)
except exception.NotFound:
raise exc.HTTPNotFound()

Expand Down Expand Up @@ -330,6 +331,7 @@ def _items(self, req, entity_maker):
self._add_visible_admin_metadata(context, volume)

limited_list = common.limited(volumes, req)
req.cache_resource(limited_list)
res = [entity_maker(context, vol) for vol in limited_list]
return {'volumes': res}

Expand Down
2 changes: 2 additions & 0 deletions cinder/api/v2/volumes.py
Expand Up @@ -212,6 +212,7 @@ def show(self, req, id):

try:
vol = self.volume_api.get(context, id)
req.cache_resource(vol)
except exception.NotFound:
msg = _("Volume could not be found")
raise exc.HTTPNotFound(explanation=msg)
Expand Down Expand Up @@ -285,6 +286,7 @@ def _get_volumes(self, req, is_detail):
volumes = self._view_builder.detail_list(req, limited_list)
else:
volumes = self._view_builder.summary_list(req, limited_list)
req.cache_resource(limited_list)
return volumes

def _image_uuid_from_href(self, image_href):
Expand Down
2 changes: 1 addition & 1 deletion cinder/tests/api/fakes.py
Expand Up @@ -137,7 +137,7 @@ class HTTPRequest(webob.Request):
def blank(cls, *args, **kwargs):
kwargs['base_url'] = 'http://localhost/v1'
use_admin_context = kwargs.pop('use_admin_context', False)
out = webob.Request.blank(*args, **kwargs)
out = os_wsgi.Request.blank(*args, **kwargs)
out.environ['cinder.context'] = FakeRequestContext(
'fake_user',
'fake',
Expand Down
8 changes: 8 additions & 0 deletions cinder/tests/api/v1/test_volumes.py
Expand Up @@ -386,6 +386,8 @@ def test_volume_list(self):
1, 1, 1),
'size': 1}]}
self.assertEqual(res_dict, expected)
# Finally test that we cached the returned volumes
self.assertEqual(1, len(req.cached_resource()))

def test_volume_list_with_admin_metadata(self):
volume = stubs.stub_volume("1")
Expand Down Expand Up @@ -451,6 +453,8 @@ def test_volume_list_detail(self):
1, 1, 1),
'size': 1}]}
self.assertEqual(res_dict, expected)
# Finally test that we cached the returned volumes
self.assertEqual(1, len(req.cached_resource()))

def test_volume_list_detail_with_admin_metadata(self):
volume = stubs.stub_volume("1")
Expand Down Expand Up @@ -638,6 +642,8 @@ def test_volume_show(self):
1, 1, 1),
'size': 1}}
self.assertEqual(res_dict, expected)
# Finally test that we cached the returned volume
self.assertIsNotNone(req.cached_resource_by_id('1'))

def test_volume_show_no_attachments(self):
def stub_volume_get(self, context, volume_id):
Expand Down Expand Up @@ -701,6 +707,8 @@ def test_volume_show_no_volume(self):
self.controller.show,
req,
1)
# Finally test that we did not cache anything
self.assertIsNone(req.cached_resource_by_id('1'))

def test_volume_detail_limit_offset(self):
def volume_detail_limit_offset(is_admin):
Expand Down
8 changes: 8 additions & 0 deletions cinder/tests/api/v2/test_volumes.py
Expand Up @@ -435,6 +435,8 @@ def test_volume_list_summary(self):
]
}
self.assertEqual(res_dict, expected)
# Finally test that we cached the returned volumes
self.assertEqual(1, len(req.cached_resource()))

def test_volume_list_detail(self):
self.stubs.Set(volume_api.API, 'get_all',
Expand Down Expand Up @@ -482,6 +484,8 @@ def test_volume_list_detail(self):
]
}
self.assertEqual(res_dict, expected)
# Finally test that we cached the returned volumes
self.assertEqual(1, len(req.cached_resource()))

def test_volume_list_detail_with_admin_metadata(self):
volume = stubs.stub_volume("1")
Expand Down Expand Up @@ -869,6 +873,8 @@ def test_volume_show(self):
}
}
self.assertEqual(res_dict, expected)
# Finally test that we cached the returned volume
self.assertIsNotNone(req.cached_resource_by_id('1'))

def test_volume_show_no_attachments(self):
def stub_volume_get(self, context, volume_id):
Expand Down Expand Up @@ -915,6 +921,8 @@ def test_volume_show_no_volume(self):
req = fakes.HTTPRequest.blank('/v2/volumes/1')
self.assertRaises(webob.exc.HTTPNotFound, self.controller.show,
req, 1)
# Finally test that nothing was cached
self.assertIsNone(req.cached_resource_by_id('1'))

def test_volume_show_with_admin_metadata(self):
volume = stubs.stub_volume("1")
Expand Down

0 comments on commit 1126044

Please sign in to comment.