Merge "libvirt: introduce method to wait for block device job"

This commit is contained in:
Jenkins 2015-07-24 08:17:52 +00:00 committed by Gerrit Code Review
commit 1d2d6801ea
4 changed files with 79 additions and 52 deletions

View File

@ -13300,8 +13300,9 @@ class LibvirtVolumeSnapshotTestCase(test.NoDBTestCase):
domain.blockRebase('vda', 'snap.img', 0, flags=0)
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1000, 'end': 1000})
domain.blockJobInfo('vda', flags=0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vda', flags=0).AndReturn(
{'cur': 1000, 'end': 1000})
self.mox.ReplayAll()
@ -13336,8 +13337,9 @@ class LibvirtVolumeSnapshotTestCase(test.NoDBTestCase):
domain.blockRebase('vda', 'snap.img', 0,
flags=fakelibvirt.VIR_DOMAIN_BLOCK_REBASE_RELATIVE)
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1000, 'end': 1000})
domain.blockJobInfo('vda', flags=0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vda', flags=0).AndReturn(
{'cur': 1000, 'end': 1000})
self.mox.ReplayAll()
@ -13405,8 +13407,8 @@ class LibvirtVolumeSnapshotTestCase(test.NoDBTestCase):
domain.blockCommit('vda', 'other-snap.img', 'snap.img', 0,
flags=fakelibvirt.VIR_DOMAIN_BLOCK_COMMIT_RELATIVE)
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vda', 0).AndReturn({})
domain.blockJobInfo('vda', flags=0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vda', flags=0).AndReturn({})
self.mox.ReplayAll()
@ -13534,8 +13536,9 @@ class LibvirtVolumeSnapshotTestCase(test.NoDBTestCase):
domain.blockRebase('vdb', 'vdb[1]', 0, flags=0)
domain.blockJobInfo('vdb', 0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vdb', 0).AndReturn({'cur': 1000, 'end': 1000})
domain.blockJobInfo('vdb', flags=0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vdb', flags=0).AndReturn(
{'cur': 1000, 'end': 1000})
self.mox.ReplayAll()
@ -13575,8 +13578,9 @@ class LibvirtVolumeSnapshotTestCase(test.NoDBTestCase):
domain.blockRebase('vdb', 'vdb[1]', 0,
flags=fakelibvirt.VIR_DOMAIN_BLOCK_REBASE_RELATIVE)
domain.blockJobInfo('vdb', 0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vdb', 0).AndReturn({'cur': 1000, 'end': 1000})
domain.blockJobInfo('vdb', flags=0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vdb', flags=0).AndReturn(
{'cur': 1000, 'end': 1000})
self.mox.ReplayAll()
@ -13657,8 +13661,9 @@ class LibvirtVolumeSnapshotTestCase(test.NoDBTestCase):
domain.blockCommit('vdb', 'vdb[0]', 'vdb[1]', 0,
flags=fakelibvirt.VIR_DOMAIN_BLOCK_COMMIT_RELATIVE)
domain.blockJobInfo('vdb', 0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vdb', 0).AndReturn({'cur': 1000, 'end': 1000})
domain.blockJobInfo('vdb', flags=0).AndReturn({'cur': 1, 'end': 1000})
domain.blockJobInfo('vdb', flags=0).AndReturn(
{'cur': 1000, 'end': 1000})
self.mox.ReplayAll()

View File

@ -19,6 +19,7 @@ from oslo_config import cfg
from oslo_utils import encodeutils
from nova import context
from nova import exception
from nova import test
from nova.tests.unit.virt.libvirt import fakelibvirt
from nova import utils
@ -420,3 +421,30 @@ class GuestBlockTestCase(test.NoDBTestCase):
self.domain.blockCommit.assert_called_once_with(
'vda', "foo", "top", 0,
flags=fakelibvirt.VIR_DOMAIN_BLOCK_COMMIT_RELATIVE)
def test_wait_for_job(self):
self.domain.blockJobInfo.return_value = {
"type": 4,
"bandwidth": 18,
"cur": 95,
"end": 100}
in_progress = self.gblock.wait_for_job()
self.assertTrue(in_progress)
self.domain.blockJobInfo.return_value = {
"type": 4,
"bandwidth": 18,
"cur": 100,
"end": 100}
in_progress = self.gblock.wait_for_job()
self.assertFalse(in_progress)
self.domain.blockJobInfo.return_value = {"type": 0}
in_progress = self.gblock.wait_for_job(wait_for_job_clean=True)
self.assertFalse(in_progress)
def test_wait_for_job_arbort_on_error(self):
self.domain.blockJobInfo.return_value = -1
self.assertRaises(
exception.NovaException,
self.gblock.wait_for_job, abort_on_error=True)

View File

@ -1124,9 +1124,7 @@ class LibvirtDriver(driver.ComputeDriver):
# allow writing to existing external volume file
dev.rebase(new_path, copy=True, reuse_ext=True)
# TODO(sahid): This method needs to be implemented in Guest
# a future patch will come.
while self._wait_for_block_job(guest._domain, disk_path):
while dev.wait_for_job():
time.sleep(0.5)
dev.abort_job(pivot=True)
@ -1134,8 +1132,7 @@ class LibvirtDriver(driver.ComputeDriver):
# NOTE(alex_xu): domain.blockJobAbort isn't sync call. This
# is bug in libvirt. So we need waiting for the pivot is
# finished. libvirt bug #1119173
while self._wait_for_block_job(guest._domain, disk_path,
wait_for_job_clean=True):
while dev.wait_for_job(wait_for_job_clean=True):
time.sleep(0.5)
dev.resize(resize_to * units.Gi / units.Ki)
finally:
@ -1431,36 +1428,6 @@ class LibvirtDriver(driver.ComputeDriver):
LOG.info(_LI("Snapshot image upload complete"),
instance=instance)
@staticmethod
def _wait_for_block_job(domain, disk_path, abort_on_error=False,
wait_for_job_clean=False):
"""Wait for libvirt block job to complete.
Libvirt may return either cur==end or an empty dict when
the job is complete, depending on whether the job has been
cleaned up by libvirt yet, or not.
:returns: True if still in progress
False if completed
"""
status = domain.blockJobInfo(disk_path, 0)
if status == -1 and abort_on_error:
msg = _('libvirt error while requesting blockjob info.')
raise exception.NovaException(msg)
try:
cur = status.get('cur', 0)
end = status.get('end', 0)
except Exception:
return False
if wait_for_job_clean:
job_ended = not status
else:
job_ended = cur == end
return not job_ended
def _can_quiesce(self, image_meta):
if CONF.libvirt.virt_type not in ('kvm', 'qemu'):
return (False, _('Only KVM and QEMU are supported'))
@ -1557,7 +1524,7 @@ class LibvirtDriver(driver.ComputeDriver):
# issue an abort once we have a complete copy.
dev.rebase(disk_delta, copy=True, reuse_ext=True, shallow=True)
while self._wait_for_block_job(guest._domain, disk_path):
while dev.wait_for_job():
time.sleep(0.5)
dev.abort_job()
@ -1939,8 +1906,7 @@ class LibvirtDriver(driver.ComputeDriver):
if result == 0:
LOG.debug('blockRebase started successfully')
while self._wait_for_block_job(guest._domain, my_dev,
abort_on_error=True):
while dev.wait_for_job(abort_on_error=True):
LOG.debug('waiting for blockRebase job completion')
time.sleep(0.5)
@ -1991,8 +1957,7 @@ class LibvirtDriver(driver.ComputeDriver):
if result == 0:
LOG.debug('blockCommit started successfully')
while self._wait_for_block_job(guest._domain, my_dev,
abort_on_error=True):
while dev.wait_for_job(abort_on_error=True):
LOG.debug('waiting for blockCommit job completion')
time.sleep(0.5)

View File

@ -33,6 +33,8 @@ from oslo_utils import encodeutils
from oslo_utils import excutils
from oslo_utils import importutils
from nova import exception
from nova.i18n import _
from nova.i18n import _LE
from nova import utils
from nova.virt.libvirt import config as vconfig
@ -317,6 +319,33 @@ class BlockDevice(object):
"""Resizes block device to Kib size."""
self._guest._domain.blockResize(self._disk, size_kb)
def wait_for_job(self, abort_on_error=False, wait_for_job_clean=False):
"""Wait for libvirt block job to complete.
Libvirt may return either cur==end or an empty dict when
the job is complete, depending on whether the job has been
cleaned up by libvirt yet, or not.
:param abort_on_error: Whether to stop process and raise NovaException
on error (default: False)
:param wait_for_job_clean: Whether to force wait to ensure job is
finished (see bug: LP#1119173)
:returns: True if still in progress
False if completed
"""
status = self.get_job_info()
if not status and abort_on_error:
msg = _('libvirt error while requesting blockjob info.')
raise exception.NovaException(msg)
if wait_for_job_clean:
job_ended = status.job == 0
else:
job_ended = status.cur == status.end
return not job_ended
class VCPUInfo(object):
def __init__(self, id, cpu, state, time):