def _swap_volume( self , guest, disk_path, new_path, resize_to): """Swap existing disk with a new block device.""" dev = guest.get_block_device(disk_path) # Save a copy of the domain's persistent XML file xml = guest.get_xml_desc(dump_inactive = True , dump_sensitive = True ) # Abort is an idempotent operation, so make sure any block # jobs which may have failed are ended. try : dev.abort_job() except Exception: pass reraise = False try : # NOTE (rmk): blockRebase cannot be executed on persistent # domains, so we need to temporarily undefine it. # If any part of this block fails, the domain is # re-defined regardless. if guest.has_persistent_configuration(): guest.delete_configuration() # Start copy with VIR_DOMAIN_REBASE_REUSE_EXT flag to # allow writing to existing external volume file dev.rebase(new_path, copy = True , reuse_ext = True ) while not dev.is_job_complete(): time.sleep( 0.5 ) dev.abort_job(pivot = True ) # 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 not dev.is_job_complete(): time.sleep( 0.5 ) if resize_to: dev.resize(resize_to * units.Gi / units.Ki) except Exception: dev.abort_job() reraise = True finally : # NOTE(mdbooth): We don't know if we're in exception context or # not. reraise=False will not fail if we're not in exception # context. with excutils.save_and_reraise_exception(reraise = reraise): self ._host.write_instance_config(xml) |