Nova API 在nova中的作用
Nova API服务是openstack nova模块的核心模块。API服务使nova计算模块的命令和控制流程,为用户提供服务。API是一个HTTP web服务,负责处理认证、授权、基本命令和控制功能。缺省情况下,nova-api监控8774端口。为了接受和处理API请求,nova-api初始化大部分流程服务(比如驱动server和创建flavors),同时初始化策略(认证、授权和配额检查)。对于一小部分请求,它通过查询数据库处理整个请求,然后返回处理后的结果。对大部分复杂的请求,通过向数据库写信息和把消息发送到队列的方式,向其它服务进程发送消息。
WSGI和Middleware
WSGI,是一个web应用服务规范、规范规定了server和application的接口。如何一个应用A基于wsgi规范定义的接口编写、它将可以在任何遵守wgsi规范的server上运行(Philli J.Eby,2003).
WSGI应用可以放入到中间件堆栈中,这些中间件必须实现WSGI的server和application两边接口。对于顶层应用、它就是一个server;然而,对于它的下层的应用,它是application。
WSGI服务器只有一个工作,就是接受client发过来的请求,将请求传递给应用,然后将应用处理后的结果返回client。Application或中间件进行详细的处理。
Webob,Routes和Paste
Routes是Rails routes的一个Python语言实现,用于URL到应用action的映射,可以直接生成URL。Routes让编写Restful的URL更加容易、花费的工作更少。
Webob是一个Python库,提供抓取wsgirequest环境、同时协助创建WSGI 响应response。Webob映射HTTP的大部分参数、包括http头解析,内容协商、正确处理条件和范围的的请求request(webob)。
Paste depolment是一个查找和配置WSGI应用和服务的系统。对于WSGI应用消费者,提供一个单例函数,简单的功能(loadappp),该函数实现从一个配置文件或python Egg中加载WSGI应用。对于应用提供者,需要一个单例、简单的入口点,这样,应用用户不需要暴露应用的具体实现细节(Paste Deployment)。
Nova API结构
Nova.wsgi.server在每个Nova APIworker进程中,以嵌入式web服务器的方式通过服务。它封装和管理WSGI服务器的一个实现evenlet版本的服务器,运行在自我管理的green线程池(大小可以配置),提供定制化的socket(监听端口、最大连接队列)。
避免把wsgi应用直接提供给WSGI server,nova.api.openstack.compute.APIRouters在一个wsgi server中绑定多个wsgi应用。这样做目的是,使每一个核心API和扩展资源应用直接,相互独立。
Nova.api.openstack.compute.APIRouter的父类Nova.wsgi.Router使用routes.middleware.RoutesMiddleware映射请求到WSGI应用。Nova.api.openstack.wsgi.Resource(nova.Application的一个实现)是定义webob抓取wsgi应用入口点和处理进来请求的地方。所有核心和扩展的API实质上是nova.api.openstack.wsgi.Resource的控制器controllers, nova.api.openstack.wsgi.Resource也负责controller方法的分发。
扩展API(Extension API)
有两种方式扩展openstack API,创建一个新的WSGI resource或者扩展已存在wsgi resource的controllers。两种方式都需要编写一个新的模块module,在模块中声明一个控制器类处理请求;实现extensions.ExtensionDescriptor注册新创建resource或控制器extensions.Multiply的resource。扩展的controller可以定义在单独的API模块。比如nova.openstack.contrib.host中的实现。
安全策略Security Policy
Nova.openstack.commn.policy强制执行安全策略。在nova/policy.json中,每一个API可以有他们自己的策略,策略可以针对API的整个操作,或者全部操作。
注,定义的规则将会递归解析,直到最后一个被解析。角色根据用户的凭证进行验证。
Nova API 服务初始化
Nova/bin/nova-api根据预配置的工作线程数量加载nova API。它创建一个wsgi server(可以根据enabled_apis配置启动多个server),server创建nova.api.openstackAPIRouter子类实例(实际上是routes.middleware.RoutesMiddleware)来处理请求分发,配置文件通过paste加载;然后,nova API使用nova.service.ProcessLauncher调用一个子进程,一直等到,直到nova-api退出。
在初始化阶段,APIRouter的子类通过routes.Mapper资源为核心和扩展API应用,建立RESTful的资源,,比如nova.api.openstack.compute.APIRtouter提供计算API。子进程,可以nova 配置文件中配置的多个进程,准备好处理http请求。
注,当为一个API配置一个或多个worker(osapi_compute_workes=3)时,子进程监听相同端口的方式是通过继承父进程打开的一个文件描述(服务套接字socket)。父进程在子进程被创建之前,创建和监听服务套接字(不提供连接)。
加载Nova API应用
Nova.wsgi.Server没有硬编码加载nova.api.opnestack.APIRouter实现,取而代之,Router及多个过滤器filter通过paste部署到wsgi服务器。相关信息放在paste配置文件中。比如,用户认证和利用率限制通过过滤器完成。Paste配置文件的名字是api-paste.ini,一般部署在/etc/nova目录下。
扩展API加载
根据osapi_compute_extension配置文件,ExtensionManager将会加载标准或选择的扩展实现。加载扩展实现的入口点定义在contrib包的初始化stage(standard_extensions和select_extensions)。标准扩展加载制定目录模块(计算和存储API的contrib包),使用标准扩展命名规范(模块的类与初始化的地方有相同的名字)。选择性模块加载nova配置文件中配置的模块。
加载过程包括两个阶段:扩展模块加载和扩展API建立,如下图所示。
处理请求
客户请求首先到达nova.api.openstac.APIRouter实例,请求传递内部的routes.middleware。通过初始化阶段建立的route映射,RouteMiddleware中间件实例将请求路由到wsgi资源。WSGI资源(核心或扩展API资源)接受请求后,nova.api.openstack.wsgi.Resource将客户请求传递给请求处理方法(index,create,delete…或者其他定制的action),请求将在这些方法中处理。
如何写核心API
1. 写一个controller,为RESTful资源实现标准动作(index,create,delete)和其他定制的操作
2. 在APIRouter实现中,建立标准Restful资源,比如compute的nova.api.opnestack.compute.APIRouter
如何写扩展API
1. 为一个新的Restful资源或已存在的资源,写一个controller实现标准操作(比如,index、create、delete…),其它定制的动作。
2. 定义extensions.ExensionDescriptor的一个子类。子类实现get_resources和get_controller_extensions方法,建立一个新的资源或控制器扩展。
3. 把controller和扩展描述类放进有同样名字的初始化的模块里。描述全部小写。这样做是为了,当系统配置为加载standard_extension时,让nova.api.openstack.extensions.load_standard_extensions识别出来。
4. 把模块放在包被加载的目录下,一般是contrib包。
5. 当创建资源扩展(extensions.ResourceExtension)时,如果需要创建一个定制资源,要提供一个custom_routes_fn,比如去除{tenant_id}路由组件。
以下是一个domcuments简单API定义扩展。Controller实现定义了5个基本操作(CRUD和LIST)。
[python]
1. class DocumentController(object):
2. “””the Document s API controller deceleration”””
3.
4. def index(self,req):
5. return a list of documents “””
6. pass
7. def create(self,req, body):
8. “””create a document “””
9. pass
10. def show(self,req, id):
11. “”” read the details of a document given its id”””
12. pass
13. def update(self, req, id, body):
14. and content “””
15. pass
16. def delete(self,req, id):
17. “””removes a document given its id”””
18. pass
19.
20. class Documents(extensions.ExtensionDescriptor):
21. “”“ExtensionDescriptor implementation”””
22. "document"
23. "os-documents"
24. "......"
25. "......"
26.
27. def get_resources(self):
28. “”” register the new Documents RESTful resource ”””
29. 'os-documents',DocumentController())]
30. return resources
31.
32. 提供以下API,
33.
34. GET v2/{tenant_id}/ os-documents
35. POST v2/{tenant_id}/ os-documents
36. GET v2/{tenant_id}/ os-documents/{document_id}
37. PUT v2/{tenant_id}/ os-documents/{document_id}
38. DELETE v2/{tenant_id}/ os-documents/{document_id}