此处以OpenStack mitaka版本为例,实际最新的Ocata版本也差不多,以创建一个虚拟机为例来分析nova源码中执行流程,该流程有助于二次开发,阅读源码前最好先熟悉一下pastedeploy、webob、stevedore等openstack中的核心库,以及rpc消息通信机制。
安装完OpenStack后,所有的源码在/usr/lib//usr/lib/python2.7/site-packages/目录下,nova服务器端源码在nova目录中,客户端源码在novaclient目录中,动态加载nova插件的映射文件在nova-XXXX-info目录中的entry_points.txt文件中。
客户端:
novaclient在初始化的过程会把/nova/v2/下所有的xxxxManager类加载进来,并通过_construct_http_client()构造一个HTTPClient对象,用来发送url请求,每个xxxxManger类都直接或间接继承了base.ManagerWithFind类,xxxxManager类中的方法主要用来构造url格式、请求参数、请求方法。客户端创建虚拟机的请求对应在/novaclient/v2/servers.py中的_boot()方法,该方法调用了基类Manager中的_create()方法。
服务器端:
nova在接收到客户端的请求后,会通过pastedeploy加载/etc/nova/api-paste.ini配置文件来完成url的映射、认证、请求等,配置文件中包含了四类部件app(应用程序)、filter(过滤器)、pipeline(管道)、composite(复合体)。
[composite:openstack_compute_api_v21]
use = call:nova.api.auth:pipeline_factory_v21
noauth2 = cors compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21
/v2: openstack_compute_api_v21_legacy_v2_compatible
/v2.1: openstack_compute_api_v21
根据客户端请求的版本,此处是v2.1,继续进入openstack_compute_api_v21这个管道体。
[composite:openstack_compute_api_v21]
use = call:nova.api.auth:pipeline_factory_v21
noauth2 = cors compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21
keystone = cors compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21
首先,通过pipeline_factory_v21()方法选择认证策略,默认配置文件/etc/nova/nova.conf中的认证策略auth_strategy为keystone。然后,会进入keystone管道体,前面一系列cors compute_req_id faultwrap sizelimit authtoken keystonecontext为过滤器,auth_token是OpenStack中各个组件交互时来完成安全认证的,其调用的核心方法为/keystonemiddleware/auth_token中的_do_fetch_token(),osapi_compute_app_v21为具体的应用,nova主要的功能都在该应用中实现。
[app:osapi_compute_app_v21]
paste.app_factory=nova.api.openstack.compute:APIRouterV21.factory
该应用程序调用了APIRouterV21类对应的工厂方法factory(),该方法在其父类/nova/api/openstack/APIRouterV21中实现,其创建了一个APIRouterV21()实例,其初始化方法通过如下代码完成插件的动态加载。
self.api_extension_manager = stevedore.enabled.EnabledExtensionManager(
namespace=self.api_extension_namespace(),
check_func=_check_load_extension,
invoke_on_load=True,
invoke_kwds={"extension_info": self.loaded_extension_info})
其中,通过mapper = ProjectMapper()完成所有插件的url映射,_register_controllers()方法将所有插件对应XXXXController类中的方法进行注册,指定mapper所对应的具体action动作。以创建虚拟机为例,其将会调用/nova/api/openstack/compute/servers.py中的create()方法,该方法调用了/nova/compute/api.py中的create()方法,该方法中会检测用户权限,并调用了_create_instance()方法,该方法中完成虚拟机创建的准备工作。其后,调用了/nova/conductor/api.py中的build_instances()方法,该方法通过/nova/conductor/rpcapi.py中的build_instances()方法发送创建虚拟机的rpc消息。
cctxt.cast(context, 'build_instances', **kw)
随后,会执行manager.py中的build_instances()方法,该方法会通过_schedule_instances()方法完成虚拟机的调度,其中也涉及到rpc消息通信,调用的核心方法在filter_scheduler.py中的select_destinations(),此处不展开说明了,build_instances()调用了/nova/compute/rpcapi.py中的build_and_instance()方法发送rpc消息,请求创建虚拟机。
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)
最终,/nova/compute/manager.py中的build_and_run_instance()方法会完成虚拟机的创建,其调用的核心方法为driver.spawn(),具体的driver由/etc/nova/nova.conf中的compute_driver指定。