Libvirt: Allow missing volumes during delete

When deleting an instance, libvirt driver will clear all the volumes
of the instance. Ignore exception when clearing a missing volume
to avoid delete instance error.

Closes-Bug: 1404791
Change-Id: I8a663e8f0396bf2303642610ae1001c330159b75
This commit is contained in:
Eli Qiao 2015-02-16 11:23:42 +08:00 committed by Alexis Lee
parent 10a7974b3a
commit 11fb3936a1
2 changed files with 33 additions and 31 deletions

View File

@ -50,10 +50,20 @@ class LvmTestCase(test.NoDBTestCase):
self.assertRaises(exception.VolumeBDMPathNotFound,
lvm.get_volume_size, '/dev/foo')
@mock.patch.object(utils, 'execute',
side_effect=processutils.ProcessExecutionError(
stderr=('blockdev: cannot open /dev/foo: '
'No such file or directory')))
def test_get_volume_size_not_found_file(self, mock_execute):
self.assertRaises(exception.VolumeBDMPathNotFound,
lvm.get_volume_size, '/dev/foo')
@mock.patch.object(libvirt_utils, 'path_exists', return_value=True)
@mock.patch.object(utils, 'execute',
side_effect=processutils.ProcessExecutionError(
stderr='blockdev: i am sad in other ways'))
def test_get_volume_size_unexpectd_error(self, mock_execute):
def test_get_volume_size_unexpectd_error(self, mock_execute,
mock_path_exists):
self.assertRaises(processutils.ProcessExecutionError,
lvm.get_volume_size, '/dev/foo')
@ -168,6 +178,13 @@ class LvmTestCase(test.NoDBTestCase):
lvm.clear_volume('/dev/vd')
self.assertEqual(expected_commands, executes)
@mock.patch.object(utils, 'execute',
side_effect=processutils.ProcessExecutionError(
stderr=('blockdev: cannot open /dev/foo: '
'No such file or directory')))
def test_lvm_clear_ignore_lvm_not_found(self, mock_execute):
lvm.clear_volume('/dev/foo')
def test_fail_remove_all_logical_volumes(self):
def fake_execute(*args, **kwargs):
if 'vol2' in args:

View File

@ -19,8 +19,6 @@
# under the License.
#
import functools
from oslo_concurrency import processutils
from oslo_config import cfg
from oslo_log import log as logging
@ -31,7 +29,6 @@ from nova import exception
from nova.i18n import _
from nova.i18n import _LE
from nova.i18n import _LW
from nova import utils as nova_utils
from nova.virt.libvirt import utils
@ -51,28 +48,6 @@ CONF.import_opt('instances_path', 'nova.compute.manager')
LOG = logging.getLogger(__name__)
@nova_utils.expects_func_args('path')
def wrap_no_device_error(function):
"""Wraps a method to catch exceptions related to volume BDM not found.
This decorator wraps a method to catch ProcessExecutionError having to do
with a missing volume block device mapping. It translates the error to a
VolumeBDMPathNotFound exception.
"""
@functools.wraps(function)
def decorated_function(path):
try:
return function(path)
except processutils.ProcessExecutionError as e:
if 'No such device or address' in e.stderr:
raise exception.VolumeBDMPathNotFound(path=path)
else:
raise
return decorated_function
def create_volume(vg, lv, size, sparse=False):
"""Create LVM image.
@ -184,7 +159,6 @@ def volume_info(path):
return dict(zip(*info))
@wrap_no_device_error
def get_volume_size(path):
"""Get logical volume size in bytes.
@ -193,9 +167,14 @@ def get_volume_size(path):
fails in some unexpected way.
:raises: exception.VolumeBDMPathNotFound if the volume path does not exist.
"""
out, _err = utils.execute('blockdev', '--getsize64', path,
run_as_root=True)
try:
out, _err = utils.execute('blockdev', '--getsize64', path,
run_as_root=True)
except processutils.ProcessExecutionError:
if not utils.path_exists(path):
raise exception.VolumeBDMPathNotFound(path=path)
else:
raise
return int(out)
@ -246,7 +225,13 @@ def clear_volume(path):
return
volume_clear_size = int(CONF.libvirt.volume_clear_size) * units.Mi
volume_size = get_volume_size(path)
try:
volume_size = get_volume_size(path)
except exception.VolumeBDMPathNotFound:
LOG.warn(_LW('ignoring missing logical volume %(path)s'),
{'path': path})
return
if volume_clear_size != 0 and volume_clear_size < volume_size:
volume_size = volume_clear_size