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:
Eric Harney 2013-12-19 16:21:25 -05:00
parent e7b2e3a6c3
commit 17f27bf184
3 changed files with 22 additions and 1 deletions

View File

@ -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):

View File

@ -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,

View File

@ -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