cinder-api启动过程学习

本文详细解析了OpenStack Cinder-API的启动过程,涉及api-paste.ini配置、过滤器(Filter)和应用(App)的设置,特别是ExtensionManager如何加载扩展资源以及创建mapper和routes的过程。通过理解这些,可以深入掌握Cinder-API如何处理HTTP请求并进行资源调度。
摘要由CSDN通过智能技术生成

cinder-api启动过程学习

Openstack中的xxx-api都是WSGI service,负责接收、分析、处理HTTP request,并返回response。其中最重要的两个Python package是paste.delopy和routes。前者负责查找、配置、启动WSGI app,后者负责把RESTful的HTTP requests dispatch到相应的处理方法上。

paste.deploy官网:http://pythonpaste.org/deploy/
routes官网:http://routes.readthedocs.org/en/latest/

下面是cinder-api(juno)启动过程的学习,难免有不对的地方,请联系我哦:-)

api-paste.ini

cinder/etc/cinder/api-paste.ini是WSGI app的配置文件。

安装cinder之后会copy到/etc/cinder/

[root@all ~]# ll /etc/cinder/
total 92
-rw-------. 1 cinder cinder  2136 Mar  2 10:46 api-paste.ini
-rw-------. 1 cinder cinder 79250 Mar  2 10:46 cinder.conf
-rw-r-----. 1 root   cinder  3200 Dec  5 13:00 policy.json
-rw-r-----. 1 root   cinder   942 Dec  5 13:00 rootwrap.conf
drwxr-xr-x. 2 cinder root       6 Jan 18 07:35 volumes
入口
[composite:osapi_volume]
use = call:cinder.api:root_app_factory
/: apiversions
/v1: openstack_volume_api_v1
/v2: openstack_volume_api_v2
  • composite表示把HTTP request dispatch到一个或多个app上
  • use表示用什么方法来dispatch
  • 其他的KEY=VALUE都是app

找到cinder.api:root_app_factory

#cinder/api/__init__.py
def root_app_factory(loader, global_conf, **local_conf):
    if CONF.enable_v1_api:
        LOG.warn(_('The v1 api is deprecated and will be removed after the '
                   'Juno release. You should set enable_v1_api=false and '
                   'enable_v2_api=true in your cinder.conf file.'))
    else:
        del local_conf['/v1']
    if not CONF.enable_v2_api:
        del local_conf['/v2']
    return paste.urlmap.urlmap_factory(loader, global_conf, **local_conf)

从注释看主要用openstack_volume_api_v2

openstack_volume_api_v2
[composite:openstack_volume_api_v2]
use = call:cinder.api.middleware.auth:pipeline_factory
noauth = request_id faultwrap sizelimit osprofiler noauth apiv2
keystone = request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2
keystone_nolimit = request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2

也是composite类型。定义3个app:noauthkeystone, keystone_nolimit

找到cinder.api.middleware.auth:pipeline_factory

# cinder/api/middleware/auth.py
def pipeline_factory(loader, global_conf, **local_conf):
    """A paste pipeline replica that keys off of auth_strategy."""
    #debug on all_in_one 2015/3/14
    #(Pdb) global_conf
    #{'__file__': '/etc/cinder/api-paste.ini', 'here': '/etc/cinder'}
    #(Pdb) local_conf
    #{'keystone': 'request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2', 'noauth': 'request_id faultwrap sizelimit osprofiler noauth apiv2', 'keystone_nolimit': 'request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2'}
    #(Pdb) CONF.auth_strategy
    #'keystone'
    #(Pdb) CONF.api_rate_limit
    #True
    pipeline = local_conf[CONF.auth_strategy]
    if not CONF.api_rate_limit:
        limit_name = CONF.auth_strategy + '_nolimit'
        pipeline = local_conf.get(limit_name, pipeline)
    pipeline = pipeline.split()
    #依次load各个filter
    filters = [loader.get_filter(n) for n in pipeline[:-1]]
    #(Pdb) pipeline
    #['request_id', 'faultwrap', 'sizelimit', 'osprofiler', 'authtoken', 'keystonecontext', 'apiv2']
    #(Pdb) pipeline[:-1]
    #['request_id', 'faultwrap', 'sizelimit', 'osprofiler', 'authtoken', 'keystonecontext']
    #load app
    app = loader.get_app(pipeline[-1])
    filters.reverse()
    #(Pdb) filters
    #[<function _factory at 0x3a2f9b0>, <function auth_filter at 0x3a2f938>, <function filter_ at 0x3548050>, <function _factory at 0x3541cf8>, <function _factory at 0x3541aa0>, <class 'cinder.openstack.common.middleware.request_id.RequestIdMiddleware'>]
    #依次用filter来包装app
    for filter in filters:
        app = filter(app)
    return app
  1. 配置文件中的KEY=VALUE都放在了local_conf这个dict中
  2. 首先根据cinder.conf中的auth_strategy参数来决定走哪个app
  3. keystone = aaa bbb ccc,前面的都是filter,最后一个是app。一个HTTP request过来之后,先由filters过滤一遍,最后由app处理。
Filter

以下为例,看filter是怎么包装app的:
keystone = request_id faultwrap sizelimit osprofiler authtoken keystonecontext apiv2

1.request_id

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

找到RequestIdMiddleware.factory:

#cinder/openstack/common/middleware/request_id.py
from cinder.openstack.common.middleware import base

ENV_REQUEST_ID = 'openstack.request_id'
HTTP_RESP_HEADER_REQUEST_ID = 'x-openstack-request-id'

class RequestIdMiddleware(base.Middleware):

    @webob.dec.wsgify
    def __call__(self, req):
        req_id = context.generate_request_id()
        req.environ[ENV_REQUEST_ID] = req_id
        response = req.get_response(self.application)
        if HTTP_RESP_HEADER_REQUEST_ID not in response.headers:
            response.headers.add(HTTP_RESP_HEADER_REQUEST_ID, req_id)
        return response

其父类为:

# cinder/openstack/common/middleware/base.py
class Middleware(object):
    """Base WSGI middleware wrapper.

    These classes require an application to be initialized that will be called
    next.  By default the middleware will simply call its wrapped app, or you
    can override __call__ to customize its behavior.
    """

    @classmethod
    def factory(cls, global_conf, **local_conf):
        """Factory method for paste.deploy."""
        return cls

    def __init__(self, application):
        self.application = application

factory方法就是返回cls,也就调用了__init__,也就是return了application。

顺便看一下RequestIdMiddleware.__call__。当这个filer被调用的时候,会调用的这个__call__,它在response的header中加了一个x-openstack-request-id

2.faultwrap

[filter:faultwrap]
paste.filter_factory = cinder.api.middleware.fault:FaultWrapper.factory
# fault.py
from cinder import wsgi as base_wsgi

class FaultWrapper(base_wsgi.Middleware):
    """Calls down the middleware stack, making exceptions into faults."""

其父类:

# cinder/wsgi.py
class Middleware(Application):
    """Base WSGI middleware.
    """

    @classmethod
    def factory(cls, global_config, **local_config):
        """Used for paste app factories in paste.deploy config files.

        Any local configuration (that is, values under the [filter:APPNAME]
        section of the paste config) will be passed into the `__init__` method
        as kwargs.

        A hypothetical configuration would look like:

            [filter
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值