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:
parent
53c87f9c1b
commit
692b5ef984
|
@ -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')
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue