Openstack liberty 云主机迁移源码分析之在线迁移4

时间:2023-02-02 02:14:00

这是在线迁移源码分析第四篇,也是最后一篇,介绍在线迁移完成后的清理过程及迁移失败后的滚回操作,下面一起来看具体内容:

complete完成阶段

迁移成功后的清理过程

Openstack liberty 云主机迁移源码分析之在线迁移3中的分析可知,迁移成功后的清理方法为:_post_live_migration,下面一起来看看:

#`nova/compute/manager.py/ComputeManager._post_live_migration `
#省略异常处理装饰器定义
def _post_live_migration(self, ctxt, instance,
dest, block_migration=False,
migrate_data=None)
:

"""Post operations for live migration."""
#从`nova.block_device_mapping`数据表获取实例的块设备映射
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
ctxt, instance.uuid)
"""获得实例的块设备信息
1.将上文获取的实例块设备映射转化为驱动格式(字典格式),如:
{'root_device_name'=u'/dev/vda','ephemerals'=[],
'block_device_mapping'=[],'swap'= None}
并排除'block_device_mapping'中'connection_info'信息缺失的卷设备
"""

block_device_info = self._get_instance_block_device_info(
ctxt, instance, bdms=bdms)
"""断开卷连接
1.从块设备信息`block_device_info`中得到卷设备
`block_device_mapping`
2.获得主机上的设备连接器('connector')信息,返回如下格式的字典:
{'ip'='', 'host'='', 'initiator'='','wwpn'='',
'wwnn'='','multipath'=False/True,'platform'='x86_64',
'os_type'='linux2'}, 具体过程如下
1. 发起`sudo nova-rootwrap /etc/nova/rootwrap.conf cat
/etc/iscsi/initiatorname.iscsi`命令得到主机上的iscsi
initiator名称,如:iqn.1994-05.com.redhat:92c97b181e6
2.发起`sudo nova-rootwrap /etc/nova/rootwrap.conf
systool -c fc_host -v`命令得到主机FC HBA的WWPN及WWNN信息
3.通过`uname -a` 及`sys.platform`获得`platform`及
'os_type'
3.通过`cinder/volume/api.py/API`发起同步
`initialize_connection`请求给 `cinder-volume`更新卷设备的
`connection_info`信息, 具体处理过程如下:
1. 通过卷id,从`cinder.volume`数据表获得卷信息
2. 通过具体的卷驱动(如:`LVMVolumeDriver`,`RBDDriver`)
验证输入的`connector`信息格式是否合法(如:
`LVMVolumeDriver`调用`iscsi_helper`完成格证;`RBDDriver`
是空操作)
3.通过具体的卷驱动(如:`LVMVolumeDriver`,`RBDDriver`)导
出卷设备(如:`LVMVolumeDriver`调用`iscsi_helper`导出卷路
径,得到形如下的字典 {'provider_location': ''
'provider_auth'=''};
`RBDDriver`是空操作)
4. 将3.中的导出信息更新到`nova.volumes`数据库(如果有的话)
5. 从`nova.driver_initiator_data`数据表获得卷的
`initiator`信息
6.调用具体的卷驱动(如:`LVMVolumeDriver`,`RBDDriver`)更
新`connection`连接信息(如:`LVMVolumeDriver`调
用`iscsi_helper`更新连接信息并发回字典格式信息;`RBDDriver`
通过发起`sudo cinder-rootwrap
/etc/cinder/rootwrap.conf ceph mon dump --format=json
--id $rbd_user --conf $rbd_ceph_conf --cluster
$rbd_cluster_name`命令获得`ceph`集群的监视器信息并组
合`cinder.conf`中配置的`rbd`信息得到`rbd`的连接信息)
7.更新`nova.driver_initiator_data`数据表记录(如果有的话)
8.从数据库获取卷的`qos_specs`信息(如果有的话)
9.从`nova.volume_admin_metadata`数据表获得卷的元信息
4.调用具体的卷驱动断开卷连接
"""

self.driver.post_live_migration(ctxt, instance,
block_device_info,
migrate_data)
#获得主机上的设备连接器('connector')信息,或上述的2过程一样
connector = self.driver.get_volume_connector(instance)
for bdm in bdms:
#发送`terminate_connection`同步消息,由`cinder-volume`移除
#卷设备在hypervisor上的连接
if bdm.is_volume:
self.volume_api.terminate_connection(ctxt,
bdm.volume_id,
connector)
"""从neutron数据库(`neutron.ports`,`neutron.networks`,
`neutron.subnets`,`neutron.floatingips`等)获取实
例的网络信息(VIF)并更新`nova.instance_info_caches`数据表
"""

network_info = self.network_api.get_instance_nw_info(ctxt,
instance)
#发送`live_migration._post.start`通知给ceilometer
self._notify_about_instance_usage(ctxt, instance,
"live_migration._post.start",
network_info=network_info)
#删除实例的网络及防火墙过滤规则(IptablesFirewallDriver)
self.driver.unfilter_instance(instance, network_info)

migration = {'source_compute': self.host,
'dest_compute': dest, }
#空操作
self.network_api.migrate_instance_start(ctxt,
instance,
migration)
destroy_vifs = False
try:
#移除源主机上实例所占用的VIF网络信息;LibvirtGenericVIFDriver
#会根据具体的网络类型调用unplug_{type}方法来移除网络,对于
#` bridge`,实例关闭网络就自动消失了,不需要额外的移除操作
self.driver.post_live_migration_at_source(ctxt,
instance,
network_info)
except NotImplementedError as ex:
LOG.debug(ex, instance=instance)
""" For all hypervisors other than libvirt, there is a
possibility they are unplugging networks from source
node in the cleanup method
"""

#如果移除网络失败,后面还需要再次清理
destroy_vifs = True

# Define domain at destination host, without doing it,
# pause/suspend/terminate do not work.
"""发送异步`post_live_migration_at_destination`消息到目标主机
上,由`nova-compute`完成相关的操作,具体功能如下:
1.更新neutron数据库(设置'binding:host_id'属性为目标主机)
2.从neutron数据库(`neutron.ports`,`neutron.networks`,
`neutron.subnets`,`neutron.floatingips`等)获取实
例的网络信息(VIF)并更新`nova.instance_info_caches`数据表
3.向ceilometer发送`live_migration.post.dest.start`通知,并附带
2.中获得的网络信息
4.获取实例的块设备信息,具体如下:
1.先从`nova.block_device_mapping`数据表中获取实例的块设
备映射信息
2.将实例的块设备映射转化为驱动格式(字典格式),如:
{'root_device_name':u'/dev/vda','ephemerals'=[],
'block_device_mapping':[......],'swap':=None}
3.排除上述'block_device_mapping'中不包
含'connection_info'信息的卷设备
5.Define实例(镜像信息,网络信息,块设备信息都添加到xml文件)
6.更新实例数据库信息(主机,状态等)
7.向ceilometer发送`live_migration.post.dest.end`通知,并附带
2.中获得的网络信息
"""

self.compute_rpcapi.post_live_migration_at_destination(
ctxt,
instance,
block_migration,
dest)
"""设置清理标志:
如果是块迁移或者非共享的实例配置路径,do_cleanup=True,表示需要执行
目录清理
如果是非共享的块设备,destroy_disks=True,表示需要执行磁盘清理
"""

do_cleanup, destroy_disks =
self._live_migration_cleanup_flags(
block_migration, migrate_data)
#执行清理操作
if do_cleanup:
"""
1.如果destroy_vifs=True,就执行移除网络的操作
2.清除主机上与实例相关的网络过滤及防火墙策略
3.如果destroy_disks=True,根据CONF.libvirt.images_type后
端存储类型清理卷
4.删除实例文件
5.如果使能了serial_console,就释放占用的端口
6.undefine实例
"""

self.driver.cleanup(ctxt, instance, network_info,
destroy_disks=destroy_disks,
migrate_data=migrate_data,
destroy_vifs=destroy_vifs)
#删除所有的pending事件
self.instance_events.clear_events_for_instance(instance)
""" NOTE(timello): make sure we update available resources
on source host even before next periodic task.

更新节点资源信息:
1. 从`nova.compute_nodes`获取主机上的计算节点信息
2. 更新主机上的资源使用情况(由hypervisor获取主机上的资源,通过
主机上的实例及迁移占用的资源来计算资源使用情况)
"""

self.update_available_resource(ctxt)
#更新`nova-scheduler`上主机的实例信息
self._update_scheduler_instance_info(ctxt, instance)
#发送`live_migration._post.end`通知给ceilometer,附带网络信息
self._notify_about_instance_usage(ctxt, instance,
"live_migration._post.end",
network_info=network_info)
#通过`nova-consoleauth`服务删除`console token`
self._clean_instance_console_tokens(ctxt, instance)
#更新迁移状态:completed,`nova.instance_migrations`数据表
if migrate_data and migrate_data.get('migration'):
migrate_data['migration'].status = 'completed'
migrate_data['migration'].save()

小结:纵观上述的清理操作主要包括两个方面:源主机和目标主机。

  • 在源主机端主要是:清除实例占用的VIF网络信息及相关的过滤规则,磁盘,端口等,最后undefine 实例。
  • 在目标主机端主要是:更新VIF网络信息并define实例

迁移失败后的滚回操作

同样的,由Openstack liberty 云主机迁移源码分析之在线迁移3中的分析可知,迁移成功后的清理方法为:_rollback_live_migration,下面一起来看看:

#`nova/compute/manager.py/ComputeManager._rollback_live_migration`
#省略异常处理装饰器定义
def _rollback_live_migration(self, context, instance,
dest, block_migration,
migrate_data=None)
:

"""Recovers Instance/volume state from migrating ->
running.
"""


#更新实例的任务状态:None, `nova.instances`数据表
instance.task_state = None
instance.save(expected_task_state=[task_states.MIGRATING])

""" NOTE(danms): Pop out the migration object so we don't
pass it over RPC unintentionally below
"""

#提取`migration`属性
if migrate_data:
migration = migrate_data.pop('migration', None)
else:
migration = None

# NOTE(tr3buchet): setup networks on source host (really
#it's re-setup)
#空操作
self.network_api.setup_networks_on_host(context, instance,
self.host)
#从`nova.block_device_mapping`数据表获取实例的块设备映射
bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
context, instance.uuid)
#在目标主机上卸载卷并断开卷连接 (同步操作)
for bdm in bdms:
if bdm.is_volume:
self.compute_rpcapi.remove_volume_connection(
context, instance, bdm.volume_id, dest)
#发送`live_migration._rollback.start`通知给ceilometer
self._notify_about_instance_usage(context, instance,
"live_migration._rollback.start")
"""设置清理标志:
如果是块迁移或者非共享的实例配置路径,do_cleanup=True,表示需要执行
目录清理
如果是非共享的块设备,destroy_disks=True,表示需要执行磁盘清理
"""

do_cleanup, destroy_disks =
self._live_migration_cleanup_flags(
block_migration, migrate_data)

if do_cleanup:
"""
1.如果destroy_vifs=True,就执行移除网络的操作
2.清除主机上与实例相关的网络过滤及防火墙策略
3.如果destroy_disks=True,根据CONF.libvirt.images_type后
端存储类型清理卷
4.删除实例文件
5.如果使能了serial_console,就释放占用的端口
6.undefine实例
"""

self.compute_rpcapi.rollback_live_migration_ \
at_destination(
context, instance, dest,
destroy_disks=destroy_disks,
migrate_data=migrate_data)

#发送`live_migration._rollback.end`通知给ceilometer
self._notify_about_instance_usage(context, instance,
"live_migration._rollback.end")
#更新迁移状态:error,`nova.instance_migrations`数据表
if migration:
migration.status = 'error'
migration.save()

小结:分析过迁移成功后的清理操作后,迁移失败后的滚回操作就很好理解了,从上面的分析也可以知道:失败后的清理基本就是把迁移成功后对源主机的清理操作应用到了目标主机上。

完!!!