nova resize虚拟机接口分析1

本文详细描述了Nova框架中nova-api和nova-conductor服务关于虚拟机resize操作的实现,包括状态检查、资源分配、迁移类型区分、主机调度和预处理步骤。着重讲解了冷迁移和resize接口的逻辑以及相关异常处理。
摘要由CSDN通过智能技术生成

1. nova-api服务入口

#nova/compute/api.py
class API(base.Base):
    #检测vm是否有锁,或者在进行其他任务,存在锁则不能resize
    @check_instance_lock
    #检测vm是否是ACTIVE或者STOPPED状态,该接口不支持其他状态虚拟机
    @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED])
    #检测vm所在宿主机是否UP,没有up则不能进行resize
    @check_instance_host(check_is_up=True)
    def resize(self, context, instance, flavor_id=None, clean_shutdown=True,
               host_name=None, **extra_instance_updates):

        #在resize 虚拟机配置时host_name一直为空,只有在冷迁移虚拟机时可以被指定
        if host_name is not None:
            #冷迁移时,判断host_naame是否是虚拟机当前所在宿主机,如果是抛异常CannotMigrateToSameHost,如果不是则判断host_name对应的主机是否存在
            if host_name == instance.host:
                raise exception.CannotMigrateToSameHost()

            # Check whether host exists or not.
            node = objects.ComputeNode.get_first_node_by_host_for_old_compat(
                context, host_name, use_slave=True)

        #在resize虚拟机时,可以选择对磁盘自动或者手动进行分区,
        # 此时就需要与原来的虚拟机的这个配置进行对比,验证resize时这个分区参数的有效性
        # 如果虚拟机原来是关闭自动分区的,此时resize时再开启自动分区就会抛异常 exception.AutoDiskConfigDisabledByImage,结束resize操作
        self._check_auto_disk_config(instance, **extra_instance_updates)

        current_instance_type = instance.get_flavor()
        volume_backed = None
        # 如果调用resize接口时没有提供flavor_id,那么就是迁移虚拟机
        if not flavor_id:
            LOG.debug("flavor_id is None. Assuming migration.",
                      instance=instance)
            new_instance_type = current_instance_type
        else:
            new_instance_type = flavors.get_flavor_by_flavor_id(
                    flavor_id, read_deleted="no")
            #如果resize时选择的flavor根磁盘为0,并且vm的原来配置的flavor的根磁盘不为0
            #  如果vm的根磁盘没有使用卷存储volume_backed,抛异常CannotResizeDisk
            if (new_instance_type.get('root_gb') == 0 and
                    current_instance_type.get('root_gb') != 0):
                volume_backed = compute_utils.is_volume_backed_instance(
                        context, instance)
                if not volume_backed:
                    reason = _('Resize to zero disk flavor is not allowed.')
                    raise exception.CannotResizeDisk(reason=reason)

        current_instance_type_name = current_instance_type['name']
        new_instance_type_name = new_instance_type['name']
        LOG.debug("Old instance type %(current_instance_type_name)s, "
                  "new instance type %(new_instance_type_name)s",
                  {'current_instance_type_name': current_instance_type_name,
                   'new_instance_type_name': new_instance_type_name},
                  instance=instance)

        #根据flavor的id判断是不是同一个flavor,如果不是且新的flavor disabled就抛异常FlavorNotFound,如果是也抛异常CannotResizeToSameFlavor
        same_instance_type = (current_instance_type['id'] ==
                              new_instance_type['id'])
        if not same_instance_type and new_instance_type.get('disabled'):
            raise exception.FlavorNotFound(flavor_id=flavor_id)
        if same_instance_type and flavor_id:
            raise exception.CannotResizeToSameFlavor()

        # 如果flavor_id存在,则是进行resize操作,此时需要判断用户是否有足够的配额进行resize操作
        # 这里主要判断cpu和内存配额,如果没有足够配额抛出异常TooManyInstances
        if flavor_id:
            self._check_quota_for_upsize(context, instance,
                                         current_instance_type,
                                         new_instance_type)

        if not same_instance_type:
            image = utils.get_image_from_system_metadata(
                instance.system_metadata)
            if volume_backed is None:
                volume_backed = compute_utils.is_volume_backed_instance(
                    context, instance)
            # 如果用了后端存储,只需要验证新flavor和image的numa和pci的有效性,看看是否存在冲突
            if volume_backed:
                # 主要验证内存加密(hw:mem_encryption)、PMU特性(hw:pmu)、serial_port_count(hw:serial_port_count)、 cpu实时性(hw:cpu_realtime)
                self._validate_flavor_image_numa_pci(
                    image, new_instance_type, validate_pci=True)
            else:
                # 验证disk相关配置,然后再进行上面内存加密等的验证
                self._validate_flavor_image_nostatus(
                    context, image, new_instance_type, root_bdm=None,
                    validate_pci=True)

        filter_properties = {'ignore_hosts': []}
        #如果不允许resize虚拟机到当前宿主机,则将当前宿主机存入不被调入的主机列表中
        if not CONF.allow_resize_to_same_host:
            filter_properties['ignore_hosts'].append(instance.host)

        request_spec = objects.RequestSpec.get_by_instance_uuid(
            context, instance.uuid)
        request_spec.ignore_hosts = filter_properties['ignore_hosts']

        if not same_instance_type:
            request_spec.numa_topology = hardware.numa_get_constraints(
                new_instance_type, instance.image_meta)
        #修改虚拟机状态
        instance.task_state = task_states.RESIZE_PREP
        instance.progress = 0
        instance.update(extra_instance_updates)
        instance.save(expected_task_state=[None])

        #如果没有提供flavor_id,则更新虚拟机状态为MIGRATE,否则为RESIZE
        if not flavor_id:
            self._record_action_start(context, instance,
                                      instance_actions.MIGRATE)
        else:
            self._record_action_start(context, instance,
                                      instance_actions.RESIZE)

        scheduler_hint = {'filter_properties': filter_properties}

        if host_name is None:
            request_spec.requested_destination = None
        else:
            request_spec.requested_destination = objects.Destination(
                host=node.host, node=node.hypervisor_hostname)

        self.compute_task_api.resize_instance(context, instance,
            scheduler_hint=scheduler_hint,
            flavor=new_instance_type,
            clean_shutdown=clean_shutdown,
            request_spec=request_spec)

# nova/conductor/api.py
class ComputeTaskAPI(object):
    """ComputeTask API that queues up compute tasks for nova-conductor."""

    def __init__(self):
        self.conductor_compute_rpcapi = rpcapi.ComputeTaskAPI()

    #冷迁移以及resize都走该入口
    def resize_instance(self, context, instance, scheduler_hint, flavor,
                        reservations=None, clean_shutdown=True,
                        request_spec=None, host_list=None):
        #注意这里传的参数:live=False, rebuild=False,flavor=flavor
        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, host_list=host_list)

#nova/conductor/rpcapi.py
class ComputeTaskAPI(object):
    #发送rpc到conductor请求进行resize虚拟机操作
    def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
                  flavor, block_migration, disk_over_commit,
                  reservations=None, clean_shutdown=True, request_spec=None,
                  host_list=None):
        kw = {'instance': instance, 'scheduler_hint': scheduler_hint,
              'live': live, 'rebuild': rebuild, 'flavor': flavor,
              'block_migration': block_migration,
              'disk_over_commit': disk_over_commit,
              'reservations': reservations,
              'clean_shutdown': clean_shutdown,
              'request_spec': request_spec,
              'host_list': host_list,
              }
        cctxt = self.client.prepare(version=version)
        return cctxt.call(context, 'migrate_server', **kw)

2. nova-conductor服务入口

#nova/conductor/manager.py
class ComputeTaskManager(base.Base): 
#支持热迁移、冷迁移和resize
   def migrate_server(self, context, instance, scheduler_hint, live, rebuild,
            flavor, block_migration, disk_over_commit, reservations=None,
            clean_shutdown=True, request_spec=None, host_list=None):
        #没有提供flavor时,且live and not rebuild时,进行热迁移
        if live and not rebuild and not flavor:
            self._live_migrate(context, instance, scheduler_hint,
                               block_migration, disk_over_commit, request_spec)
        #提供flavor时,且not live and not rebuild时,进行冷迁移
        #在resize接口调用该接口时,传如下参数:live=False, rebuild=False,flavor=flavor
        elif not live and not rebuild and flavor:
            instance_uuid = instance.uuid
            with compute_utils.EventReporter(context, 'cold_migrate',
                                             self.host, instance_uuid):
                self._cold_migrate(context, instance, flavor,
                                   scheduler_hint['filter_properties'],
                                   clean_shutdown, request_spec,
                                   host_list)
        else:
            raise NotImplementedError()

    def _cold_migrate(self, context, instance, flavor, filter_properties,
                      clean_shutdown, request_spec, host_list):
        request_spec = self._get_request_spec_for_cold_migrate(
            context, instance, flavor, filter_properties, request_spec)

        task = self._build_cold_migrate_task(context, instance, flavor,
                request_spec, clean_shutdown, host_list)
        try:
            #创建迁移任务执行迁移操作
            task.execute()
        except exception.NoValidHost as ex:
            vm_state = instance.vm_state

3. task.execute()对应入口

#nova/conductor/tasks/migrate.py

class MigrationTask(base.TaskBase): 
 def _execute(self):
        #根据请求的参数生成过滤条件,
        #比如:legacy_props={"ignore_hosts":xxx, "force_hosts":, "retry":xxx,"scheduler_hints":xx}
        legacy_props = self.request_spec.to_legacy_filter_properties_dict()
        #设置服务组信息
        scheduler_utils.setup_instance_group(self.context, self.request_spec)
        #如果没有设置目的主机,则设置retry配置
        if not ('requested_destination' in self.request_spec and
                    self.request_spec.requested_destination and
                        'host' in self.request_spec.requested_destination):
            scheduler_utils.populate_retry(legacy_props,
                                           self.instance.uuid)
        #清空请求体request_spec中的fore_hosts和fore_nodes信息
        self.request_spec.reset_forced_destinations()
        #获取虚拟机网络信息
        port_res_req = self.network_api.get_requested_resource_for_instance(
            self.context, self.instance.uuid)
        self.request_spec.requested_resources = port_res_req
        #根据虚拟机cell信息设置requested_destination
        self._restrict_request_spec_to_cell(legacy_props)
        #创建migration记录
        migration = self._preallocate_migration()
        #确保project、user和network
        self.request_spec.ensure_project_and_user_id(self.instance)
        self.request_spec.ensure_network_metadata(self.instance)
        #保存“root disk是否是卷”bool值到请求体中
        compute_utils.heal_reqspec_is_bfv(
            self.context, self.request_spec, self.instance)

        #调用nova schedule进行主机调度
        if self.host_list is None:
            selection = self._schedule()

        else:
            # This is a reschedule that will use the supplied alternate hosts
            # in the host_list as destinations.
            selection = self._reschedule()

        #把选定的主机加入到retry host列表中,如果重新调度就会忽略当前的主机
        scheduler_utils.populate_filter_properties(legacy_props, selection)

        legacy_props.pop('context', None)

        (host, node) = (selection.service_host, selection.nodename)

        self.instance.availability_zone = (
            availability_zones.get_host_availability_zone(
                self.context, host))
        #发送rpc请求到目的节点进行resize操作
        self.compute_rpcapi.prep_resize(
            self.context, self.instance, self.request_spec.image,
            self.flavor, host, migration,
            request_spec=self.request_spec, filter_properties=legacy_props,
            node=node, clean_shutdown=self.clean_shutdown,
            host_list=self.host_list)

后面再就nova-schedule调度以及nova-compute resize分别进行分析。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟简介 2-6 java的垃圾回收器 2-7 java上练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
好的,以下是对cv2.resize源码进行的分析: cv2.resize函数的源码实现非常复杂,主要分为三个部分:计算输出图像的大小、创建输出图像、对输入图像进行缩放并输出。 第一部分:计算输出图像的大小 如果指定了输出图像的大小,则根据指定的大小计算缩放比例。如果没有指定大小,而是指定了缩放比例,则根据缩放比例计算输出图像的大小。如果既没有指定大小也没有指定缩放比例,则输出图像的大小与输入图像大小相同。 第二部分:创建输出图像 根据计算出的输出图像大小创建一个全0的输出图像。 第三部分:对输入图像进行缩放并输出 根据指定的插值方法对输入图像进行缩放,并将结果输出到输出图像中。cv2.resize支持的插值方法有四种:最近邻插值(INTER_NEAREST)、双线性插值(INTER_LINEAR)、区域插值(INTER_AREA)和双三次插值(INTER_CUBIC)。 最近邻插值的实现方式是对每个输出像素,找到其在输入图像中对应的最近邻像素,并将其值赋给输出像素。 双线性插值的实现方式是对每个输出像素,计算其在输入图像中对应的4个最近邻像素,并根据其距离和权重计算插值结果。 区域插值的实现方式是对每个输出像素,计算其在输入图像中对应的区域,并将该区域内像素的平均值赋给输出像素。 双三次插值的实现方式是对每个输出像素,计算其在输入图像中对应的16个最近邻像素,并根据其距离和权重计算插值结果。 需要注意的是,cv2.resize在实现过程中,对输入图像进行了多次遍历,因此处理大图像时可能会比较耗时。此外,不同的插值方法对图像质量的影响是不同的,应根据具体应用场景选择合适的插值方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值