nova创建虚拟机源码流程分析

  1. 调用/nova/api/openstack/compute/servers.py文件中ServersController类的create方法

    # 主要是调用:self.compute_api.create(...)
    self.compute_api = compute.API()
    # compute.API()指向/nova/compute/__init__.py
    CELL_TYPE_TO_CLS_NAME = {
      'api': 'nova.compute.cells_api.ComputeCellsAPI',
      'compute': 'nova.compute.api.API',
       None: 'nova.compute.api.API'
    }
    
    def _get_compute_api_class_name():
        """Returns the name of compute API class."""
        cell_type = nova.cells.opts.get_cell_type()
        return CELL_TYPE_TO_CLS_NAME[cell_type]
    
    def API(*args, **kwargs):
        class_name = _get_compute_api_class_name()
        return importutils.import_object(class_name, *args, **kwargs)
    
    # nova.cells.opts.py
    def get_cell_type():
        """Return the cell type, 'api', 'compute', or None (if cells is disabled).
        """
        if not CONF.cells.enable:
            return
        return CONF.cells.cell_type
    
  2. 调用/nova/compute/api.py文件中API类的create方法

    # 属性验证
    filter_properties = scheduler_utils.build_filter_properties(
                scheduler_hints, forced_host, forced_node, instance_type)
    ...
    # 最后调用
    self._create_instance(...)
    
  3. 调用/nova/compute/api.py文件中API类的_create_instance方法

    # 获取镜像
    image_id, boot_meta = self._get_image(context, image_href)
    # 获取实例数据
    base_options, max_net_count, key_pair, security_groups,  network_metadata = self._validate_and_build_base_options(...)
    # 获取块设备映射
    block_device_mapping = self._check_and_transform_bdm(...)
    # 获取实例组
    instance_group = self._get_requested_instance_group(...)
    # 提供实例数据
    instances_to_build = self._provision_instances(...)
    # 生成创建实例参数
    instances = []
    request_specs = []
    build_requests = []
    for rs, build_request, im in instances_to_build:
        build_requests.append(build_request)
        instance = build_request.get_new_instance(context)
        instances.append(instance)
        request_specs.append(rs)
    # 默认的CONF.cells.enable为False
    if CONF.cells.enable:
        pass
    else:
        self.compute_task_api.schedule_and_build_instances(...)
    # 方法指向
    from nova import conductor
    from nova.conductor import api as conductor_api
    ComputeTaskAPI = conductor_api.ComputeTaskAPI
    self.compute_task_api = conductor.ComputeTaskAPI()
    
  4. 调用/nova/conductor/api.py文件中ComputeTaskAPI类的schedule_and_build_instances方法

    # 直接调用
    self.conductor_compute_rpcapi.schedule_and_build_instances(...)
    # 方法指向
    from nova.conductor import rpcapi
    self.conductor_compute_rpcapi = rpcapi.ComputeTaskAPI()
    
  5. 调用/nova/conductor/rpcapi.py文件中ComputeTaskAPI类的schedule_and_build_instances方法

    cctxt.cast(context, 'schedule_and_build_instances', **kw)
    # 通过rpc服务将数据发送到mq队列中
    
  6. 调用/nova/conductor/manager.py文件中ComputeTaskManager类的schedule_and_build_instances方法

    # 获取主机列表
    host_lists = self._schedule_instances(context, request_specs[0], instance_uuids, return_alternates=True)
    # 通过for循环获取实例创建节点
    for (build_request, request_spec, host_list) in six.moves.zip(build_requests, request_specs, host_lists):
        ....
    # 获取cell
    cell = host_mapping.cell_mapping
    # ....调度
    # 调用/nova/compute/utils.py下的check_num_instances_quota方法检查配额
    compute_utils.check_num_instances_quota(...)
    # 直接调用
    self.compute_rpcapi.build_and_run_instance(...)
    # 方法指向
    from nova.compute import rpcapi as compute_rpcapi
    self.compute_rpcapi = compute_rpcapi.ComputeAPI()
    
  7. 调用/nova/compute/rpcapi.py文件中ComputeAPI类的build_and_run_instance方法

    cctxt.cast(ctxt, 'build_and_run_instance', **kwargs)
    # 通过rpc服务将数据发送到mq队列中
    
  8. 调用/nova/compute/manager.py文件中ComputeManager类下的build_and_run_instance方法

    # 执行下面的方法,其实就是启动eventlet协程
    utils.spawn_n(_locked_do_build_and_run_instance, ....)
    # 然后执行
    _locked_do_build_and_run_instance(...)
    # 最后执行
    result = self._do_build_and_run_instance(*args, **kwargs)
    
  9. 调用/nova/compute/manager.py文件中ComputeManager类下的_do_build_and_run_instance方法

    # 实例状态更新
    instance.vm_state = vm_states.BUILDING
    instance.task_state = None
    instance.save(expected_task_state=(task_states.SCHEDULING, None))
    # 最后执行
    self._build_and_run_instance(...)
    
  10. 调用/nova/compute/manager.py文件中ComputeManager类下的_build_and_run_instance方法

    # 通知数据库操作
    self._notify_about_instance_usage(...)
    compute_utils.notify_about_instance_create(...)
    # 获取请求数据
    request_group_resource_providers_mapping = self._get_request_group_mapping(request_spec)
    # 获取调度数据
    scheduler_hints = self._get_scheduler_hints(filter_properties, request_spec)
    # 调用上下文管理器方法
    with self._build_resources(...) as resources:
        ...
        with timeutils.StopWatch() as timer:
            # 生成实例,调用/nova/virt/libvirt/driver.py下的spawn方法
            self.driver.spawn(...)
    
  11. 调用/nova/compute/manager.py文件中ComputeManager类下的_build_resources方法

    # 准备网络数据
    network_info = self._build_networks_for_instance(
      context, instance, requested_networks, security_groups, resource_provider_mapping
    )
    resources['network_info'] = network_info
    # 准备块设备
    block_device_info = self._prep_block_device(context, instance, block_device_mapping)
        -> 调用`/nova/compute/manager.py`中`ComputeManager`类下`_prep_block_device`方法
        -> 调用`/nova/virt/block_device.py`中`attach_block_devices`方法
         def attch_block_devices(block_device_mapping, *attach_args, **attach_kwargs):
             def _log_and_attch(bdm):
                 bdm.attch(*attach_args, **attach_kwargs)
             for device in block_device_mapping:
                 _log_and_attach(device)
             return block_device_mapping
      -> # for循环中分别是执行`/nova/virt/block_device.py`下`DriverVolumeBlockDevice`,
         # `DriverVolSnapshotBlockDevice`,`DriverVolImageBlockDevice`,`DriverVolBlankBlockDevice`等类
         # 下`attch`方法,按需执行,不一定四个`attch`方法全部执行,根据参数确定执行哪些。
         # 下面以`DriverVolumeBlockDevice`下的`attch`方法为例说明。
      -> 调用`/nova/virt/block_device.py`下`DriverVolumeBlockDevice`类的`attach`方法
         # 主要是执行self._do_attach(...)方法。
         # self._do_attch()方法下主要是执行self._volume_attach(...)或self._legacy_volume_attach(...)方法。
         # self._volume_attach(...)或self._legacy_volume_attach(...)方法主要执行了
         # virt_driver.attach_volume(...)方法。
         # 由于使用的是livirt驱动方式,所以virt_driver即为/nova/virt/libvirt/dirver.py下的LibvirtDriver类。
                -> 即调用`LibvirtDriver`类下的`attach_volume(...)`方法
                # 主要是调用self._connect_volume(context, connection_info, instance, encryption=encryption)
                # 获取卷驱动:vol_driver = self._get_volume_driver(connection_info)
                # 连接卷:vol_driver.connect_volume(connection_info, instance)
                -> # 加密连接:self._attach_encryptor(context, connection_info, encryption, allow_native_luks)
            -> # 执行encryptor._format_volume(...)或encryptor.attach_volume(...)方法进行卷处理
      -> 最终通过eventlet.event进行处理,主要是数据库操作,关联镜像,网络和存储数据
    
  12. 调用/nova/virt/libvirit/driver.py文件中LibvirtDriver类下的spawn方法

    # 获取磁盘数据
    disk_info = blockinfo.get_disk_info(...)
    # 注入数据处理
    injection_info = InjectionInfo(...)
    # 配置数据源处理
    gen_confdrive = functools.partial(self._create_configdrive, ...)
      -> cdb = configdrive.ConfigDriveBuilder(instance_md=inst_md)
      -> with cdb:
            ...
            cdb.make_drive(config_disk_local_path)
      -> 调用/nova/virt/configdrive.py文件中ConfigDriveBuilder泪下的make_drive方法
         # CONF.config_drive_format默认值为iso9660
         # 执行self._make_iso9660(path, tmpdir)
         # 最终调用processutils.execute(...)方法
         # from oslo_concurrency import processutils
      # 虚拟机路径,磁盘处理
      created_instance_dir, created_disks = self._create_image(...)
    # 获取实例用户的xml格式数据
    xml = self._get_guest_xml(...)
    # 分配虚拟cpu介导设备
    mdevs = self._allocate_mdevs(allocations)
    # 生成一个xml文件
    xml = self._get_guest_xml(context, instance, network_info, disk_info, image_meta, block_device_info=block_device_info, mdevs=mdevs)
    # 域和网路处理
    self._create_domain_and_network(context, xml, ...)
    
  1. 调用/nova/virt/libvirit/driver.py文件中LibvirtDriver类下的_create_domain_and_network方法

    # 执行下面方法
    guest = self._create_domain(xml, pause=pause, power_on=power_on, post_xml_callback=post_xml_callback)
    # /nova/virt/libvirt/guest.py文件下
    guest = libvirt_guest.Guest.create(xml, self._host)
    # /nova/virt/libvirt/host.py文件下
    guest = host.write_instance_config(xml)
    domain = self.get_connection().defineXML(xml)       # 相当于执行命令:virsh define ***.xml
    # 此时已经创建了虚拟机,启动虚拟机时执行命令:virsh start ***
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容