OpenStack中的API结构地图

1. OpenStack中的API结构地图

当你执行如下命令的时候:

里面做了什么呢?

OpenStack中的API结构地图_第1张图片

在这张图中我们加了--debug就看得更清楚了。

具体来说它是由两次http请求构成的。

分别是

(1)向keystone验证

REQ: curl -i 'http://ubuntu80:35357/v2.0/tokens' -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -d '{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin", "password": "{SHA1}5705cc2e5fda0ab7529d5093c5e389fffe45d615"}}}'

(2)调用nova-api取得所有实例(虚机)

REQ: curl -i 'http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e/servers/detail' -X GET -H "Accept: application/json" -H "User-Agent: python-novaclient" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: {SHA1}5962c90ceb8f53d805382c386ac240776fe55a54"

我们从上面的例子中看到了一条条URL,而这些URL构成了整个OpenStack API的基础。本文的目的在于,通过这一条条可见的URL找到与OpenStack相关的源码(类或方法),从而迅速定位代码点。


2. OpenStack中的地图配置文件

 查找api-paste.ini,为什么找这个配置文件,可以查看我的另外一篇文章(《Paste模块的世界》http://my.oschina.net/crooner/blog/606895  )。

我的这台服务器上安装了nova,glance,neutron(说明一下,我这里是JUNO版本),这里主要介绍nova,打开它吧。

nano  /etc/api-paste.ini

OpenStack中的API结构地图_第2张图片

OpenStack中的API结构地图_第3张图片

看到里面的注释,Metadata,EC2,OpenStack,社区还是很贴心的哇,一看就很清楚。

因为nova api主要就分成三个部分,关于metadata的部分可以参看我的另外一篇(《扩展OpenStack的nova metadata api》http://my.oschina.net/crooner/blog/603044  )。这里主要是介绍OpenStack API部分。

我把这部分内容抽出来

#############
# OpenStack #
#############

[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/: oscomputeversions
/v1.1: openstack_compute_api_v2
/v2: openstack_compute_api_v2
/v2.1: openstack_compute_api_v21
/v3: openstack_compute_api_v3

[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/: oscomputeversions
/v1.1: openstack_compute_api_v2
/v2: openstack_compute_api_v2
/v2.1: openstack_compute_api_v21
/v3: openstack_compute_api_v3

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth = compute_req_id faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2

[composite:openstack_compute_api_v21]
use = call:nova.api.auth:pipeline_factory_v21
noauth = request_id faultwrap sizelimit noauth osapi_compute_app_v21
keystone = request_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v21

[composite:openstack_compute_api_v3]
use = call:nova.api.auth:pipeline_factory_v21
noauth = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3
keystone = request_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3

[filter:request_id]
paste.filter_factory = nova.openstack.common.middleware.request_id:RequestIdMiddleware.factory


[filter:request_id]
paste.filter_factory = nova.openstack.common.middleware.request_id:RequestIdMiddleware.factory


[filter:compute_req_id]
paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory

[filter:faultwrap]
paste.filter_factory = nova.api.openstack:FaultWrapper.factory

[filter:noauth]
paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory

[filter:noauth_v3]
paste.filter_factory = nova.api.openstack.auth:NoAuthMiddlewareV3.factory

[filter:ratelimit]
paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory

[filter:sizelimit]
paste.filter_factory = nova.api.sizelimit:RequestBodySizeLimiter.factory

[app:osapi_compute_app_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

[app:osapi_compute_app_v21]
paste.app_factory = nova.api.openstack.compute:APIRouterV21.factory

[app:osapi_compute_app_v3]
paste.app_factory = nova.api.openstack.compute:APIRouterV3.factory

[pipeline:oscomputeversions]
pipeline = faultwrap oscomputeversionapp

[app:oscomputeversionapp]
paste.app_factory = nova.api.openstack.compute.versions:Versions.factory

这个就是一地图啊,它告诉你里面是怎么回事,如果你已经看过Paste模块的世界》http://my.oschina.net/crooner/blog/606895 。

你就知道这样一个配置文件描述了一套路由系统(管道走向)及对应的factory关系。

无论怎样吧,我们还是需要分析一下里面的路径。

我们以v2版的API为例,下面的部分是我抽出来,需要重点关注的:

[composite:osapi_compute]
use = call:nova.api.openstack.urlmap:urlmap_factory
/: oscomputeversions
/v1.1: openstack_compute_api_v2
/v2: openstack_compute_api_v2
/v2.1: openstack_compute_api_v21
/v3: openstack_compute_api_v3

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth = compute_req_id faultwrap sizelimit noauth ratelimit osapi_compute_app_v2
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2
[app:osapi_compute_app_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

根据上面三部分,我们知道composite为起分发作用(多通管道/多口的接头管道),其中v2指向openstack_compute_api_v2。

就是下面的openstack_compute_api_v2的composite,在里面我们看到noauth,keystone,keystone_nolimit通过许多个filter之后最终都是到达osapi_compute_app_v2这个app的。

来到第三部分,这就很直接了,这个app的factory是nova.api.openstack.compute:APIRouter.factory。

nova.api.openstack.compute就是路径(python的包结构,如果熟悉java的朋友com.apache.xxx,是不是倍感亲切 :)),后面APIRouter.factory就是一个类了。


3. 一探究竟

那么进入nova.api.openstack.compute,对应的就是

locate nova/api/openstack/compute

直接找到对应目录,然后进入查看。

OpenStack中的API结构地图_第4张图片

既然是nova.api.openstack.compute指的自然就是__init__.py这个文件了(python基础语法知识)。

打开__init__.py文件,查找到APIRouter的factory方法。

OpenStack中的API结构地图_第5张图片

APIRouter找到了,一直往下拉都没找到factory方法,猜想一定是OpenStack的小伙伴们做了封装。

我们看到APIRouter是继承自nova.api.openstack.APIRouter的。

好吧,我们去看看nova.api.openstack.APIRouter吧

OpenStack中的API结构地图_第6张图片

OpenStack中的API结构地图_第7张图片

果然,里面有了factory方法。

这里说明一下,可以使用LOG.error()打印信息到/var/log/nova/nova-api.log。

这里可以得出这样的结论:

nova.api.openstack.compute.APIRouter类继承自nova.api.openstack.APIRouter,在nova.api.openstack.APIRouter内部的__init__方法中,最重要的几句:

mapper = ProjectMapper()

self._setup_routes(mapper, ext_mgr, init_only)

self._setup_ext_routes(mapper, ext_mgr, init_only)

我们知道这几句产生了整个map路由(注:这里主要涉及到routes模块),特别要注意的是

self._setup_routes(mapper, ext_mgr, init_only)

它生成了主要的URL规则(你可以通过调试看到),在nova.api.openstack.APIRouter中的 _setup_routes方法:

它只是抛出了一个异常,那么它必然被子类所实现。

回到nova.api.openstack.compute.APIRouter中的_setup_routes方法:

OpenStack中的API结构地图_第8张图片

OpenStack中的API结构地图_第9张图片

非常明显,这里注意mapper.resource方法,它会自动生成相关的RESTful API URL,如果朋友们有兴趣可以试一下routes模块的mapper.resource方法。

还有要提一下:

mapper.redirect("", "/")

这句起了重定向的作用

在我的博客(WSGI必知必会 http://my.oschina.net/crooner/blog/609030  )的“7. 路由处理”中的最后两个例子中都有提到使用到这句,单独的例子中易于直观感受它的作用。


4. 相关的py文件怎么与API关联起来的?

还是接着上面的例子,我们看到nova.api.openstack.compute.APIRouter中的_setup_routes方法

我们还是以servers为例:

OpenStack中的API结构地图_第10张图片

可以看到,里面最重要的依据就是:

self.resources['servers'] = servers.create_resource(ext_mgr)

回到目录结构:

OpenStack中的API结构地图_第11张图片

找到servers.py中的create_resource方法:

可以看到,这里将Controller对象放入wsgi.Resource方法调用。

Controller中是本servers.py中最重要的部分,里面有主要的API包括,detail,index...等方法,这里请记住detail,我们会在后面的例子中用到。

还有要注意的是,在Controller的__init__构造方法中,加载了compute.API()

self.compute_api = compute.API()

它将compute.API()实例化放入self.compute_api供调用。

回到话题的中心,.py是怎么关联API的呢,这里尤其是servers,py怎么关联API(URL:xxx/servers/xxx)的。

回到images.py头部,看到

OpenStack中的API结构地图_第12张图片

from nova.api.openstack import wsgi

那么就可以在下面的路径中找到wsgi.py

定位到Resource类中的__init__方法与register_actions方法之间看到:

OpenStack中的API结构地图_第13张图片

register_actions中加载进对应的controller中的所有方法。

即:将所有API通过wsgi.Resource将对应Controller中的所有方法加载进来。

看到整个的调用链:

api-paste.ini -> /v2: openstack_compute_api_v2 -> osapi_compute_app_v2 -> nova.api.openstack.compute:APIRouter -> self._setup_routes -> xx.create_resource() -> wsgi.Resource(Controller()) -> wsgi.Resource.register_actions()


5. 反推测试结论,添加自定义nova api

由上面的结论得出,在nova-api服务启动时,对应的URL与相应的类和方法就会被加载。

那么以v2版本的nova api为例,最重要的部分应该是在nova.api.openstack.compute.APIRouter中的_setup_routes,它决定了各个类和方法与URL的对应。

那么反过来,如果我们希望自己添加一个v2 API,只需要nova.api.openstack.compute.APIRouter中的_setup_routes中添加即可。

下面我们以images为模板,添加一个test_images,进入nova.api.openstack.compute(如下目录):

执行:

cp images.py test_images.py
nano test_images.py

在打开test_images.py后,找到Controller中的detail方法修改如下:

OpenStack中的API结构地图_第14张图片

接下来就应该建立URL与这个类文件的对应了

退出test_images.py,进入nova.api.openstack.compute,打开__init__.py进行编辑

首先在头部导入模块:

from nova.api.openstack.compute import test_images

OpenStack中的API结构地图_第15张图片

接着就可以来到nova.api.openstack.compute.APIRouter中的_setup_routes

将test_images添加进来

OpenStack中的API结构地图_第16张图片

好了,一切大功告成!这个测试的api就添加完成了。


6. 测试添加的自定义API

在上面的步骤中,我们添加了自定义的API (xxx/test_images/detail),接下来我们通过curl来进行测试。

这个步骤分两步,第一步取得keystone的token,第二部执行我们自己的api。

在第一节中,我们演示过正常查看内部请求的过程

nova --debug list

这里我们截取一下里面的请求为我们所用

curl -i 'http://ubuntu80:35357/v2.0/tokens' -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -d '{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin", "password": "{SHA1}5705cc2e5fda0ab7529d5093c5e389fffe45d615"}}}'

修改成:

curl -i 'http://ubuntu80:35357/v2.0/tokens' -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -d '{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin", "password": "ADMIN_PASS"}}}'

注意这里将{SHA1}5705cc2e5fda0ab7529d5093c5e389fffe45d615修改成ADMIN_PASS,这个ADMIN_PASS是你的OpenStack密码。

执行之后,结果如下:

root@ubuntu80:/# curl -i 'http://ubuntu80:35357/v2.0/tokens' -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "User-Agent: python-novaclient" -d '{"auth": {"tenantName": "admin", "passwordCredentials": {"username": "admin", "password": "ADMIN_PASS"}}}'
HTTP/1.1 200 OK
Vary: X-Auth-Token
X-Distribution: Ubuntu
Content-Type: application/json
Content-Length: 1744
Date: Tue, 26 Jan 2016 02:18:41 GMT
{"access": {"token": {"issued_at": "2016-01-26T02:18:41.487301", "expires": "2016-01-26T03:18:41Z", "id": "a479cdb5f5ce47aebccd15f1790beb2c", "tenant": {"description": "Admin Tenant", "enabled": true, "id": "0e962df9db3f4469b3d9bfbc5ffdaf7e", "name": "admin"}, "audit_ids": ["eavCb8mjT863hnOxhdxUwQ"]}, "serviceCatalog": [{"endpoints": [{"adminURL": "http://ubuntu80:9292", "region": "regionOne", "internalURL": "http://ubuntu80:9292", "id": "4794a2d722ab4f6bbda00d779c1410d1", "publicURL": "http://ubuntu80:9292"}], "endpoints_links": [], "type": "image", "name": "glance"}, {"endpoints": [{"adminURL": "http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e", "region": "regionOne", "internalURL": "http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e", "id": "a8ccc19100934fc1ae7c899dc5e17bdd", "publicURL": "http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e"}], "endpoints_links": [], "type": "compute", "name": "nova"}, {"endpoints": [{"adminURL": "http://ubuntu80:9696", "region": "regionOne", "internalURL": "http://ubuntu80:9696", "id": "656371fd3163415c95ff2fc0facbe5e1", "publicURL": "http://ubuntu80:9696"}], "endpoints_links": [], "type": "network", "name": "neutron"}, {"endpoints": [{"adminURL": "http://ubuntu80:35357/v2.0", "region": "regionOne", "internalURL": "http://ubuntu80:5000/v2.0", "id": "4f1d53f12dc6485cb5816c83f68b7053", "publicURL": "http://ubuntu80:5000/v2.0"}], "endpoints_links": [], "type": "identity", "name": "keystone"}], "user": {"username": "admin", "roles_links": [], "id": "96a7c834b3f8485c87d79df7b6480c92", "roles": [{"name": "_member_"}, {"name": "admin"}], "name": "admin"}, "metadata": {"is_admin": 0, "roles": ["9fe2ff9ee4384b1894a90878d3e92bab", "fc2574382dd74936b1bc85cc2110c3c2"]}}}root@ubuntu80:/#

这里获取了token的id为

a479cdb5f5ce47aebccd15f1790beb2c

这里备用

在第一节中还有第二条curl请求,我们将其修改一下:

curl -i 'http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e/servers/detail' -X GET -H "Accept: application/json" -H "User-Agent: python-novaclient" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: {SHA1}5962c90ceb8f53d805382c386ac240776fe55a54"

修改如下,这里主要修改URL为http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e/test_images/detail,并修改token为我们第一步通过keystone获取的token:

curl -i 'http://ubuntu80:8774/v2/0e962df9db3f4469b3d9bfbc5ffdaf7e/test_images/detail' -X GET -H "Accept: application/json" -H "User-Agent: python-novaclient" -H "X-Auth-Project-Id: admin" -H "X-Auth-Token: a479cdb5f5ce47aebccd15f1790beb2c"

执行得到结果如下:

OpenStack中的API结构地图_第17张图片

这里,打印出了我们想要的结果。

特别声明:本文原创,欢迎大家转载,但还请注明出处,谢谢!(http://my.oschina.net/crooner/blog/609419)


你可能感兴趣的:(api,openstack,nova,paste)