1. 程式人生 > >openstack-nova原始碼虛擬機器建立流程

openstack-nova原始碼虛擬機器建立流程

nova-api接收到訊息後,呼叫nova\api\openstack\compute\servers.py 中ServersController類的create()方法,

部分程式碼:

try:             inst_type = flavors.get_flavor_by_flavor_id(                     flavor_id, ctxt=context, read_deleted="no")

            supports_multiattach = common.supports_multiattach_volume(req)             (instances, resv_id) = self.compute_api.create(context,                             inst_type,                             image_uuid,                             display_name=name,                             display_description=description,                             availability_zone=availability_zone,                             forced_host=host, forced_node=node,                             metadata=server_dict.get('metadata', {}),                             admin_password=password,                             requested_networks=requested_networks,                             check_server_group_quota=True,                             supports_multiattach=supports_multiattach,                             **create_kwargs)

這個方法最後呼叫了.compute_api.create()方法,這個實際呼叫的是nova.compute.api.API.create(),下面為這個方法的部分程式碼:

def create(self, context, instance_type,                image_href, kernel_id=None, ramdisk_id=None,                min_count=None, max_count=None,                display_name=None, display_description=None,                key_name=None, key_data=None, security_groups=None,                availability_zone=None, forced_host=None, forced_node=None,                user_data=None, metadata=None, injected_files=None,                admin_password=None, block_device_mapping=None,                access_ip_v4=None, access_ip_v6=None, requested_networks=None,                config_drive=None, auto_disk_config=None, scheduler_hints=None,                legacy_bdm=True, shutdown_terminate=False,                check_server_group_quota=False, tags=None,                supports_multiattach=False, trusted_certs=None):      (省略中間部分程式碼)

        return self._create_instance(                        context, instance_type,                        image_href, kernel_id, ramdisk_id,                        min_count, max_count,                        display_name, display_description,                        key_name, key_data, security_groups,                        availability_zone, user_data, metadata,                        injected_files, admin_password,                        access_ip_v4, access_ip_v6,                        requested_networks, config_drive,                        block_device_mapping, auto_disk_config,                        filter_properties=filter_properties,                        legacy_bdm=legacy_bdm,                        shutdown_terminate=shutdown_terminate,                        check_server_group_quota=check_server_group_quota,                        tags=tags, supports_multiattach=supports_multiattach,                        trusted_certs=trusted_certs)

這個方法最後呼叫了該類中的_create_instance方法,這個方法最後呼叫了

self.compute_task_api.schedule_and_build_instances方法

部分程式碼如下:

 def _create_instance(self, context, instance_type,                image_href, kernel_id, ramdisk_id,                min_count, max_count,                display_name, display_description,                key_name, key_data, security_groups,                availability_zone, user_data, metadata, injected_files,                admin_password, access_ip_v4, access_ip_v6,                requested_networks, config_drive,                block_device_mapping, auto_disk_config, filter_properties,                reservation_id=None, legacy_bdm=True, shutdown_terminate=False,                check_server_group_quota=False, tags=None,                supports_multiattach=False, trusted_certs=None):

               (中間部分程式碼省略)

 else:             self.compute_task_api.schedule_and_build_instances(                 context,                 build_requests=build_requests,                 request_spec=request_specs,                 image=boot_meta,                 admin_password=admin_password,                 injected_files=injected_files,                 requested_networks=requested_networks,                 block_device_mapping=block_device_mapping,                 tags=tags)

        return instances, reservation_id

而這個schedule_and_build_instances方法實際呼叫的為nova/conductor/rpcapi.py下的ComputeTaskAPI類中的schedule_and_build_instances方法,此方法定義如下:

   def schedule_and_build_instances(self, context, build_requests,                                      request_specs,                                      image, admin_password, injected_files,                                      requested_networks,                                      block_device_mapping,                                      tags=None):         version = '1.17'         kw = {'build_requests': build_requests,               'request_specs': request_specs,               'image': jsonutils.to_primitive(image),               'admin_password': admin_password,               'injected_files': injected_files,               'requested_networks': requested_networks,               'block_device_mapping': block_device_mapping,               'tags': tags}

        if not self.client.can_send_version(version):             version = '1.16'             del kw['tags']

        cctxt = self.client.prepare(version=version)         cctxt.cast(context, 'schedule_and_build_instances', **kw) 這裡的schedule_and_build_instances呼叫了訊息佇列客戶端的方法cast方法,這個cast是非同步呼叫了rpc server端的schedule_and_build_instances方法。實際這個最後呼叫了

nova/conductor/manager.py 中的ComputeTaskManager類的schedule_and_build_instances方法,部分程式碼如下:

def schedule_and_build_instances(self, context, build_requests,                                      request_specs, image,                                      admin_password, injected_files,                                      requested_networks, block_device_mapping,                                      tags=None):      (中間部分程式碼省略)         try:             host_lists = self._schedule_instances(context, request_specs[0],                     instance_uuids, return_alternates=True)         except Exception as exc:             LOG.exception('Failed to schedule instances')             self._bury_in_cell0(context, request_specs[0], exc,                                 build_requests=build_requests,                                 block_device_mapping=block_device_mapping)             return

      ...........................................................             with obj_target_cell(instance, cell) as cctxt:                 self.compute_rpcapi.build_and_run_instance(                     cctxt, instance=instance, image=image,                     request_spec=request_spec,                     filter_properties=filter_props,                     admin_password=admin_password,                     injected_files=injected_files,                     requested_networks=requested_networks,                     security_groups=legacy_secgroups,                     block_device_mapping=instance_bdms,                     host=host.service_host, node=host.nodename,                     limits=host.limits, host_list=host_list)

這個方法主要執行了兩個函式,_schedule_instances和 build_and_run_instance,前者呼叫self._schedule_instances()篩選合適的計算節點。這個方法實際上通過rpc呼叫了nova-schedule的select_destinations方法。這個select_destinations方法使用了driver的篩選方法,也就是說這個driver是可以使用者自行配置的,配置檔案預設的filter_scheduler 。後者呼叫的是nova\compute\rpcapi.py中的ComputeAPI類的build_and_run_instance方法,部分程式碼如下:

   def build_and_run_instance(self, ctxt, instance, host, image, request_spec,             filter_properties, admin_password=None, injected_files=None,             requested_networks=None, security_groups=None,             block_device_mapping=None, node=None, limits=None,             host_list=None):         # NOTE(edleafe): compute nodes can only use the dict form of limits.         if isinstance(limits, objects.SchedulerLimits):             limits = limits.to_dict()         kwargs = {"instance": instance,                   "image": image,                   "request_spec": request_spec,                   "filter_properties": filter_properties,                   "admin_password": admin_password,                   "injected_files": injected_files,                   "requested_networks": requested_networks,                   "security_groups": security_groups,                   "block_device_mapping": block_device_mapping,                   "node": node,                   "limits": limits,                   "host_list": host_list,                  }         client = self.router.client(ctxt)         version = '5.0'         cctxt = client.prepare(server=host, version=version)         cctxt.cast(ctxt, 'build_and_run_instance', **kwargs)

這個方法最後通過rpc呼叫,nova\compute\manager.py 中的ComputeManager類的build_and_run_instance方法,最後呼叫libvirt建立虛擬機器。