目录

Keystone WSGI 实现

Keystone 项目把每个功能都分到单独的目录下,EXAMPLE:

  • token 相关的功能 ===> keystone/token/
  • assignment 相关的功能 ===> keystone/assignment/
  • auth 相关的功能 ===> keystone/auth/
  • catalog 相关的功能 ===> keystone/catalog/
  • credential 相关的功能 ===> keystone/credential/
  • identity 相关的功能 ===> keystone/identity/
  • policy 相关的功能 ===> keystone/policy/
  • resource 相关的功能 ===> keystone/resource/

这些功能目录下都一般会有三个文件:routers.py/ controllers.py/ core.py

controllers.py

controllers.py 中的 action 操作函数调用了 core.py 中的底层接口实现来 RESTful API 对应的操作功能。

EXAMPLE:这个例子的代码非官方源码,用于理解。

# controller.py
class AccountController(wsgi.Controller):
def __init__(self, ext_mgr):
self.ext_mgr = ext_mgr
self.account_api = account_api.API()
super(AccountController, self).__init__() @wsgi.serializers()
def index(self, req): #Action:index ==> HTTP:Get(all)
context = req.environ['duckbill.context']
params = req.GET
qs = {}
qs['page_count'] = params.get('page_count', DEFAULT_PAGE_COUNT)
qs['page_num'] = params.get('page_num', 0)
qs['account_name'] = params.get('account_name', None)
qs['pubcloud'] = params.get('pubcloud', None)
qs['user'] = params.get('user', None) accounts = self.account_api.list_account(context, qs) #account_api.list_account()是从core.py中实现的函数
return {'accounts': accounts} # core.py
class API(base.Base):
"""API for handling account resources.""" def __init__(self):
super(API, self).__init__() def list_account(self, context, filter=None):
"""Get account list. :param context: class:`RequestContext` instance :param filter: select data by filter
:type: ``dict`` :return: return a list of class:`AccountInfo` instance.
"""
return self.db.account_get_all(context, filter) #调用 db Module 的方法实现对数据库的操作, db Module 使用了 ORM # db.py
def account_get_all(context, filter=None):
"""Get account list. :param context: class:`RequestContext` instance :param filter: select data by filter
:type: ''dict'' :return: return a list of class:`AccountInfo` instance.
"""
return IMPL.account_get_all(context, filter=filter) #IMPL 主要在 oslo.db 通用库中实现

routers.py

routers.py 中实现了 URL 路由,把 URL 和 controllers.py 中的 action 对应起来。

EXAMPLE:

URl == http://hostname:35357/v3/auth/tokens 对 Keystone 而言,/v3 开头的请求会交给 keystone.service.v3_app_factory 这个函数生成的 application 来处理。

routes 的一般用法是创建一个 mapper 对象,然后调用该 Mapper 对象的 connect() 方法把 URL_Path(这里是 /auth/tokens )和 HTTP 内建方法映射到一个 controller 的某个 action 上。如果是这样的话,那么我们就需要先实现 controller 和其 action 操作函数。然后使用 mapper.connect() 将上述的几个关键的参数映射到一起。使得一个请求,在 Client 看起来是 URL ,在程序内部看起来就是一个 Action 操作函数。

keystone.service.v3_app_factory 这个函数说明了路由转发的原理,我们来看代码:

def v3_app_factory(global_conf, **local_conf):    #v3_app_factory()函数中先遍历了所有的模块,将每个模块的路由都添加到同一个mapper对象中
...
mapper = routes.Mapper() # 创建一个 mapper 对象
... router_modules = [auth, # Keystone 功能模块列表
assignment,
catalog,
credential,
identity,
policy,
resource]
... for module in router_modules:
routers_instance = module.routers.Routers()
_routers.append(routers_instance)
routers_instance.append_v3_routers(mapper, sub_routers)
#将每个 keystone 功能模块的路由都添加到同一个 mapper 对象中,这样的话每个模块的 routes 都拥有了 mapper 的能力。 # Add in the v3 version api
sub_routers.append(routers.VersionV3('public', _routers))
return wsgi.ComposingRouter(mapper, sub_routers)
#然后把 mapper 对象作为参数用于初始化 wsgi.ComposingRouter 对象 # ComposingRouter 对象(在其父类Router中实现)被调用时,会 Return 一个 WSGI application 。
# 即当调用 keystone.service.v3_app_factory 这个函数时会返回一个 application 对象,用于连接 WSGI Server 和 Application(application参数传递请求)。

这个 wsgi.ComposingRouter 对象一定是一个 WSGI application,我们看看代码就知道了:

class Router(object):
"""WSGI middleware that maps incoming requests to WSGI apps.""" def __init__(self, mapper):
self.map = mapper
self._router = routes.middleware.RoutesMiddleware(self._dispatch,
self.map)
#这个 application 中则使用了 routes 模块的中间件来实现了请求路由 (在routes.middleware.RoutesMiddleware中实现)。
#这里对 Path 进行路由的结果就是返回各个模块的 controllers.py 中定义的 controller (路由的结果就是将请求中的URL的资源和一个 controller 对应起来)。
#各个模块的 controller 都是一个WSGI application,这个你可以通过这些 controller 的类继承关系看出来 @webob.dec.wsgify()
def __call__(self, req):
return self._router ... class ComposingRouter(Router):
def __init__(self, mapper=None, routers=None):
...

routes 模块把 URL_Path 映射到了一个 controller,但是如何把对 URL_Path 的处理(HTTP方法)映射到 controller 的操作函数(Action)呢?

这个可以从 controller 的父类 keystone.common.wsgi.Application 的实现看出来。

这个 Application 类中使用了 environ[‘wsgiorg.routing_args’] 中的数据来确定调用 controller 的哪个方法,这些数据是由上面提到的routes.middleware.RoutesMiddleware 设置的。所以最近调用哪一个 Controller 的 Action 还是由 routes.middleware.RoutesMiddleware 来决定的。

class Application(BaseApplication):
@webob.dec.wsgify()
def __call__(self, req):
arg_dict = req.environ['wsgiorg.routing_args'][1]
action = arg_dict.pop('action')

参考文档

routes 库的项目官网

Python Paste 库项目官网

通过demo学习OpenStack开发–API服务

Openstack Restful API 开发框架 Paste + PasteDeploy + Routes + WebOb

Keystone controller.py & routers.py代码解析的更多相关文章

  1. GraphSAGE 代码解析(四) - models.py

    原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(一) - unsupervised_train.py GraphSAGE 代码解析(二) - layers.py ...

  2. GraphSAGE 代码解析(三) - aggregators.py

    原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(一) - unsupervised_train.py GraphSAGE 代码解析(二) - layers.py ...

  3. GraphSAGE 代码解析(二) - layers.py

    原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(一) - unsupervised_train.py GraphSAGE 代码解析(三) - aggregator ...

  4. GraphSAGE 代码解析(一) - unsupervised_train.py

    原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(二) - layers.py GraphSAGE 代码解析(三) - aggregators.py GraphSA ...

  5. 使用python对py文件程序代码复用度检查

    #!/user/bin/env python # @Time :2018/6/5 14:58 # @Author :PGIDYSQ #@File :PyCheck.py from os.path im ...

  6. 用 TensorFlow 实现 k-means 聚类代码解析

    k-means 是聚类中比较简单的一种.用这个例子说一下感受一下 TensorFlow 的强大功能和语法. 一. TensorFlow 的安装 按照官网上的步骤一步一步来即可,我使用的是 virtua ...

  7. OpenStack之虚机热迁移代码解析

    OpenStack之虚机热迁移代码解析 话说虚机迁移分为冷迁移以及热迁移,所谓热迁移用度娘的话说即是:热迁移(Live Migration,又叫动态迁移.实时迁移),即虚机保存/恢复(Save/Res ...

  8. pointnet.pytorch代码解析

    pointnet.pytorch代码解析 代码运行 Training cd utils python train_classification.py --dataset <dataset pat ...

  9. django基础 -- 3. urls.py view.py 参数 别名 重定向 常用方法 静态文件

    一.基本格式 from django.conf.urls import url from . import views #循环urlpatterns,找到对应的函数执行,匹配上一个路径就找到对应的函数 ...

随机推荐

  1. 基础(一):SCSI硬盘与IDE硬盘有什么区别

    硬盘接口是硬盘与主机系统间的连接部件,作用是在硬盘缓存和主机内存之间传输数据.不同的硬盘接口决定着硬盘与计算机之间的连接速度,在整个系统中,硬盘接口的优劣直接影响着程序运行快慢和系统性能好坏.从整体的 ...

  2. Sql生成 Insert 语句

    declare @TableName sysname select @TableName = 'T_OOSOrder' declare @result varchar(max) = 'INSERT I ...

  3. 转-C++之虚函数不能定义成内联函数的原因

    转自:https://blog.csdn.net/flydreamforever/article/details/61429140 在C++中,inline关键字和virtual关键字分别用来定义c+ ...

  4. appium无法定位连接的真机元素

    报错信息: com.android.ddmlib.SyncException:Remote object dosen't exist! 解决办法: 错误原因是因为没有dump下来界面的信息保存到uid ...

  5. Openstack组件部署 — Nova_Install and configure a compute node

    目录 目录 前文列表 Prerequisites 先决条件 Install and configure a compute node Install the packages Edit the etc ...

  6. TFS 中如何将项目加入已有的源代码管理器中?

    Visual Studio 的某解决方案已经加入 Team Foundation Server,现在再将已经存在的项目加入到解决方案中,可是签入时,并没有把新加入的项目签入,怎么办呢? 在团队资源管理 ...

  7. 通过Bochs分析Lilo启动Linux内核的过程

    1. Bochs调试 参考:http://www.cnblogs.com/long123king/p/3414884.html http://bochs.sourceforge.net/cgi-bin ...

  8. Naive RNN vs LSTM vs GRU、attention基础

    原文地址:https://www.jianshu.com/p/b8653f8b5b2b 一.Recurrent Neural Network 二.Naive RNN Naive RNN更新参数时易出现 ...

  9. 记一次批量修改SQLServer表数据

    前提: 1.数据有上百万条,分成10几张excel表,从数据库中导出,由业务部门修改: 2.数据没什么规律: 3.和数据库DB商量后决定先把从excel导进数据库中,再通过关联查询修改数据 将 Exc ...

  10. linux下读取移动硬盘

    前提是安装了ntfs-3g软件,系统才能识别到移动硬盘. 第一步.fdisk -l    该命令查看系统识别到的磁盘,如果移动硬盘系统能够识别,    在屏幕上会输出“/dev/sdb1”之类的字样. ...