def is_job_complete(self):
"""Return True if the job is complete, False otherwise
:returns: True if the job is complete, False otherwise
:raises: libvirt.libvirtError on error fetching block job info
"""
# NOTE(mdbooth): This method polls for block job completion. It returns
# true if either we get a status which indicates completion, or there
# is no longer a record of the job. Ideally this method and its
# callers would be rewritten to consume libvirt events from the job.
# This would provide a couple of advantages. Firstly, as it would no
# longer be polling it would notice completion immediately rather than
# at the next 0.5s check, and would also consume fewer resources.
# Secondly, with the current method we only know that 'no job'
# indicates completion. It does not necessarily indicate successful
# completion: the job could have failed, or been cancelled. When
# polling for block job info we have no way to detect this, so we
# assume success.
try:
status = self.get_job_info()
except libvirt.libvirtError as e:
if 'cannot acquire state change lock' in str(e):
# The domain lock is temporarily held by another libvirt
# operation (e.g. virConnectGetAllDomainStats from
# get_diagnostics). The block copy job is still running;
# we just cannot query its status right now. Return False
# so the caller retries after the next 0.5s sleep.
LOG.warning('Transient libvirt lock contention polling block '
'job status for %(disk)s, will retry: %(err)s',
{'disk': self._disk, 'err': e})
return False
raise
# If the job no longer exists, it is because it has completed