openstack-nova源码分析(九)冷迁移

本文详细解析了OpenStack Nova进行冷迁移的整个流程,从入口API`migrate_server.py`开始,依次介绍了resize、migrate_server、conductor的migrate_server、prep_resize、原宿主机的resize_instance、磁盘迁移、finish_resize、finish_migration以及虚拟机的创建。在冷迁移过程中,涉及到了实例状态检查、目标主机选择、磁盘和网络迁移等多个关键步骤。
摘要由CSDN通过智能技术生成
冷迁移 cold migration:

不保存虚拟机在线状态的,将主机迁移到其他宿主机, 迁移过程中会有关机的操作

备注: 为了方便梳理流程, 展示关键的流程步骤,过程中展示的源码部分会被删减

冷迁移

一. 入口API:
nova/api/openstack/compute/migrate_server.py
class MigrateServerController(wsgi.Controller):
    def __init__(self, *args, **kwargs):
    ....

    @wsgi.action('migrate')
    def _migrate(self, req, id, body):
        """Permit admins to migrate a server to a new host."""
        context = req.environ['nova.context']
        context.can(ms_policies.POLICY_ROOT % 'migrate')

        instance = common.get_instance(self.compute_api, context, id)
        try:
            self.compute_api.resize(req.environ['nova.context'], instance)
        except (exception.TooManyInstances, exception.QuotaError) as e:
            raise exc.HTTPForbidden(explanation=e.format_message())

instance = common.get_instance(self.compute_api, context, id) 依据instance id 获取instance id 并对instance的存在性做了校验

实际调用函数self.compute_api.resize(req.environ['nova.context'], instance)


二. resize
compute_api.resize定义在 nova/compute/api.py

定义在API类中

@profiler.trace_cls("compute_api")
class API(base.Base):
    """API for interacting with the compute manager."""

    @check_instance_lock       // 校验虚拟机的状态, 一个虚拟机上同时不进行多个任务
    @check_instance_cell
    @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED])
    
    // 校验虚拟机状态,active 和stopped状态允许迁移
    
    def resize(self, context, instance, flavor_id=None, clean_shutdown=True,
               **extra_instance_updates):
        """Resize (ie, migrate) a running instance.

        If flavor_id is None, the process is considered a migration, keeping
        the original flavor_id. If flavor_id is not None, the instance should
        be migrated to a new host and resized to the new flavor_id.
        """
        
        // 校验磁盘信息
        self._check_auto_disk_config(instance, **extra_instance_updates)
        
        // 获取当前flavor 并校验flavor

        current_instance_type = instance.get_flavor()

        # If flavor_id is not provided, only migrate the instance.
        if not flavor_id:
            LOG.debug("flavor_id is None. Assuming migration.",
                      instance=instance)
            new_instance_type = current_instance_type
        else:
					....

        if not new_instance_type:
            raise exception.FlavorNotFound(flavor_id=flavor_id)


        same_instance_type = (current_instance_type['id'] == new_instance_type['id'])


				//获取配额信息
        if flavor_id:
						....
        else:
            quotas = objects.Quotas(context=context)

				// 更新虚拟机状态为RESIZE_PREP, 虚拟机设置为该状态开始,将会锁定,不允许进行其他任务
				
        instance.task_state = task_states.RESIZE_PREP
        instance.progress = 0
        instance.update(extra_instance_updates)
        instance.save(expected_task_state=[None])

				//  依据参数 创建调度过滤参数
				
        filter_properties = {'ignore_hosts': []}

				// 是否允许迁移到同一台主机, 默认为False
				
        if not CONF.allow_resize_to_same_host:
            filter_properties['ignore_hosts'].append(instance.host)


				// 发送迁移状态
        if not flavor_id:
            self._record_action_start(context, instance,
                                      instance_actions.MIGRATE)
        else:
            .....
				
				
					// 获取request_spec,该参数为新的调度参数,将ignore  host加入调度
        try:
            request_spec = objects.RequestSpec.get_by_instance_uuid(
                context, instance.uuid)
            request_spec.ignore_hosts = filter_properties['ignore_hosts']
        except exception.RequestSpecNotFound:
            # Some old instances can still have no RequestSpec object attached
            # to them, we need to support the old way
            request_spec = None

        scheduler_hint = {'filter_properties': filter_properties}
        
        //resize_instance  任务迁移
        self.compute_task_api.resize_instance(context, instance,
                extra_instance_updates, scheduler_hint=scheduler_hint,
                flavor=new_instance_type,
                reservations=quotas.reservations or [],
                clean_shutdown=clean_shutdown,
                request_spec=request_spec)



该步骤主要是进行参数校验,并获取request_spec 调度参数。 调用resize_instance

resize_instance 定义

    def resize_instance(self, context, instance, extra_instance_updates,
                        scheduler_hint, flavor, reservations,
                        clean_shutdown=True, request_spec=None):
        # NOTE(comstud): 'extra_instance_updates' is not used here but is
        # needed for compatibility with the cells_rpcapi version of this
        # method.
        self.conductor_compute_rpcapi.migrate_server(
            context, instance, scheduler_hint, live=False, rebuild=False,
            flavor=flavor, block_migration=None, disk_over_commit=None,
            reservations=reservations, clean_shutdown=clean_shutdown,
            request_spec=request_spec)
三. migrate_server

调用的conductor 层的 migrate_server, 通过rpc远程调用方式进行

定义在nova/conductor/rpcapi.py

    def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
                  flavor, block_migration, disk_over_commit,
                  reservations=None, clean_shutdown=True, request_spec=None):
                  
                  ....
                  
        cctxt = self.client.prepare(version=version)
        return cctxt.call(context, 'migrate_server', **kw)        


四. conductor migrate_server

实际调用的conductor的migrate_server
该过程实际通过Manager进行处理

nova/conductor/manager.py
定义:

@profiler.trace_cls("rpc")
class ComputeTaskManager(base.Base):
    """Namespace for compute methods.

    @wrap_instance_event(prefix='conductor')
    def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
            flavor, block_migration, disk_over_commit, reservations=None,
            clean_shutdown=True, request_spec=None):
        if instance and not isinstance(instance, nova_object.NovaObject):
            # NOTE(danms): Until v2 of the RPC API, we need to tolerate
            # old-world instance objects here
            attrs = ['metadata', 'system_metadata', 'info_cache',
                     'security_groups']
            instance = objects.Instance._from_db_object(
                context, objects.Instance(), instance,
                expected_attrs=attrs)
        # NOTE: Remove this when we drop support for v1 of the RPC API
        if flavor and not isinstance(flavor, objects.Flavor):
            # Code downstream may expect extra_specs to be populated since it
            # is receiving an object, so lookup the flavor to ensure this.
            flavor = objects.Flavor.get_by_id(context, flavor['id'])
        if live and not rebuild and not
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值