Remove second get call to list/show volumes
Recently it was observed that with large numbers of volumes
that things like "cinder list" could take extremely long to
return.
For example, running cinder list on a system with 1000 volumes took
greater than 30 seconds to return. It turns out that the cause of
this is the addition of visible admin_metadata.
There's two problems with this:
1. The original patch probably shouldn't have gone in
data is either admin data or it's not, selectively picking
pieces of admin data out to provide to the user just creates
complications and introduces confusion.
2. The REAL issue here is that since the standar gets are made
with the standard user context, the add_visible_admin_metadata
would go through and do an elevated context get on every single
volume individually. This is what caused the horrible performance
issue on cinder list with large numbers of volumes.
Running as admin, or removing the second call drops this down to about 3
seconds for the same 1000 volume list.
This patch removes the secondary admin context get_call. Instead where
we expect to do display the visible admin_meta, we pass in a flag
requesting that the volume object we're getting has the appropriate
metadata. This way we can elevate the context if needed and avoid
iterating through the gets again.
This patch also cleans up the get_visible_admin_meta methods, and
consolidates both V1 and V2 to use the utils method.
Change-Id: I3fb7aefb7d8a5664b0a3fb3958f509b5cd621320
Closes-Bug: 1317606
(cherry picked from commit 0505bb2689
)
This commit is contained in:
parent
1c494a15ac
commit
fe37a6ee1d
|
@ -144,7 +144,7 @@ class VolumeManageController(wsgi.Controller):
|
|||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
new_volume = dict(new_volume.iteritems())
|
||||
utils.add_visible_admin_metadata(context, new_volume, self.volume_api)
|
||||
utils.add_visible_admin_metadata(new_volume)
|
||||
|
||||
return self._view_builder.detail(req, new_volume)
|
||||
|
||||
|
|
|
@ -218,71 +218,23 @@ class CreateDeserializer(CommonDeserializer):
|
|||
class VolumeController(wsgi.Controller):
|
||||
"""The Volumes API controller for the OpenStack API."""
|
||||
|
||||
_visible_admin_metadata_keys = ['readonly', 'attached_mode']
|
||||
|
||||
def __init__(self, ext_mgr):
|
||||
self.volume_api = cinder_volume.API()
|
||||
self.ext_mgr = ext_mgr
|
||||
super(VolumeController, self).__init__()
|
||||
|
||||
def _add_visible_admin_metadata(self, context, volume):
|
||||
if context is None:
|
||||
return
|
||||
|
||||
visible_admin_meta = {}
|
||||
|
||||
if context.is_admin:
|
||||
volume_tmp = volume
|
||||
else:
|
||||
try:
|
||||
volume_tmp = self.volume_api.get(context.elevated(),
|
||||
volume['id'])
|
||||
except Exception:
|
||||
return
|
||||
|
||||
if volume_tmp.get('volume_admin_metadata'):
|
||||
for item in volume_tmp['volume_admin_metadata']:
|
||||
if item['key'] in self._visible_admin_metadata_keys:
|
||||
visible_admin_meta[item['key']] = item['value']
|
||||
# avoid circular ref when volume is a Volume instance
|
||||
elif (volume_tmp.get('admin_metadata') and
|
||||
isinstance(volume_tmp.get('admin_metadata'), dict)):
|
||||
for key in self._visible_admin_metadata_keys:
|
||||
if key in volume_tmp['admin_metadata'].keys():
|
||||
visible_admin_meta[key] = volume_tmp['admin_metadata'][key]
|
||||
|
||||
if not visible_admin_meta:
|
||||
return
|
||||
|
||||
# NOTE(zhiyan): update visible administration metadata to
|
||||
# volume metadata, administration metadata will rewrite existing key.
|
||||
if volume.get('volume_metadata'):
|
||||
orig_meta = list(volume.get('volume_metadata'))
|
||||
for item in orig_meta:
|
||||
if item['key'] in visible_admin_meta.keys():
|
||||
item['value'] = visible_admin_meta.pop(item['key'])
|
||||
for key, value in visible_admin_meta.iteritems():
|
||||
orig_meta.append({'key': key, 'value': value})
|
||||
volume['volume_metadata'] = orig_meta
|
||||
# avoid circular ref when vol is a Volume instance
|
||||
elif (volume.get('metadata') and
|
||||
isinstance(volume.get('metadata'), dict)):
|
||||
volume['metadata'].update(visible_admin_meta)
|
||||
else:
|
||||
volume['metadata'] = visible_admin_meta
|
||||
|
||||
@wsgi.serializers(xml=VolumeTemplate)
|
||||
def show(self, req, id):
|
||||
"""Return data about the given volume."""
|
||||
context = req.environ['cinder.context']
|
||||
|
||||
try:
|
||||
vol = self.volume_api.get(context, id)
|
||||
vol = self.volume_api.get(context, id, viewable_admin_meta=True)
|
||||
req.cache_resource(vol)
|
||||
except exception.NotFound:
|
||||
raise exc.HTTPNotFound()
|
||||
|
||||
self._add_visible_admin_metadata(context, vol)
|
||||
utils.add_visible_admin_metadata(vol)
|
||||
|
||||
return {'volume': _translate_volume_detail_view(context, vol)}
|
||||
|
||||
|
@ -326,12 +278,13 @@ class VolumeController(wsgi.Controller):
|
|||
|
||||
volumes = self.volume_api.get_all(context, marker=None, limit=None,
|
||||
sort_key='created_at',
|
||||
sort_dir='desc', filters=search_opts)
|
||||
sort_dir='desc', filters=search_opts,
|
||||
viewable_admin_meta=True)
|
||||
|
||||
volumes = [dict(vol.iteritems()) for vol in volumes]
|
||||
|
||||
for volume in volumes:
|
||||
self._add_visible_admin_metadata(context, volume)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
|
||||
limited_list = common.limited(volumes, req)
|
||||
req.cache_resource(limited_list)
|
||||
|
@ -436,8 +389,6 @@ class VolumeController(wsgi.Controller):
|
|||
# a dict to avoid an error.
|
||||
new_volume = dict(new_volume.iteritems())
|
||||
|
||||
self._add_visible_admin_metadata(context, new_volume)
|
||||
|
||||
retval = _translate_volume_detail_view(context, new_volume, image_uuid)
|
||||
|
||||
return {'volume': retval}
|
||||
|
@ -471,7 +422,7 @@ class VolumeController(wsgi.Controller):
|
|||
update_dict[key] = volume[key]
|
||||
|
||||
try:
|
||||
volume = self.volume_api.get(context, id)
|
||||
volume = self.volume_api.get(context, id, viewable_admin_meta=True)
|
||||
volume_utils.notify_about_volume_usage(context, volume,
|
||||
'update.start')
|
||||
self.volume_api.update(context, volume, update_dict)
|
||||
|
@ -480,7 +431,7 @@ class VolumeController(wsgi.Controller):
|
|||
|
||||
volume.update(update_dict)
|
||||
|
||||
self._add_visible_admin_metadata(context, volume)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
|
||||
volume_utils.notify_about_volume_usage(context, volume,
|
||||
'update.end')
|
||||
|
|
|
@ -164,13 +164,13 @@ class VolumeController(wsgi.Controller):
|
|||
context = req.environ['cinder.context']
|
||||
|
||||
try:
|
||||
vol = self.volume_api.get(context, id)
|
||||
vol = self.volume_api.get(context, id, viewable_admin_meta=True)
|
||||
req.cache_resource(vol)
|
||||
except exception.NotFound:
|
||||
msg = _("Volume could not be found")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
utils.add_visible_admin_metadata(context, vol, self.volume_api)
|
||||
utils.add_visible_admin_metadata(vol)
|
||||
|
||||
return self._view_builder.detail(req, vol)
|
||||
|
||||
|
@ -226,12 +226,13 @@ class VolumeController(wsgi.Controller):
|
|||
filters['metadata'] = ast.literal_eval(filters['metadata'])
|
||||
|
||||
volumes = self.volume_api.get_all(context, marker, limit, sort_key,
|
||||
sort_dir, filters)
|
||||
sort_dir, filters,
|
||||
viewable_admin_meta=True)
|
||||
|
||||
volumes = [dict(vol.iteritems()) for vol in volumes]
|
||||
|
||||
for volume in volumes:
|
||||
utils.add_visible_admin_metadata(context, volume, self.volume_api)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
|
||||
limited_list = common.limited(volumes, req)
|
||||
|
||||
|
@ -349,9 +350,6 @@ class VolumeController(wsgi.Controller):
|
|||
# trying to lazy load, but for now we turn it into
|
||||
# a dict to avoid an error.
|
||||
new_volume = dict(new_volume.iteritems())
|
||||
|
||||
utils.add_visible_admin_metadata(context, new_volume, self.volume_api)
|
||||
|
||||
retval = self._view_builder.detail(req, new_volume)
|
||||
|
||||
return retval
|
||||
|
@ -399,7 +397,7 @@ class VolumeController(wsgi.Controller):
|
|||
del update_dict['description']
|
||||
|
||||
try:
|
||||
volume = self.volume_api.get(context, id)
|
||||
volume = self.volume_api.get(context, id, viewable_admin_meta=True)
|
||||
volume_utils.notify_about_volume_usage(context, volume,
|
||||
'update.start')
|
||||
self.volume_api.update(context, volume, update_dict)
|
||||
|
@ -409,7 +407,7 @@ class VolumeController(wsgi.Controller):
|
|||
|
||||
volume.update(update_dict)
|
||||
|
||||
utils.add_visible_admin_metadata(context, volume, self.volume_api)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
|
||||
volume_utils.notify_about_volume_usage(context, volume,
|
||||
'update.end')
|
||||
|
|
|
@ -29,6 +29,7 @@ from cinder.tests.api import fakes
|
|||
from cinder.tests.api.v2 import stubs
|
||||
from cinder.tests import fake_notifier
|
||||
from cinder.tests.image import fake as fake_image
|
||||
from cinder import utils
|
||||
from cinder.volume import api as volume_api
|
||||
|
||||
|
||||
|
@ -97,8 +98,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'volume_type': 'vol_type_name',
|
||||
'snapshot_id': None,
|
||||
'source_volid': None,
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'metadata': {},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1, 1, 1,
|
||||
1, 1, 1),
|
||||
|
@ -190,8 +190,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'image_id': test_id,
|
||||
'snapshot_id': None,
|
||||
'source_volid': None,
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'metadata': {},
|
||||
'id': '1',
|
||||
'created_at': datetime.datetime(1, 1, 1,
|
||||
1, 1, 1),
|
||||
|
@ -546,7 +545,7 @@ class VolumeApiTest(test.TestCase):
|
|||
self.assertIsNotNone(req.cached_resource_by_id('1'))
|
||||
|
||||
def test_volume_show_no_attachments(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, attach_status='detached')
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
@ -571,7 +570,7 @@ class VolumeApiTest(test.TestCase):
|
|||
self.assertEqual(res_dict, expected)
|
||||
|
||||
def test_volume_show_bootable(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return (stubs.stub_volume(volume_id,
|
||||
volume_glance_metadata=dict(foo='bar')))
|
||||
|
||||
|
@ -616,7 +615,8 @@ class VolumeApiTest(test.TestCase):
|
|||
def volume_detail_limit_offset(is_admin):
|
||||
def stub_volume_get_all_by_project(context, project_id, marker,
|
||||
limit, sort_key, sort_dir,
|
||||
filters=None):
|
||||
filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return [
|
||||
stubs.stub_volume(1, display_name='vol1'),
|
||||
stubs.stub_volume(2, display_name='vol2'),
|
||||
|
@ -678,7 +678,7 @@ class VolumeApiTest(test.TestCase):
|
|||
self.assertEqual(res_dict, expected)
|
||||
|
||||
def test_volume_show_with_encrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
@ -688,7 +688,7 @@ class VolumeApiTest(test.TestCase):
|
|||
self.assertEqual(res_dict['volume']['encrypted'], True)
|
||||
|
||||
def test_volume_show_with_unencrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id=None)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
@ -758,9 +758,7 @@ class VolumeApiTest(test.TestCase):
|
|||
metadata = [{"key": "key", "value": "value"}]
|
||||
volume = dict(volume_admin_metadata=admin_metadata,
|
||||
volume_metadata=metadata)
|
||||
admin_ctx = context.get_admin_context()
|
||||
self.controller._add_visible_admin_metadata(admin_ctx,
|
||||
volume)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
self.assertEqual(volume['volume_metadata'],
|
||||
[{"key": "key", "value": "value"},
|
||||
{"key": "readonly", "value": "visible"},
|
||||
|
@ -772,9 +770,7 @@ class VolumeApiTest(test.TestCase):
|
|||
metadata = {"key": "value"}
|
||||
volume = dict(admin_metadata=admin_metadata,
|
||||
metadata=metadata)
|
||||
admin_ctx = context.get_admin_context()
|
||||
self.controller._add_visible_admin_metadata(admin_ctx,
|
||||
volume)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
self.assertEqual(volume['metadata'],
|
||||
{'key': 'value',
|
||||
'attached_mode': 'visible',
|
||||
|
|
|
@ -96,11 +96,12 @@ def stub_volume_delete(self, context, *args, **param):
|
|||
pass
|
||||
|
||||
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, viewable_admin_meta=False):
|
||||
return stub_volume(volume_id)
|
||||
|
||||
|
||||
def stub_volume_get_notfound(self, context, volume_id):
|
||||
def stub_volume_get_notfound(self, context,
|
||||
volume_id, viewable_admin_meta=False):
|
||||
raise exc.NotFound
|
||||
|
||||
|
||||
|
@ -109,14 +110,16 @@ def stub_volume_get_db(context, volume_id):
|
|||
|
||||
|
||||
def stub_volume_get_all(context, search_opts=None, marker=None, limit=None,
|
||||
sort_key='created_at', sort_dir='desc', filters=None):
|
||||
sort_key='created_at', sort_dir='desc', filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return [stub_volume(100, project_id='fake'),
|
||||
stub_volume(101, project_id='superfake'),
|
||||
stub_volume(102, project_id='superduperfake')]
|
||||
|
||||
|
||||
def stub_volume_get_all_by_project(self, context, marker, limit, sort_key,
|
||||
sort_dir, filters={}):
|
||||
sort_dir, filters={},
|
||||
viewable_admin_meta=False):
|
||||
return [stub_volume_get(self, context, '1')]
|
||||
|
||||
|
||||
|
|
|
@ -105,8 +105,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'rel': 'self'},
|
||||
{'href': 'http://localhost/fake/volumes/1',
|
||||
'rel': 'bookmark'}],
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'metadata': {},
|
||||
'name': 'Volume Test Name',
|
||||
'size': 100,
|
||||
'snapshot_id': None,
|
||||
|
@ -209,8 +208,7 @@ class VolumeApiTest(test.TestCase):
|
|||
'rel': 'self'},
|
||||
{'href': 'http://localhost/fake/volumes/1',
|
||||
'rel': 'bookmark'}],
|
||||
'metadata': {'attached_mode': 'rw',
|
||||
'readonly': 'False'},
|
||||
'metadata': {},
|
||||
'name': 'Volume Test Name',
|
||||
'size': '1',
|
||||
'snapshot_id': None,
|
||||
|
@ -690,7 +688,8 @@ class VolumeApiTest(test.TestCase):
|
|||
|
||||
def test_volume_index_with_marker(self):
|
||||
def stub_volume_get_all_by_project(context, project_id, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return [
|
||||
stubs.stub_volume(1, display_name='vol1'),
|
||||
stubs.stub_volume(2, display_name='vol2'),
|
||||
|
@ -741,7 +740,8 @@ class VolumeApiTest(test.TestCase):
|
|||
|
||||
def test_volume_index_limit_offset(self):
|
||||
def stub_volume_get_all_by_project(context, project_id, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return [
|
||||
stubs.stub_volume(1, display_name='vol1'),
|
||||
stubs.stub_volume(2, display_name='vol2'),
|
||||
|
@ -768,7 +768,8 @@ class VolumeApiTest(test.TestCase):
|
|||
|
||||
def test_volume_detail_with_marker(self):
|
||||
def stub_volume_get_all_by_project(context, project_id, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return [
|
||||
stubs.stub_volume(1, display_name='vol1'),
|
||||
stubs.stub_volume(2, display_name='vol2'),
|
||||
|
@ -819,7 +820,8 @@ class VolumeApiTest(test.TestCase):
|
|||
|
||||
def test_volume_detail_limit_offset(self):
|
||||
def stub_volume_get_all_by_project(context, project_id, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return [
|
||||
stubs.stub_volume(1, display_name='vol1'),
|
||||
stubs.stub_volume(2, display_name='vol2'),
|
||||
|
@ -853,7 +855,7 @@ class VolumeApiTest(test.TestCase):
|
|||
|
||||
def test_volume_with_limit_zero(self):
|
||||
def stub_volume_get_all(context, marker, limit,
|
||||
sort_key, sort_dir):
|
||||
sort_key, sort_dir, **kwargs):
|
||||
return []
|
||||
self.stubs.Set(db, 'volume_get_all', stub_volume_get_all)
|
||||
req = fakes.HTTPRequest.blank('/v2/volumes?limit=0')
|
||||
|
@ -867,7 +869,8 @@ class VolumeApiTest(test.TestCase):
|
|||
# Number of volumes equals the max, include next link
|
||||
def stub_volume_get_all(context, marker, limit,
|
||||
sort_key, sort_dir,
|
||||
filters=None):
|
||||
filters=None,
|
||||
viewable_admin_meta=False):
|
||||
vols = [stubs.stub_volume(i)
|
||||
for i in xrange(CONF.osapi_max_limit)]
|
||||
if limit == None or limit >= len(vols):
|
||||
|
@ -885,7 +888,8 @@ class VolumeApiTest(test.TestCase):
|
|||
# Number of volumes less then max, do not include
|
||||
def stub_volume_get_all2(context, marker, limit,
|
||||
sort_key, sort_dir,
|
||||
filters=None):
|
||||
filters=None,
|
||||
viewable_admin_meta=False):
|
||||
vols = [stubs.stub_volume(i)
|
||||
for i in xrange(100)]
|
||||
if limit == None or limit >= len(vols):
|
||||
|
@ -902,7 +906,8 @@ class VolumeApiTest(test.TestCase):
|
|||
# Number of volumes more then the max, include next link
|
||||
def stub_volume_get_all3(context, marker, limit,
|
||||
sort_key, sort_dir,
|
||||
filters=None):
|
||||
filters=None,
|
||||
viewable_admin_meta=False):
|
||||
vols = [stubs.stub_volume(i)
|
||||
for i in xrange(CONF.osapi_max_limit + 100)]
|
||||
if limit == None or limit >= len(vols):
|
||||
|
@ -941,13 +946,15 @@ class VolumeApiTest(test.TestCase):
|
|||
"""
|
||||
# Non-admin, project function should be called with no_migration_status
|
||||
def stub_volume_get_all_by_project(context, project_id, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
self.assertEqual(filters['no_migration_targets'], True)
|
||||
self.assertFalse('all_tenants' in filters)
|
||||
return [stubs.stub_volume(1, display_name='vol1')]
|
||||
|
||||
def stub_volume_get_all(context, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return []
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stub_volume_get_all_by_project)
|
||||
|
@ -963,12 +970,14 @@ class VolumeApiTest(test.TestCase):
|
|||
# Admin, all_tenants is not set, project function should be called
|
||||
# without no_migration_status
|
||||
def stub_volume_get_all_by_project2(context, project_id, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
self.assertFalse('no_migration_targets' in filters)
|
||||
return [stubs.stub_volume(1, display_name='vol2')]
|
||||
|
||||
def stub_volume_get_all2(context, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return []
|
||||
self.stubs.Set(db, 'volume_get_all_by_project',
|
||||
stub_volume_get_all_by_project2)
|
||||
|
@ -982,11 +991,13 @@ class VolumeApiTest(test.TestCase):
|
|||
# Admin, all_tenants is set, get_all function should be called
|
||||
# without no_migration_status
|
||||
def stub_volume_get_all_by_project3(context, project_id, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
return []
|
||||
|
||||
def stub_volume_get_all3(context, marker, limit,
|
||||
sort_key, sort_dir, filters=None):
|
||||
sort_key, sort_dir, filters=None,
|
||||
viewable_admin_meta=False):
|
||||
self.assertFalse('no_migration_targets' in filters)
|
||||
self.assertFalse('all_tenants' in filters)
|
||||
return [stubs.stub_volume(1, display_name='vol3')]
|
||||
|
@ -1047,7 +1058,7 @@ class VolumeApiTest(test.TestCase):
|
|||
self.assertIsNotNone(req.cached_resource_by_id('1'))
|
||||
|
||||
def test_volume_show_no_attachments(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, attach_status='detached')
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
@ -1152,7 +1163,7 @@ class VolumeApiTest(test.TestCase):
|
|||
self.assertEqual(res_dict, expected)
|
||||
|
||||
def test_volume_show_with_encrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id='fake_id')
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
@ -1162,7 +1173,7 @@ class VolumeApiTest(test.TestCase):
|
|||
self.assertEqual(res_dict['volume']['encrypted'], True)
|
||||
|
||||
def test_volume_show_with_unencrypted_volume(self):
|
||||
def stub_volume_get(self, context, volume_id):
|
||||
def stub_volume_get(self, context, volume_id, **kwargs):
|
||||
return stubs.stub_volume(volume_id, encryption_key_id=None)
|
||||
|
||||
self.stubs.Set(volume_api.API, 'get', stub_volume_get)
|
||||
|
@ -1262,9 +1273,7 @@ class VolumeApiTest(test.TestCase):
|
|||
metadata = [{"key": "key", "value": "value"}]
|
||||
volume = dict(volume_admin_metadata=admin_metadata,
|
||||
volume_metadata=metadata)
|
||||
admin_ctx = context.get_admin_context()
|
||||
utils.add_visible_admin_metadata(admin_ctx, volume,
|
||||
self.controller.volume_api)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
|
||||
self.assertEqual(volume['volume_metadata'],
|
||||
[{"key": "key", "value": "value"},
|
||||
|
@ -1277,9 +1286,7 @@ class VolumeApiTest(test.TestCase):
|
|||
metadata = {"key": "value"}
|
||||
volume = dict(admin_metadata=admin_metadata,
|
||||
metadata=metadata)
|
||||
admin_ctx = context.get_admin_context()
|
||||
utils.add_visible_admin_metadata(admin_ctx, volume,
|
||||
self.controller.volume_api)
|
||||
utils.add_visible_admin_metadata(volume)
|
||||
self.assertEqual(volume['metadata'],
|
||||
{'key': 'value',
|
||||
'attached_mode': 'visible',
|
||||
|
|
|
@ -795,36 +795,25 @@ def check_string_length(value, name, min_length=0, max_length=None):
|
|||
_visible_admin_metadata_keys = ['readonly', 'attached_mode']
|
||||
|
||||
|
||||
def add_visible_admin_metadata(context, volume, volume_api):
|
||||
def add_visible_admin_metadata(volume):
|
||||
"""Add user-visible admin metadata to regular metadata.
|
||||
|
||||
Extracts the admin metadata keys that are to be made visible to
|
||||
non-administrators, and adds them to the regular metadata structure for the
|
||||
passed-in volume.
|
||||
"""
|
||||
if context is None:
|
||||
return
|
||||
|
||||
visible_admin_meta = {}
|
||||
|
||||
if context.is_admin:
|
||||
volume_tmp = volume
|
||||
else:
|
||||
try:
|
||||
volume_tmp = volume_api.get(context.elevated(), volume['id'])
|
||||
except Exception:
|
||||
return
|
||||
|
||||
if volume_tmp.get('volume_admin_metadata'):
|
||||
for item in volume_tmp['volume_admin_metadata']:
|
||||
if volume.get('volume_admin_metadata'):
|
||||
for item in volume['volume_admin_metadata']:
|
||||
if item['key'] in _visible_admin_metadata_keys:
|
||||
visible_admin_meta[item['key']] = item['value']
|
||||
# avoid circular ref when volume is a Volume instance
|
||||
elif (volume_tmp.get('admin_metadata') and
|
||||
isinstance(volume_tmp.get('admin_metadata'), dict)):
|
||||
elif (volume.get('admin_metadata') and
|
||||
isinstance(volume.get('admin_metadata'), dict)):
|
||||
for key in _visible_admin_metadata_keys:
|
||||
if key in volume_tmp['admin_metadata'].keys():
|
||||
visible_admin_meta[key] = volume_tmp['admin_metadata'][key]
|
||||
if key in volume['admin_metadata'].keys():
|
||||
visible_admin_meta[key] = volume['admin_metadata'][key]
|
||||
|
||||
if not visible_admin_meta:
|
||||
return
|
||||
|
|
|
@ -260,14 +260,16 @@ class API(base.Base):
|
|||
def update(self, context, volume, fields):
|
||||
self.db.volume_update(context, volume['id'], fields)
|
||||
|
||||
def get(self, context, volume_id):
|
||||
def get(self, context, volume_id, viewable_admin_meta=False):
|
||||
if viewable_admin_meta:
|
||||
context = context.elevated()
|
||||
rv = self.db.volume_get(context, volume_id)
|
||||
volume = dict(rv.iteritems())
|
||||
check_policy(context, 'get', volume)
|
||||
return volume
|
||||
|
||||
def get_all(self, context, marker=None, limit=None, sort_key='created_at',
|
||||
sort_dir='desc', filters=None):
|
||||
sort_dir='desc', filters=None, viewable_admin_meta=False):
|
||||
check_policy(context, 'get_all')
|
||||
if filters == None:
|
||||
filters = {}
|
||||
|
@ -298,6 +300,8 @@ class API(base.Base):
|
|||
volumes = self.db.volume_get_all(context, marker, limit, sort_key,
|
||||
sort_dir, filters=filters)
|
||||
else:
|
||||
if viewable_admin_meta:
|
||||
context = context.elevated()
|
||||
volumes = self.db.volume_get_all_by_project(context,
|
||||
context.project_id,
|
||||
marker, limit,
|
||||
|
|
Loading…
Reference in New Issue