From 1a7ce2d32ec03a4cd80d6afd2fcc55125b4f3c39 Mon Sep 17 00:00:00 2001 From: John Griffith Date: Thu, 20 Aug 2015 10:45:03 -0600 Subject: [PATCH] Add ability to update provider_id during init During the Liberty release we added the ability to store a provider_id for a volume in the Cinder database. This simplifies a number of things for back ends when accessing volumes. One missing piece here however is that we have no way to populate this data for existing deployments if/when they upgrade. This patch provides a simple solution that issues an update call to the drivers on host init. It works by fetching a list of volumes for the specific host, and passes those in to the driver. The driver can do nothing, or it can go through and sync up the Cinder ID's with it's internal ID's and return the provider update info. Change-Id: Ib3b078a6f492afada24e534f380f5f014033d603 --- cinder/tests/unit/test_utils.py | 9 +++++++++ cinder/utils.py | 18 ++++++++++++++++++ cinder/volume/driver.py | 8 ++++++++ cinder/volume/manager.py | 20 ++++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/cinder/tests/unit/test_utils.py b/cinder/tests/unit/test_utils.py index 5f389c8cf..d7988c7af 100644 --- a/cinder/tests/unit/test_utils.py +++ b/cinder/tests/unit/test_utils.py @@ -510,6 +510,15 @@ class GenericUtilsTestCase(test.TestCase): self.assertEqual('sudo cinder-rootwrap /path/to/conf', utils.get_root_helper()) + def test_list_of_dicts_to_dict(self): + a = {'id': '1', 'color': 'orange'} + b = {'id': '2', 'color': 'blue'} + c = {'id': '3', 'color': 'green'} + lst = [a, b, c] + + resp = utils.list_of_dicts_to_dict(lst, 'id') + self.assertEqual(c['id'], resp['3']['id']) + class TemporaryChownTestCase(test.TestCase): @mock.patch('os.stat') diff --git a/cinder/utils.py b/cinder/utils.py index a2c853b06..bde22e835 100644 --- a/cinder/utils.py +++ b/cinder/utils.py @@ -288,6 +288,24 @@ def last_completed_audit_period(unit=None): return (begin, end) +def list_of_dicts_to_dict(seq, key): + """Convert list of dicts to a indexted dict. + + Takes a list of dicts, and converts it a nested dict + indexed by + + :param seq: list of dicts + :parm key: key in dicts to index by + + example: + lst = [{'id': 1, ...}, {'id': 2, ...}...] + key = 'id' + returns {1:{'id': 1, ...}, 2:{'id':2, ...} + + """ + return {d[key]: dict(d, index=d[key]) for (i, d) in enumerate(seq)} + + class ProtectedExpatParser(expatreader.ExpatParser): """An expat parser which disables DTD's and entities by default.""" diff --git a/cinder/volume/driver.py b/cinder/volume/driver.py index 85feacf89..764ead528 100644 --- a/cinder/volume/driver.py +++ b/cinder/volume/driver.py @@ -1179,6 +1179,14 @@ class BaseVD(object): """ return None + def update_provider_info(self, volid_list): + """Get provider info updates from driver. + + :param volid_list: List of Cinder vol id's to check for updates + :return: dict of update {'id': uuid, provider_id: } + """ + return None + @six.add_metaclass(abc.ABCMeta) class LocalVD(object): diff --git a/cinder/volume/manager.py b/cinder/volume/manager.py index c212b8a19..944213e8f 100644 --- a/cinder/volume/manager.py +++ b/cinder/volume/manager.py @@ -295,6 +295,25 @@ class VolumeManager(manager.SchedulerDependentManager): LOG.info(_LI("Determined volume DB was not empty at startup.")) return False + def _sync_provider_info(self, ctxt, volumes): + # NOTE(jdg): For now this just updates provider_id, we can add more + # add more items to the update if theyr'e releveant but we need + # to be safe in what we allow and add a list of allowed keys + # things that make sense are provider_*, replication_status etc + + updates = self.driver.update_provider_info([v['id'] for v in volumes]) + host_vols = utils.list_of_dicts_to_dict(volumes, 'id') + + for u in updates or []: + update = {} + # NOTE(JDG): Make sure returned item is in this hosts volumes + if host_vols.get(u['id'], None): + update['provider_id'] = u['provider_id'] + if update: + self.db.volume_update(ctxt, + u['id'], + update) + def init_host(self): """Perform any required initialization.""" @@ -315,6 +334,7 @@ class VolumeManager(manager.SchedulerDependentManager): return volumes = self.db.volume_get_all_by_host(ctxt, self.host) + self._sync_provider_info(ctxt, volumes) # FIXME volume count for exporting is wrong try: -- 2.45.2