diff options
author | Jenkins <jenkins@review.openstack.org> | 2016-10-05 00:52:39 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2016-10-05 00:52:39 +0000 |
commit | e7bf9d43bb47c2796d8ae3c46507a76c8a4bfddd (patch) | |
tree | 748f5cbd5db9707f3ca5d49150a02dae7dd717cf | |
parent | 1586abd5364a4e161d6a3bd73b36bc84b737eb84 (diff) | |
parent | e2b2f6e6249117e5f74bc8088b7f1b9f085e6de2 (diff) | |
download | nova-e7bf9d43bb47c2796d8ae3c46507a76c8a4bfddd.tar.gz |
Merge "rbd_utils: wrap blocking calls in tpool.Proxy()" into stable/mitaka
-rw-r--r-- | nova/tests/unit/virt/libvirt/storage/test_rbd.py | 12 | ||||
-rw-r--r-- | nova/virt/libvirt/storage/rbd_utils.py | 51 |
2 files changed, 45 insertions, 18 deletions
diff --git a/nova/tests/unit/virt/libvirt/storage/test_rbd.py b/nova/tests/unit/virt/libvirt/storage/test_rbd.py index 6c25c22b6e..1d812c7b00 100644 --- a/nova/tests/unit/virt/libvirt/storage/test_rbd.py +++ b/nova/tests/unit/virt/libvirt/storage/test_rbd.py @@ -11,6 +11,7 @@ # under the License. +from eventlet import tpool import mock from nova.compute import task_states @@ -82,6 +83,17 @@ class RbdTestCase(test.NoDBTestCase): def tearDown(self): super(RbdTestCase, self).tearDown() + @mock.patch.object(rbd_utils, 'rbd') + def test_rbdproxy_wraps_rbd(self, mock_rbd): + proxy = rbd_utils.RbdProxy() + self.assertIsInstance(proxy._rbd, tpool.Proxy) + + @mock.patch.object(rbd_utils, 'rbd') + def test_rbdproxy_attribute_access_proxying(self, mock_rbd): + client = mock.MagicMock(ioctx='fake_ioctx') + rbd_utils.RbdProxy().list(client.ioctx) + mock_rbd.RBD.return_value.list.assert_called_once_with(client.ioctx) + def test_good_locations(self): locations = ['rbd://fsid/pool/image/snap', 'rbd://%2F/%2F/%2F/%2F', ] diff --git a/nova/virt/libvirt/storage/rbd_utils.py b/nova/virt/libvirt/storage/rbd_utils.py index bf3a33486a..d3294fd458 100644 --- a/nova/virt/libvirt/storage/rbd_utils.py +++ b/nova/virt/libvirt/storage/rbd_utils.py @@ -42,6 +42,21 @@ from nova.virt.libvirt import utils as libvirt_utils LOG = logging.getLogger(__name__) +class RbdProxy(object): + """A wrapper around rbd.RBD class instance to avoid blocking of process. + + Offloads all calls to rbd.RBD class methods to native OS threads, so that + we do not block the whole process while executing the librbd code. + + """ + + def __init__(self): + self._rbd = tpool.Proxy(rbd.RBD()) + + def __getattr__(self, attr): + return getattr(self._rbd, attr) + + class RBDVolumeProxy(object): """Context manager for dealing with an existing rbd volume. @@ -56,9 +71,9 @@ class RBDVolumeProxy(object): client, ioctx = driver._connect_to_rados(pool) try: snap_name = snapshot.encode('utf8') if snapshot else None - self.volume = rbd.Image(ioctx, name.encode('utf8'), - snapshot=snap_name, - read_only=read_only) + self.volume = tpool.Proxy(rbd.Image(ioctx, name.encode('utf8'), + snapshot=snap_name, + read_only=read_only)) except rbd.ImageNotFound: with excutils.save_and_reraise_exception(): LOG.debug("rbd image %s does not exist", name) @@ -219,12 +234,12 @@ class RBDDriver(object): with RADOSClient(self, str(pool)) as src_client: with RADOSClient(self, dest_pool) as dest_client: try: - rbd.RBD().clone(src_client.ioctx, - image.encode('utf-8'), - snapshot.encode('utf-8'), - dest_client.ioctx, - str(dest_name), - features=src_client.features) + RbdProxy().clone(src_client.ioctx, + image.encode('utf-8'), + snapshot.encode('utf-8'), + dest_client.ioctx, + str(dest_name), + features=src_client.features) except rbd.PermissionError: raise exception.Forbidden(_('no write permission on ' 'storage pool %s') % dest_pool) @@ -266,7 +281,7 @@ class RBDDriver(object): """ LOG.debug('flattening %(pool)s/%(vol)s', dict(pool=pool, vol=volume)) with RBDVolumeProxy(self, str(volume), pool=pool) as vol: - tpool.execute(vol.flatten) + vol.flatten() def exists(self, name, pool=None, snapshot=None): try: @@ -285,7 +300,7 @@ class RBDDriver(object): """ with RADOSClient(self, self.pool) as client: try: - rbd.RBD().remove(client.ioctx, name) + RbdProxy().remove(client.ioctx, name) except rbd.ImageNotFound: LOG.warn(_LW('image %(volume)s in pool %(pool)s can not be ' 'found, failed to remove'), @@ -317,7 +332,7 @@ class RBDDriver(object): """ def _cleanup_vol(ioctx, volume, retryctx): try: - rbd.RBD().remove(ioctx, volume) + RbdProxy().remove(ioctx, volume) raise loopingcall.LoopingCallDone(retvalue=False) except rbd.ImageHasSnapshots: self.remove_snap(volume, libvirt_utils.RESIZE_SNAPSHOT_NAME, @@ -357,7 +372,7 @@ class RBDDriver(object): else: return disk.startswith(instance.uuid) - volumes = rbd.RBD().list(client.ioctx) + volumes = RbdProxy().list(client.ioctx) for volume in filter(belongs_to_instance, volumes): self._destroy_volume(client, volume) @@ -379,9 +394,9 @@ class RBDDriver(object): LOG.debug('creating snapshot(%(snap)s) on rbd image(%(img)s)', {'snap': name, 'img': volume}) with RBDVolumeProxy(self, str(volume), pool=pool) as vol: - tpool.execute(vol.create_snap, name) + vol.create_snap(name) if protect and not vol.is_protected_snap(name): - tpool.execute(vol.protect_snap, name) + vol.protect_snap(name) def remove_snap(self, volume, name, ignore_errors=False, pool=None, force=False): @@ -397,7 +412,7 @@ class RBDDriver(object): if name in [snap.get('name', '') for snap in vol.list_snaps()]: if vol.is_protected_snap(name): if force: - tpool.execute(vol.unprotect_snap, name) + vol.unprotect_snap(name) elif not ignore_errors: LOG.warning(_LW('snapshot(%(name)s) on rbd ' 'image(%(img)s) is protected, ' @@ -406,7 +421,7 @@ class RBDDriver(object): return LOG.debug('removing snapshot(%(name)s) on rbd image(%(img)s)', {'name': name, 'img': volume}) - tpool.execute(vol.remove_snap, name) + vol.remove_snap(name) elif not ignore_errors: LOG.warning(_LW('no snapshot(%(name)s) found on rbd ' 'image(%(img)s)'), @@ -422,7 +437,7 @@ class RBDDriver(object): if name in [snap.get('name', '') for snap in vol.list_snaps()]: LOG.debug('rolling back rbd image(%(img)s) to ' 'snapshot(%(snap)s)', {'snap': name, 'img': volume}) - tpool.execute(vol.rollback_to_snap, name) + vol.rollback_to_snap(name) else: raise exception.SnapshotNotFound(snapshot_id=name) |