Merge "libvirt: introduce method to wait for block device job"
This commit is contained in:
commit
1d2d6801ea
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue