Liberty nova-api HTTP请求执行流程

本博客欢迎转载,但请注明出处 http://blog.csdn.net/ringoshen/article/details/51387038

由于能力与时间有限,文章内容难免错漏,望大家多加指正,相互进步!

0. 前言

这次看了一下nova list命令的执行过程,整个过程可以分为几步:HTTP请求、URLMap分发、过滤、APIRouter到具体执行函数,接下来使用Postman组个包并发送http请求作为开始对各个模块进行跟踪和注解。

1. HTTP请求

OpenStack组件都是通过RESTful API向外提供服务,也就是说可以通过http的方式操作OpenStack。而操作的大致步骤分为两步:身份认证、发送任务,我们可以看一下http命令的实际操作情况。
首先是身份认证,这一步由keystone完成,返回token。
这里写图片描述

之后我们可以拿这个获取到的token去进行具体操作。
这里写图片描述

2. URLMap分发

还是先看一下代码,之前在Liberty nova-api启动流程分析的最后我们看到osapi_compute app负责监听8774端口,其实这个服务就是一个URLMap的callable对象,现在接收到8774端口的http请求时,调用URLMap的call()。

# nova/api/openstack/urlmap.py

class URLMap(paste.urlmap.URLMap):
    def __call__(self, environ, start_response):
        # host = '172.29.152.111:8774'
        host = environ.get('HTTP_HOST', environ.get('SERVER_NAME')).lower()
        ... ...  ... ...
        ... ...  ... ...
        # path_info = '/v2.1/35a94cc2b7bd4f088019dbc61f6dce37'
        # mime_type = None, app_url = '/v2.1'
        # app = <function wrap at 0x7ff89c03e410>
        mime_type, app, app_url = self._path_strategy(host, port, path_info)
        if (app_url and app_url + '/' == path_info) or path_info == '/':
            supported_content_types.append('application/atom+xml')
        ... ...  ... ...
        ... ...  ... ...
        if app:
            # environ['nova.best_content_type'] = 'application/json'
            environ['nova.best_content_type'] = mime_type
            return app(environ, start_response)
        ... ...  ... ...
        ... ...  ... ...
# nova/api/openstack/urlmap.py

class URLMap(paste.urlmap.URLMap):
    def _path_strategy(self, host, port, path_info):
        ... ...  ... ...
        ... ...  ... ...
        # parts = ['', 'v2.1', '35a94cc2b7bd4f088019dbc61f6dce37']
        parts = path_info.split('/')
        if len(parts) > 1:
            # possible_app = <oslo_middleware.cors.CORS object at 0x7ff89da5ff50>
            # possible_app_url = '/v2.1'
            # 这边开始进行版本匹配,获取相应的app
            possible_app, possible_app_url = self._match(host, port, path_info)

            if possible_app and possible_app_url:
                # app_url = '/v2.1'
                app_url = possible_app_url
                # app = <function wrap at 0x7ff89c03e410>
                app = self._munge_path(possible_app, path_info, app_url)
        # mime_type = None
        # app = <function wrap at 0x7ff89c03e410>
        # app_url = '/v2.1'
        return mime_type, app, app_url

之后的_match()方法真正实现根据版本调用app。

# nova/api/openstack/urlmap.py

class URLMap(paste.urlmap.URLMap):
    # 下面涉及到初始化的时候设置的applications参数,这边列出初始化的结果
    # self.applications = 
    #     [((None, '/v2.1'), <oslo_middleware.cors.CORS object at 0x7ff89da5ff50>), 
    #     ((None, '/v2'), <oslo_middleware.cors.CORS object at 0x7ff89e15a310>), 
    #     ((None, ''), <nova.api.openstack.FaultWrapper object at 0x7ff89d9e5950>)]

    def _match(self, host, port, path_info):
        """Find longest match for a given URL path."""
        # eg. v21版本对应的是openstack_compute_api_v21 app,根据pipeline的定义,
        #     最后一个filter是cors,所以可以看见app的类型如下:
        #     domain = None
        #     app_url = '/v2.1'
        #     app = <oslo_middleware.cors.CORS object at 0x7ff89da5ff50>
        for (domain, app_url), app in self.applications:
            if domain and domain != host and domain != host + ':' + port:
                continue
            # 这里根据之前初始化设置的urlmap进行匹配
            if (path_info == app_url
                    or path_info.startswith(app_url + '/')):
                return app, app_url
        return None, None

3. 过滤

之前获取的app是经过filter包装的,接下来按顺序看一下各个filter。

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

3.1 cors

CORS(Cross-Origin Resource Sharing,跨域资源共享),比如在编写javascript应用时如果需要直接使用openstack api,有可能会遇到同源策略的问题,那这边就需要扩展一下跨域资源共享,从代码的角度而言就是在api返回的response的header中加入Access-Control-Request-XXX等信息,这边简单列一下响应代码。

[filter:cors]
paste.filter_factory = oslo_middleware.cors:filter_factory
oslo_config_project = nova
# oslo_middleware/base.py

class ConfigurableMiddleware(object):
    @webob.dec.wsgify
    def __call__(self, req):
        response = self.process_request(req)
        # response = None
        if response:
            return response
        # 获取app响应(调用下一个filter)
        response = req.get_response(self.application)
        (args, varargs, varkw, defaults) = getargspec(self.process_response)
        # 对返回的response进行处理
        if 'request' in args:
            
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值