深入探秘Neutron API
一、Neutron API概述
Neutron项目作为一个虚拟网络资源池,提供了如下三种使用方式:
- 通过Web界面,也就是通过Dashboard来使用网络上的功能。
- 通过命令行,也就是通过neutron等命令,或者通过最新的openstack命令(社区目前的发展目标是使用一个单一的openstack命令替代过去的每个项目一个命令的方式,以后会只存在一个openstack命令)去使用。
- 通过API,也就是通过Neutron项目提供的API来使用其服务的功能。上面提到的三种方式中,通过API这种方式是使用其他两种方式的基础。
这里,我们将重点阐述Neutron API服务。值得注意的是,Neutron中并没有像其他项目一样单独提供一个api服务,二是将api做成了Core API和Exten API等资源方式进行提供。即被封装进了neutron-server,并未被分离。
Neutron API,主要用于提供RestAPI访问,实现的核心是WSGI。Neutron将基于各种虚拟网络资源得到的API资源分为核心资源(Core API)和扩展资源(Exten API)两种。Core API只对应于ML2层的network/subnet/port三种抽象。其余的各层抽象都属于Extension API的范围,通过进行扩展,提供更多的网络服务。目前已有的扩展有L3( router)、L4(tcp/udp firewall)及L7(load balancer)。随着neutron项目的不断成熟,扩展API会演化为标准API。
在Neutron中, neutron-server(相当于REST API Server)负责将收到的REST API请求交由Plugin来进行相关处理。可以看出,这其实就是一个web服务器要完成的事情,将http请求转化为对资源的操作(通过plugin的方法调用),并返回响应。
二、如何探秘Neutron API
Neutron API实现的主要代码位于/neutron/api目录下:
[root@controllerapi(keystone_admin)]# tree
api_common.py #该API主要用于实现通用的类和方法
extensions.py #定义了实现extension的几个类
rpc
agentnotifiers #负责发送RPC消息分别给dhcp/l3/meter agent
dhcp_rpc_agent_api.py
__init__.py
l3_rpc_agent_api.py
metering_rpc_agent_api.py
handlers #定义了对dvr服务两端的rpc的api和callback类
dhcp_rpc.py
dvr_rpc.py
__init__.py
v2#用于实现neutron api V2版本的定义
attributes.py
base.py
__init__.py
resource_helper.py
resource.py
router.py
versions.py#当rest api请求是版本号时,调用该模块中的类Versions进行处理。
views
__init__.py
versions.py
这里,以neutron.api.v2包为例,其中的base.py中定义了Controller类,是实现URL到plugin的api进行mapping的核心。 其主要方法包括create、 delete、 index、 show、 update。顾名思义,create用于创建资源, delete用于删除资源, show是获取资源、 update是更新资源, index是返回请求资源的列表。代码如下:
47 class Controller(object):
48 LIST = 'list'
49 SHOW = 'show'
50 CREATE = 'create'
51 UPDATE = 'update'
52 DELETE = 'delete'
v2目录下包括了ML2层核心资源的实现代码。每个Neutron API资源都会被封装成一个WSGI Application。Neutron API服务进程neutron-server接收到用户的HTTP请求后会通过Router模块将其路由到相关资源的Controller(即wsgi app)中去执行相应的操作。 对于ML2核心资源而言,都使用了base.py文件中的类Controller去实现。只是在封装成WSGI Application的时候去调用这个文件中的createresource()函数根据不同的参数动态创建对应的Controller对象。
676 defcreate_resource(collection, resource, plugin, params, allow_bulk=False,
677 member_actions=None, parent=None, allow_pagination=False,
678 allow_sorting=False):
679 controller = Controller(plugin, collection, resource, params, allow_bulk,
680 member_actions=member_actions, parent=parent,
681 allow_pagination=allow_pagination,
682 allow_sorting=allow_sorting)
683
684 return wsgi_resource.Resource(controller, FAULT_MAP)
而对于其他的诸如L3-L7层的扩展资源,Neutron仍然使用的是传统的方式去实现。它们在neutron/extensions/目录下都分别有对应的实现文件与对应的Controller类,而位于neutron/api/目录下的extension.py文件只是一些实现基类和共用的代码。
什么是Paste Deployment
Paste Deployment用于发现和配置WSGI Application和Server,有了Paste Deployment,WSGI applications只需向其用户提供一个单独的入口loadapp函数,然后用户调用这个函数就可以使用已经开发好的WSGI application,同时,由于只提供了一个入口,WSGI的开发者也不再需要将App的具体实现暴露给用户,大大简化了整个开发过程。
这里涉及到了两个概念: server和application,server可能大家比较熟悉,即常用的apache,nignx等等,applications广义理解就是一个符合wsgi规范的一个可调用的object,规范指的是:一个接受两个参数的函数(environ,start_response)。
neutron-server作为Neutron中的唯一一个服务进程,承担着接受用户REST API请求并分发处理的任务。
根据neutron/setup.cfg中的显示,neutron-server的入口位于neutron.cmd.eventlet.server:mainwsgieventlet,Paste Deploy会在这个WSGI Server创建时参与进来,基于Paste配置文件/etc/neutron/api-paste.ini文件去加载WSGI Application。
Neutron的paste deployment配置文件分析
定义了WSGI应用和路由信息。利用Paste来实例化Neutron的APIRouter类,将资源(端口、网络、子网)映射到URL上,以及各个资源的控制器。在neutron-server启动的时候,一般会指定参数--config-file neutron.conf --config-file xxx.ini。
Neutron的paste deployment配置文件为api-paste.ini。前面提到,paste deployment就是完成从配置文件中加载WSGI App的功能,以Neutron-server(api)为例,分析下都定义了哪些WSGI App以及每个App的含义。
其中,api-paste.ini文件的注释如下:
[composite:neutron]
#格式为[type:name]
#composite使用urlmap,根据url不同实现跳转
use = egg:Paste#urlmap
/: neutronversions
/v2.0: neutronapi_v2_0</p>
[composite:neutronapi_v2_0]
#调用deploy.loadapp方法,使用config方式来load section名为“neutronapi_v2_0”的应用
use = call:neutron.auth:pipeline_factory
#对应到代码行7,是一个composite类型的section,直接调用neutron.auth模块中的pipeline_factory函数
noauth = request_idcatch_errors extensions neutronapiapp_v2_0
#作为local</em>conf参数传入
keystone = request_idcatch_errorsauthtokenkeystonecontext extensions neutronapiapp_v2_0
#作为local_conf参数传入
[filter:request_id]
#定义过滤器,类似python中的装饰器。返回一个封装后的 application,这里只是定义了filter,并没有将filter作用到application上。
#将filter作用到app的方法有两种:filter-app section和 pipe section
paste.filter_factory = oslo_middleware:RequestId.factory
[filter:catch_errors]
paste.filter_factory = oslo_middleware:CatchErrors.factory
[filter:keystonecontext]
#keystonecontext,实际上是一个过滤器,使用了neutron.auth模块下的类的NeutronKeystoneContext的factory函数
paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory
#filter_factory: 可调用对象,接受参数(global_config, **local_conf),返回filter对象
[filter:extensions]
paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
[app:neutronversions]
#核心的app,将app指向python代码。app_factory表明这个函数接收一系列参数
paste.app_factory = neutron.api.versions:Versions.factory
#app_factory:可调用对象,接受参数(global,**local_conf),返回app对象
[app:neutronapiapp_v2_0]
paste.app_factory = neutron.api.v2.router:APIRouter.factory
#api服务的实现是service.NeutronApiService,这是一个符合WSGI规范的app #通过paste进行配置,paste文件位置可以在配置文件中指定,默认是/etc/neutron/api-paste.ini,在代码中是etc/api-paste.ini。 #可以知道api-paste.ini的v2版api的实现是在neutron.api.v2.router:APIRouter类中。 #Neutron-Server就已经基本上启动了,无外乎就是加载配置,router各种resource,然后就等待请求了。 #其中router哪些resource完全是由配置文件来决定的。 #由于,在启动的过程中会初始化db,这也就是为何在安装neutron的时候无需像nova、glance等要执行db sync的原因了。
neutron.api.v2.router模块中的APIRouter类会完成所有Core API和Extension API的加载与路由规则的创建。从收到用户的HTTP请求到Controller中的操作具体执行时,会根据请求的资源和Action,拼接出应该调用的接口交由Plugin处理,比如所请求操作的资源是network,Action是“Create”,则应该调用的Plugin接口是“createnetwork”。代码如下所示:
69 class APIRouter(wsgi.Router):
70
71 @classmethod
72 deffactory(cls, global_config, **local_config):
73 return cls(**local_config)
74
75 def _init_(self, **local_config):
76 mapper = routes_mapper.Mapper()
77 plugin = manager.NeutronManager.get_plugin()
78 ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
79 ext_mgr.extend<em>resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)
80
81 col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
82 member_actions=MEMBER_ACTIONS)
三.如何给Neutron API增加资源
相信,大家看了上面的长篇叙述之后,多半已经不厌其烦。好了,这里,我们将Demo一个列子,即如何为Neutron API增加WSGI APP资源。 我的环境:由DevStack在CentOS上安装的OpenStack
1)在Neutron API的Paste deploy配置文件中,增加所需的资源配置。编辑api-paste.ini文件。
# vim /etc/neutron/api-paste.ini 在[composite:neutron]部分,增加如下一行: /pastetest: pastetest
再在该文件最后,增加如下两行:
[app:paste_test]
paste.app_factory = paste_test.test:PasteTest.factory
2)切换到Python的源码包目录下。
# cd/usr/lib/python2.7/site-packages/
# mkdirpaste_test&& cd paste_test
# touch _init_.py</p>
再新建一个test.py文件,并输入如下内容: # cattest.py
#!/usr/bin/env python
#coding=utf-8
importwebob.dec
from neutron import wsgi
classPasteTest(object):
@classmethod
def factory(cls, global_config, **local_config):
returncls()
@webob.dec.wsgify(RequestClass=wsgi.Request)
def _call_(self,req):
response = webob.Response()
response.body = "Hello Neutron API!"
return response
这里的内容主要是,无论是什么REST API请求,始终将“Hello Neutron API!”这段内容作为回复。
3)最后,我们需要重启Neutron服务
# /usr/bin/neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini & echo $! >/opt/stack/status/stack/q-svc.pid; fg || echo "q-svc failed to start" | tee "/opt/stack/status/stack/q-svc.failure"
4)验证。使用我们刚才添加的WSGI APP资源
#curl 127.0.0.1:9696/paste_test
输出如下所示:
当然,为了直观,我们干脆直接在浏览器中查看吧。如下图所示。
小结
通过此篇介绍,相信,能够为我们了解、学习Neutron API的运行机制以及如何为Neutron API增加WSGI APP资源提供思路和方法。
当然,限于多方面原因,这里并未讲解WSGI、webob、router等知识,大家可以参阅其他资料学习。如何扩展Neutron ML2资源,期待我们能在下一篇见面。
- d3.js在博客园中的展示例子
- nuget服务器搭建,以及如何发布一个Nuget包
- knockoutjs 上自己实现的flux
- 简单实现 C# 与 Javascript的兼容
- Oozie分布式工作流——从理论和实践分析使用节点间的参数传递
- 如何写好CSS系列之表单(form)
- 2017年Dataversity 最受欢迎文章 Top 20 榜单
- “自如”获40亿融资,组合域名用的妙
- D3、openlayers的一次尝试
- 对快速排序算法的分析
- 如何写好css系列之button
- Oozie分布式工作流——Action节点
- mockjs,json-server一起搭建前端通用的数据模拟框架
- Oozie分布式工作流——流控制
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- centos6超20TB磁盘的分区格式化的示例代码
- Linux 系统双网卡绑定配置实现
- Linux系统设置开机自动运行脚本的方法实例
- Linux中fuser命令用法详解
- 在Ubuntu中实现人脸识别登录的完整步骤
- Linux下如何寻找相同文件的方法
- CentOS 7中Nginx日志定时拆分实现过程详解
- 浅谈linux模拟多线程崩溃和多进程崩溃
- Linux下MongoDB的安装和配置教程
- Linux配置实现免密钥登录过程解析
- 可以提高效率的十个Linux命令别名汇总
- 基于linux命令提取文件夹内特定文件路径
- Ubuntu20.04修改ip地址的方法示例
- Linux 逻辑卷管理(LVM)使用方法总结
- Linux 下载安装VSCode 使用编程输出当前时间的方法