summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-10-05 00:52:39 +0000
committerGerrit Code Review <review@openstack.org>2016-10-05 00:52:39 +0000
commite7bf9d43bb47c2796d8ae3c46507a76c8a4bfddd (patch)
tree748f5cbd5db9707f3ca5d49150a02dae7dd717cf
parent1586abd5364a4e161d6a3bd73b36bc84b737eb84 (diff)
parente2b2f6e6249117e5f74bc8088b7f1b9f085e6de2 (diff)
downloadnova-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.py12
-rw-r--r--nova/virt/libvirt/storage/rbd_utils.py51
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)