From bb2daca2864a5607635a3aa37f3874fdda22797b Mon Sep 17 00:00:00 2001 From: "Luis A. Garcia" Date: Tue, 5 Nov 2013 02:19:02 +0000 Subject: [PATCH] Add call to retrieve image metadata for volumes in bulk When using the GET volume details REST API call, the image metadata API contribution is making an individual db call for each of the available volumes. When the number of volumes is large the details call can take several minutes. This patch adds a call to the volume.API to retrieve image metadata in bulk, very similar to the one used to retrieve individual volume image metadata. Change-Id: Ic3aa721016704c72b7564cc5ceff71676806a24a Partial-Bug: #1197612 --- cinder/db/api.py | 5 +++++ cinder/db/sqlalchemy/api.py | 19 +++++++++++++++++++ cinder/tests/test_volume_glance_metadata.py | 20 ++++++++++++++++++++ cinder/volume/api.py | 10 ++++++++++ 4 files changed, 54 insertions(+) diff --git a/cinder/db/api.py b/cinder/db/api.py index 0648ead86..966dbdae3 100644 --- a/cinder/db/api.py +++ b/cinder/db/api.py @@ -549,6 +549,11 @@ def volume_glance_metadata_create(context, volume_id, key, value): value) +def volume_glance_metadata_get_all(context): + """Return the glance metadata for all volumes.""" + return IMPL.volume_glance_metadata_get_all(context) + + def volume_glance_metadata_get(context, volume_id): """Return the glance metadata for a volume.""" return IMPL.volume_glance_metadata_get(context, volume_id) diff --git a/cinder/db/sqlalchemy/api.py b/cinder/db/sqlalchemy/api.py index e872bce33..ceef71780 100644 --- a/cinder/db/sqlalchemy/api.py +++ b/cinder/db/sqlalchemy/api.py @@ -2289,6 +2289,25 @@ def volume_encryption_metadata_get(context, volume_id, session=None): #################### +@require_context +def _volume_glance_metadata_get_all(context, session=None): + rows = model_query(context, + models.VolumeGlanceMetadata, + project_only=True, + session=session).\ + filter_by(deleted=False).\ + all() + + return rows + + +@require_context +def volume_glance_metadata_get_all(context): + """Return the Glance metadata for all volumes.""" + + return _volume_glance_metadata_get_all(context) + + @require_context @require_volume_exists def _volume_glance_metadata_get(context, volume_id, session=None): diff --git a/cinder/tests/test_volume_glance_metadata.py b/cinder/tests/test_volume_glance_metadata.py index 0a8cf7c52..ec44d3c1c 100644 --- a/cinder/tests/test_volume_glance_metadata.py +++ b/cinder/tests/test_volume_glance_metadata.py @@ -82,6 +82,26 @@ class VolumeGlanceMetadataTestCase(test.TestCase): for key, value in expected_metadata_1.items(): self.assertEqual(metadata[0][key], value) + def test_vols_get_glance_metadata(self): + ctxt = context.get_admin_context() + db.volume_create(ctxt, {'id': '1'}) + db.volume_create(ctxt, {'id': '2'}) + db.volume_create(ctxt, {'id': '3'}) + db.volume_glance_metadata_create(ctxt, '1', 'key1', 'value1') + db.volume_glance_metadata_create(ctxt, '2', 'key2', 'value2') + db.volume_glance_metadata_create(ctxt, '2', 'key22', 'value22') + + metadata = db.volume_glance_metadata_get_all(ctxt) + self.assertEqual(len(metadata), 3) + self._assert_metadata_equals('1', 'key1', 'value1', metadata[0]) + self._assert_metadata_equals('2', 'key2', 'value2', metadata[1]) + self._assert_metadata_equals('2', 'key22', 'value22', metadata[2]) + + def _assert_metadata_equals(self, volume_id, key, value, observed): + self.assertEqual(volume_id, observed.volume_id) + self.assertEqual(key, observed.key) + self.assertEqual(value, observed.value) + def test_vol_delete_glance_metadata(self): ctxt = context.get_admin_context() db.volume_create(ctxt, {'id': 1}) diff --git a/cinder/volume/api.py b/cinder/volume/api.py index 15bf95467..a1398d4d8 100644 --- a/cinder/volume/api.py +++ b/cinder/volume/api.py @@ -21,6 +21,7 @@ Handles all requests relating to volumes. """ +import collections import functools from oslo.config import cfg @@ -700,6 +701,15 @@ class API(base.Base): def get_snapshot_metadata_value(self, snapshot, key): pass + def get_volumes_image_metadata(self, context): + check_policy(context, 'get_volumes_image_metadata') + db_data = self.db.volume_glance_metadata_get_all(context) + results = collections.defaultdict(dict) + for meta_entry in db_data: + results[meta_entry['volume_id']].update({meta_entry['key']: + meta_entry['value']}) + return results + @wrap_check_policy def get_volume_image_metadata(self, context, volume): db_data = self.db.volume_glance_metadata_get(context, volume['id']) -- 2.45.2