libvirt: Fix infinite loop waiting for block job
Libvirt may return an empty dict when a block job has completed.
In this case, _wait_for_block_job will return True, causing
its callers to loop.
Affects volume_snapshot_delete, swap_volume, and live_snapshot.
(See http://libvirt.org/git/?p=libvirt.git;a=commit;h=0f9e67bf )
Closes-Bug: #1260123
Change-Id: Iab81299f0ce32a14e46aee0fd389ed29f7e503b8
(cherry picked from commit e3ac20fca7
)
This commit is contained in:
parent
e7b2e3a6c3
commit
17f27bf184
@ -498,6 +498,9 @@ class Domain(object):
|
||||
def maxMemory(self):
|
||||
return self._def['memory']
|
||||
|
||||
def blockJobInfo(self, disk, flags):
|
||||
return {}
|
||||
|
||||
|
||||
class DomainSnapshot(object):
|
||||
def __init__(self, name, domain):
|
||||
|
@ -7301,6 +7301,7 @@ class LibvirtVolumeSnapshotTestCase(test.TestCase):
|
||||
self.mox.StubOutWithMock(self.conn, 'has_min_version')
|
||||
self.mox.StubOutWithMock(domain, 'blockRebase')
|
||||
self.mox.StubOutWithMock(domain, 'blockCommit')
|
||||
self.mox.StubOutWithMock(domain, 'blockJobInfo')
|
||||
|
||||
self.conn._lookup_by_name('instance-%s' % instance['id']).\
|
||||
AndReturn(domain)
|
||||
@ -7308,6 +7309,9 @@ class LibvirtVolumeSnapshotTestCase(test.TestCase):
|
||||
|
||||
domain.blockRebase('vda', 'snap.img', 0, 0)
|
||||
|
||||
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1, 'end': 1000})
|
||||
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1000, 'end': 1000})
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.conn._volume_snapshot_delete(self.c, instance, self.volume_uuid,
|
||||
@ -7329,6 +7333,7 @@ class LibvirtVolumeSnapshotTestCase(test.TestCase):
|
||||
self.mox.StubOutWithMock(self.conn, 'has_min_version')
|
||||
self.mox.StubOutWithMock(domain, 'blockRebase')
|
||||
self.mox.StubOutWithMock(domain, 'blockCommit')
|
||||
self.mox.StubOutWithMock(domain, 'blockJobInfo')
|
||||
|
||||
self.conn._lookup_by_name('instance-%s' % instance['id']).\
|
||||
AndReturn(domain)
|
||||
@ -7336,6 +7341,9 @@ class LibvirtVolumeSnapshotTestCase(test.TestCase):
|
||||
|
||||
domain.blockCommit('vda', 'other-snap.img', 'snap.img', 0, 0)
|
||||
|
||||
domain.blockJobInfo('vda', 0).AndReturn({'cur': 1, 'end': 1000})
|
||||
domain.blockJobInfo('vda', 0).AndReturn({})
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
self.conn._volume_snapshot_delete(self.c, instance, self.volume_uuid,
|
||||
|
@ -1429,6 +1429,16 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
|
||||
@staticmethod
|
||||
def _wait_for_block_job(domain, disk_path, abort_on_error=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.')
|
||||
@ -1439,7 +1449,7 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
if cur == end and cur != 0 and end != 0:
|
||||
if cur == end:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
Loading…
Reference in New Issue
Block a user