cinder的migrate功能,如果遇到热迁移(卷已经挂载在虚机)的情况:cinder在目标后端host上创建好卷,然后交给nova;nova保证两个卷都挂着,然后调用nova.virt.libvirt.guest.BlockDevice的几个方法,实现硬盘数据从原卷到新卷的拷贝,然后修改虚机的xml配置文件(即virsh dumpxml instance-xxxxx 出来的xml文件,保存了虚拟机的配置信息)。
abort_job()
:
同步终止关于硬盘的所有读写操作。rebase(new_path, copy=True, reuse_ext=True)
:
在路径new_path(即新硬盘)为磁盘创建一个备份,同时reuse_ext=True指定了在拷贝过程中还可以写硬盘,但是此时不是写在块设备中,而是写在nova本地的一个文件中。dev.is_job_complete()
检查job是否完成。dev.abort_job(pivot=True)
:
停止磁盘的读写,并且将过程2中的读写内容合并。self._host.write_instance_config(xml)
:
nova.virt.libvirt.driver.LibvirtDriver#_swap_volume
def _swap_volume(self, guest, disk_path, conf, 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
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():
support_uefi = self._has_uefi_support()
guest.delete_configuration(support_uefi)
try:
# Start copy with VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT flag to
# allow writing to existing external volume file. Use
# VIR_DOMAIN_BLOCK_REBASE_COPY_DEV if it's a block device to
# make sure XML is generated correctly (bug 1691195)
copy_dev = conf.source_type == 'block'
dev.rebase(conf.source_path, copy=True, reuse_ext=True,
copy_dev=copy_dev)
while not dev.is_job_complete():
time.sleep(0.5)
dev.abort_job(pivot=True)
except Exception as exc:
LOG.exception("Failure rebasing volume %(new_path)s on "
"%(old_path)s.", {'new_path': conf.source_path,
'old_path': disk_path})
raise exception.VolumeRebaseFailed(reason=six.text_type(exc))
if resize_to:
dev.resize(resize_to * units.Gi / units.Ki)
finally:
self._host.write_instance_config(xml)
nova.virt.libvirt.guest.BlockDevice#rebase
def rebase(self, base, shallow=False, reuse_ext=False,
copy=False, relative=False, copy_dev=False):
"""Copy data from backing chain into a new disk
This copies data from backing file(s) into overlay(s), giving
control over several aspects like what part of a disk image
chain to be copied, whether to reuse an existing destination
file, etc. And updates the backing file to the new disk
:param shallow: Limit copy to top of the source backing chain
:param reuse_ext: Reuse an existing external file that was
pre-created
:param copy: Start a copy job
:param relative: Keep backing chain referenced using relative names
:param copy_dev: Treat the destination as type="block"
"""
flags = shallow and libvirt.VIR_DOMAIN_BLOCK_REBASE_SHALLOW or 0
flags |= reuse_ext and libvirt.VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT or 0
flags |= copy and libvirt.VIR_DOMAIN_BLOCK_REBASE_COPY or 0
flags |= copy_dev and libvirt.VIR_DOMAIN_BLOCK_REBASE_COPY_DEV or 0
flags |= relative and libvirt.VIR_DOMAIN_BLOCK_REBASE_RELATIVE or 0
return self._guest._domain.blockRebase(
self._disk, base, self.REBASE_DEFAULT_BANDWIDTH, flags=flags)