Fixes _cleanup_rbd code to capture ImageBusy exception

This patch captures the rbd.ImageBusy exception and attempts to
remove the image from the rbd volume.

Conflicts:
	nova/tests/unit/virt/libvirt/test_rbd.py
	nova/virt/libvirt/rbd_utils.py

Co-Authored-By: Dan Smith <dansmith@redhat.com>
Change-Id: I6a5ca4c68a39c2abf5f3f7d2d863fa2198d3c8e9
Closes-Bug: 1438331
(cherry picked from commit a37bc78ed5)
This commit is contained in:
Joe Talerico 2015-03-30 13:55:47 -04:00 committed by Dan Smith
parent 53c87f9c1b
commit 692b5ef984
2 changed files with 31 additions and 9 deletions

View File

@ -296,11 +296,14 @@ class RbdTestCase(test.NoDBTestCase):
rbd.list.return_value = ['12345_test', '111_test']
client = mock_client.return_value
self.driver.cleanup_volumes(instance)
rbd.remove.assert_called_once_with(client.ioctx, '12345_test')
with mock.patch('eventlet.greenthread.sleep'):
self.driver.cleanup_volumes(instance)
rbd.remove.assert_any_call(client.ioctx, '12345_test')
# NOTE(danms): 10 retries + 1 final attempt to propagate = 11
self.assertEqual(11, len(rbd.remove.call_args_list))
def test_cleanup_volumes_fail_not_found(self):
self._test_cleanup_exception('ImageNotFound')
self._test_cleanup_exception('ImageBusy')
def test_cleanup_volumes_fail_snapshots(self):
self._test_cleanup_exception('ImageHasSnapshots')

View File

@ -30,6 +30,7 @@ from nova.i18n import _LW
from nova.openstack.common import excutils
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.openstack.common import loopingcall
from nova.openstack.common import units
from nova import utils
@ -254,6 +255,18 @@ class RBDDriver(object):
utils.execute('rbd', 'import', *args)
def cleanup_volumes(self, instance):
def _cleanup_vol(ioctx, volume, retryctx):
try:
rbd.RBD().remove(client.ioctx, volume)
raise loopingcall.LoopingCallDone(retvalue=False)
except (rbd.ImageBusy, rbd.ImageHasSnapshots):
LOG.warn(_LW('rbd remove %(volume)s in pool %(pool)s '
'failed'),
{'volume': volume, 'pool': self.pool})
retryctx['retries'] -= 1
if retryctx['retries'] <= 0:
raise loopingcall.LoopingCallDone()
with RADOSClient(self, self.pool) as client:
def belongs_to_instance(disk):
@ -262,12 +275,18 @@ class RBDDriver(object):
# pylint: disable=E1101
volumes = rbd.RBD().list(client.ioctx)
for volume in filter(belongs_to_instance, volumes):
try:
rbd.RBD().remove(client.ioctx, volume)
except (rbd.ImageNotFound, rbd.ImageHasSnapshots):
LOG.warn(_LW('rbd remove %(volume)s in pool %(pool)s '
'failed'),
{'volume': volume, 'pool': self.pool})
# NOTE(danms): We let it go for ten seconds
retryctx = {'retries': 10}
timer = loopingcall.FixedIntervalLoopingCall(
_cleanup_vol, client.ioctx, volume, retryctx)
timed_out = timer.start(interval=1).wait()
if timed_out:
# NOTE(danms): Run this again to propagate the error, but
# if it succeeds, don't raise the loopingcall exception
try:
_cleanup_vol(client.ioctx, volume, retryctx)
except loopingcall.LoopingCallDone:
pass
def get_pool_info(self):
with RADOSClient(self) as client: