美文网首页
nova创建虚拟机源码流程分析

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

作者: 君致 | 来源:发表于2020-12-16 13:37 被阅读0次
    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 ***
      

    相关文章

      网友评论

          本文标题:nova创建虚拟机源码流程分析

          本文链接:https://www.haomeiwen.com/subject/tjbngktx.html