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建立虛擬機器。