目录

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. bzoj1046题解

    [解题思路] 先倒着求一遍LIS,然后对于每个询问L从左到右找到第一个大于等于L的上升序列即可.复杂度O(N(log2N+M)). [参考代码] #pragma GCC optimize(2) #in ...

  2. 线性基思想+贪心——cf1249C

    /*1+3+9+...+3^n<3^(n+1),按这个思路贪心一下就好*/#include<bits/stdc++.h> using namespace std; #define l ...

  3. Luogu P1738 洛谷的文件夹

    P1738 Luogu 发一个链表题解! 仅有24ms,排名第一哦~ 圆圈代表点,每个店有两个指针,一个指向自己兄弟(同级文件夹),另一个指向自己孩子(子文件夹),还有一个保存当前名字. 有点像二叉树 ...

  4. nginx填坑补充(nginx根据上下文跳转ip或者域名)

    今天有一个需求,要根据上下文调到不同的ip或域名地址,使用上下文做域名跳转的时候,proxy_pass域名后面一定要带‘/’否则会把nginx的上下文自动带入,这样就行. location ^~ /d ...

  5. 12、testng.xml指定运行测试包、测试类、测试方法

    目录如下: TestFixture.java 代码如下: package com.testng.cn; import org.testng.annotations.*; public class Te ...

  6. Java控制台

    Console类的目的是使Java程序和控制台之间的交互更容易.Console类是java.io包中的一个实用程序类,用于访问系统控制台.控制台不能保证在所有机器上的Java程序中可访问. 例如,如果 ...

  7. MFC VC 双缓冲绘图基本原理与实现,详细解释

    转自:http://blog.csdn.net/foreverhuylee/article/details/21548107 当然你可以直接搜索到能用的代码,并且基本能满足要求.不过这样总不是学习的态 ...

  8. xshell6 远程连接时提示 WARNING! The remote SSH server rejected X11 forwarding request.

    1.输入命令 vi /etc/ssh/sshd_config ,修改配置文件 2.将UserLogin no 的注释解除   3.执行yum install -y xorg-x11-font xorg ...

  9. hdu6393 /// 树链剖分

    题目大意: 给定n q 在n个点n条边的图中 进行q次操作 0 k x 为修改第k条边的值为x 1 x y 为查询x到y的最短路 https://blog.csdn.net/nka_kun/artic ...

  10. MySQL数据库 -- Navicat、pycharm连接数据库

    内容目录 1.Navicat使用 2.pycharm使用数据库 一.Navicat使用 #1. 测试+链接数据库 #2. 新建库 #3. 新建表,新增字段+类型+约束 #4. 设计表:外键 #5. 新 ...