雲主機創建流程圖:

dashboard發創建雲主機的請求是先到novaclient,再由novaclient以http的形式發送到nova-api端,我們這里直接從nova端講起,通過wsgi映射匹配,API映射匹配可以看我的另一篇博客:OpenStack Restful API框架介紹
創建雲主機會首先調用到nova/api/openstack/compute/servers.py文件中的create()函數:
@wsgi.response(202) @extensions.expected_errors((400, 403, 409)) @validation.schema(schema_server_create_v20, '2.0', '2.0') @validation.schema(schema_server_create, '2.1', '2.18') @validation.schema(schema_server_create_v219, '2.19', '2.31') @validation.schema(schema_server_create_v232, '2.32', '2.36') @validation.schema(schema_server_create_v237, '2.37', '2.41') @validation.schema(schema_server_create_v242, '2.42') def create(self, req, body): """Creates a new server for a given user.""" ...... # 前面的代碼主要是做了傳進參數的檢查、轉換和操作的權限檢查,同時獲取鏡像 # id和flavor對象,這些處理完后會調用: (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, group_id=server_dict.get('group_id', None), os_type=server_dict.get('os_type', None), boot_type='legacy', store_id=server_dict.get('store_id', None), enable_ha=server_dict.get('enable_ha', None), thinputer_extra=server_dict.get('thinputer_extra', None), **create_kwargs)
這里是調用到了nova/compute/api.py文件中的create函數
該函數進行網絡是否有不合規操作,比如多個雲主機卻只指定了一個ip,檢查可用域,生成過濾字典,然后調用_create_instance方法
主要是初始化一些參數,檢查和檢驗參數和配額方面的檢查,生成instances、request_specs和build_requests對象,request_specs和build_requests對象用以調度選擇,instances用以返回給客戶端,值可看注解,接着函數調用:
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)
實現文件是在nova/conductor/api.py,該api.py其實是對同級下的rpcapi.py做了層封裝,真正實現在rpcapi.py文件。
api.py中的:
def schedule_and_build_instances(self, context, build_requests, request_spec, image, admin_password, injected_files, requested_networks, block_device_mapping): self.conductor_compute_rpcapi.schedule_and_build_instances( context, build_requests, request_spec, image, admin_password, injected_files, requested_networks, block_device_mapping)
這里調用了rpcapi.py中的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): version = '1.16' 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} cctxt = self.client.prepare(version=version) cctxt.cast(context, 'schedule_and_build_instances', **kw)
這里是遠程調用到了nova/conductor/manager.py中的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): legacy_spec = request_specs[0].to_legacy_request_spec_dict() try: hosts = self._schedule_instances(context, legacy_spec, request_specs[0].to_legacy_filter_properties_dict()) ..........
這個函數主要前面部分主要是先通過scheduler選擇合適的host,然后是將要創建的虛擬機的信息寫入到數據庫中,最后是調用build_and_run_instance函數,該函數實現是在nova/compute_rpcapi.py:
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): version = '4.0' cctxt = self.router.by_host(ctxt, host).prepare( server=host, version=version) cctxt.cast(ctxt, 'build_and_run_instance', 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參數遠程調用指定宿主機的build_and_run_instance方法,實現文件在nova/compute/manage.py:
@wrap_exception() @reverts_task_state @wrap_instance_fault def build_and_run_instance(self, context, instance, 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): @utils.synchronized(instance.uuid) def _locked_do_build_and_run_instance(*args, **kwargs): # NOTE(danms): We grab the semaphore with the instance uuid # locked because we could wait in line to build this instance # for a while and we want to make sure that nothing else tries # to do anything with this instance while we wait. with self._build_semaphore: self._do_build_and_run_instance(*args, **kwargs) # NOTE(danms): We spawn here to return the RPC worker thread back to # the pool. Since what follows could take a really long time, we don't # want to tie up RPC workers. utils.spawn_n(_locked_do_build_and_run_instance, context, instance, image, request_spec, filter_properties, admin_password, injected_files, requested_networks, security_groups, block_device_mapping, node, limits)
這里的關鍵點是調用到了_do_build_and_run_instance函數,該函數的關鍵代碼是調用了_build_and_run_instance函數來創建:
def _build_and_run_instance(self, context, instance, image, injected_files, admin_password, requested_networks, security_groups, block_device_mapping, node, limits, filter_properties): .......... # 這個函數的主要功能有進行事件通知、獲取所需資源、創建好網絡設備和磁盤設備,最 # 后是通過配置文件的driver選定以哪種虛擬化方式實現虛擬機的生成,這里調用的函數是: self.driver.spawn(context, instance, image_meta, injected_files, admin_password, network_info=network_info, block_device_info=block_device_info)
對應的函數實現在nova/virt/libvirt/driver.py:
def spawn(self, context, instance, image_meta, injected_files, admin_password, network_info=None, block_device_info=None): disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance, image_meta, block_device_info) injection_info = InjectionInfo(network_info=network_info, files=injected_files, admin_pass=admin_password) gen_confdrive = functools.partial(self._create_configdrive, context, instance, injection_info) self._create_image(context, instance, disk_info['mapping'], injection_info=injection_info, block_device_info=block_device_info) # Required by Quobyte CI self._ensure_console_log_for_instance(instance) # 生成libvirt所需的xml文件 xml = self._get_guest_xml(context, instance, network_info, disk_info, image_meta, block_device_info=block_device_info) self._create_domain_and_network( context, xml, instance, network_info, disk_info, block_device_info=block_device_info, post_xml_callback=gen_confdrive, destroy_disks_on_failure=True, power_on=False) LOG.debug("Instance is running", instance=instance)
在該函數中主要的功能是生成鏡像、生成xml信息,最后調用_create_domain_and_network函數進行掛載上磁盤、網絡初始化和虛擬機域生成。
虛擬機域生成通過調用了_create_domain函數來實現
