`

Glance源码架构探秘(三)

阅读更多

      上一篇分析了OpenStack中如何用eventlet库创建一个“绿化”的协程式web server,以及WSGI相关概念,本篇将具体讲解WSGI程序内部的框架。

      Glance及其他OpenStack的组件和大多数的web service一样,也是实现了MVC的框架,这个框架称之为RackSpace框架。包括消息路由,控制器Controller、action等等。

      这个框架并非完全自己实现,而是借用了许多开源的组件,比如消息路由就用到了Routes这个组件。Routes是借鉴了ruby on rails的某些思想后在Python上的一个实现,用于路由URL消息至对应的控制器和动作action,也可以用来生成URLs。

# Setup a mapper 
from routes import Mapper 
map = Mapper() 
map.connect(None, "/error/{action}/{id}, controller="error") 
map.connect("home", "/", controller="main", action="index") 
# Match a URL, returns a dict or None 
if no match 
    result = map.match('/error/myapp/4') 
# result == {'controller': 'main', 'action': 'myapp', 'id': '4'}

 导入routes,创建一个Mapper实例。之后,我们就可以用Mapper.connect()绑定路由。最后用Mapper.match()方法可以将给定的URL转换为路由信息,包括controller,action或其他用户自定义的路由类型。

      正式讲解Glance的代码之前,先介绍其WSGI中用到的另外一个开源组件webob。使用webob可以大幅简化编写框架的复杂度和代码量,webob用来包装WSGI应用程序的请求以及响应的类库。

from webob import Request 
environ = {'wsgi.url_scheme': 'http', ...} 
req = Request(environ)
req = Request.blank('/article id=1')
from pprint import pprint
pprint(req.environ) {
                     ' HTTP_HOST': 'localhost:80', 
                     'PATH_INFO': '/article', 
                     'QUERY_STRING': 'id=1', 
                     'REQUEST_METHOD': 'GET', 
                     'SCRIPT_NAME': '', 
                     'SERVER_NAME': 'localhost', 
                     'SERVER_PORT': '80', 
                     ' SERVER_PROTOCOL': 'HTTP/1.0', 
                     'wsgi.errors': <open file '<stderr$amp;>apos;$, mode 'w' at ...>, 
                     'wsgi.input': <...IO... object at ...>, 
                     'wsgi.multiprocess': False, 
                     'wsgi.multithread': False, 
                     'wsgi.run_once': False, 
                     'wsgi.url_scheme': 'http', 
                     'wsgi.version': (1, 0)}       

 上面的示例程序就简单说明了如何用webob的Request生成一个request请求和解析一个request请求的环境信息。然而,webob的功能不止这些,还有一个功能是将一个普通的函数function包装为一个WSGI函数,并符合WSGI函数的规范(实现规范的接口,evn,start_response)。

@webob.dec.wsgify
def myfunc(req): 
   return webob.Response('hey there')

 如上示例,就将myfunc包装为一个可被webserver调用的wsgi函数。如果我们不用这个包装,就要非常繁琐地写为:

def myfunc(req, start_response): 
    start_response('200 OK', header)
    return ['hey there']

 另外,用webob.exc通过生成Python异常的方式,生成HTTP的一些错误响应,如404,500等。

       下面先看route.py这个文件。上一篇文章提到,启动http server中填入的WSGI function是从glance-api-paste.ini中读取的,这个app正是glance.api.v2.router.API.factory。

class API(wsgi.Router): 
    """WSGI router for Glance v2 API requests.""" 
    def __init__(self, mapper): 
        custom_image_properties = images.load_custom_properties() 
        schemas_resource = schemas.create_resource(custom_image_properties) 
        mapper.connect('/schemas/image', controller=schemas_resource, action='image', conditions={'method': ['GET']})
        mapper.connect('/schemas/images', controller=schemas_resource, action='images', conditions={'method': ['GET']}) 
        images_resource = images.create_resource(custom_image_properties) 
        mapper.connect('/images', controller=images_resource, action='index', conditions={'method': ['GET']})
        mapper.connect('/images', controller=images_resource, action='create', conditions={'method': ['POST']}) 
        mapper.connect('/images/{image_id}', controller=images_resource, action='update', conditions={'method': ['PATCH']}) 
        mapper.connect('/images/{image_id}', controller=images_resource, action='show', conditions={'method': ['GET']}) 
        mapper.connect('/images/{image_id}', controller=images_resource, action='delete', conditions={'method': ['DELETE']}) 
        super(API, self).__init__(mapper)

 之前介绍过了routes的mapper类,这里的路由分配设置就一目了然了。因为使用的是RESTful接口,路由分配的时候还可以指定method。API这个类的基类是wsgi.Router,刚刚WSGI也是调用的其基类的工厂方法router.factory。这样我们继续介绍wsgi.py的后半部分。

class Router(object): 
    """ WSGI middleware that maps incoming requests to WSGI apps. """ 
    def __init__(self, mapper): 
        """ Create a router for the given routes.Mapper. Each route in `mapper` must specify a 'controller', which is a WSGI app to call. 
        You'll probably want to specify an 'action' as well and have your controller be a wsgi.Controller, who will route the request to the action method. Examples: 
        mapper = routes.Mapper( sc = ServerController() # Explicit mapping of one route to a controller+action mapper.connect(None, "/svrlist", controller=sc, action="list") 
        # Actions are all implicitly defined mapper.resource("server", "servers", controller=sc) 
        # Pointing to an arbitrary WSGI app. You can specify the 
        # {path_info:.*} parameter so the target app can be handed just that 
        # section of the URL. mapper.connect(None, "/v1.0/{path_info:.*}", controller=BlogApp()) """ 
        self.map = mapper 
        self._router = routes.middleware.RoutesMiddleware(self._dispatch, self.map) 
        @classmethod 
        def factory(cls, global_conf, **local_conf): 
            return cls(routes.Mapper()) 
        @webob.dec.wsgify 
        def __call__(self, req): 
            """ Route the incoming request to a controller based on self.map. If no match, return a 404. """
             return self._router 
         @staticmethod @webob.dec.wsgify 
         def _dispatch(req): 
             """ Called by self._router after matching the incoming request to a route and putting the information into req.environ. 
             Either returns 404 or the routed WSGI app's response. """ 
             match = req.environ['wsgiorg.routing_args'][1] 
             if not match: 
                 return webob.exc.HTTPNotFound() 
             app = match['controller'] 
             return app       

 这个基类的工厂方法被包装为类方法,实际就会创建刚才的API子类。此类的可调用对象方法__call__被包装成了wsgi,所以这个类的对象可以作为WSGI函数进行调用。routes.middleware是routes组件中另外一个重要的模块,他可以从上层wsgi程序中接收request请求的URL,并自动调用map.match()方法,将URL进行消息路由,并返回路由的结果。路由结果将会被存入request请求的环境变量['wsgiorg.routing_args']中。最后会调用其第一个参数给出的函数接口,继续下一级的WSGI调用,代码中就是self._dispath。

      这层的dispatch分发会从路由结果中找到是哪个controller,然后从router.py中查找并创建controller对应的resource,分析其创建过程,实质上最后还是会在wsgi.py中创建一个resource基类,所以我们继续看wsgi.py的最后一部分。

class Resource(object): 
    """ WSGI app that handles (de)serialization and controller dispatch. Reads routing information supplied by RoutesMiddleware and calls the requested action method 
    upon its deserializer, controller, and serializer. Those three objects may implement any of the basic controller action methods 
    (create, update, show, index, delete) along with any that may be specified in the api router. A 'default' method may also be implemented to be used in place 
    of any non-implemented actions. Deserializer methods must accept a request argument and return a dictionary. Controller methods must accept a request argument. 
    Additionally, they must also accept keyword arguments that represent the keys returned by the Deserializer. They may raise a webob.exc exception or return a dict, 
    which will be serialized by requested content type. """ 
    def __init__(self, controller, deserializer=None, serializer=None): 
        """ :param controller: object that implement methods created by routes lib :param deserializer: object that supports webob request deserializatio through
         controller-like actions :param serializer: object that supports webob response serialization through controller-like actions """ 
        self.controller = controller 
        self.serializer = serializer or JSONResponseSerializer() 
        self.deserializer = deserializer or JSONRequestDeserializer() 
        @webob.dec.wsgify(RequestClass=Request) 
        def __call__(self, request): 
            """WSGI method that controls (de)serialization and method dispatch.""" 
            action_args = self.get_action_args(request.environ) 
            action = action_args.pop('action', None) 
            deserialized_request = self.dispatch(self.deserializer, action, request) 
            action_args.update(deserialized_request) 
            action_result = self.dispatch(self.controller, action, request, **action_args) 
            try: 
                response = webob.Response(request=request) 
                self.dispatch(self.serializer, action, response, action_result) 
                return response 
            # return unserializable result (typically a webob exc) 
            except Exception: 
                return action_result 
            def dispatch(self, obj, action, *args, **kwargs): 
                """Find action-specific method on self and call it.""" 
                try: 
                    method = getattr(obj, action) 
                except AttributeError: 
                    method = getattr(obj, 'default') 
                    return method(*args, **kwargs) 
                def get_action_args(self, request_environment): 
                    """Parse dictionary created by routes library."""
                     try: 
                         args = request_environment['wsgiorg.routing_args'][1].copy() 
                     except Exception: 
                         return {} 
                     try: 
                         del args['controller'] 
                     except KeyError: 
                         pass 
                     try: 
                         del args['format'] 
                     except KeyError 
                     pass 
                 return args

 Resoutce这个类可以对请求解串行化,或串行化响应信息,并可以分发controller控制器action的方法。这个类的初始化方法会给对象添加三个属性,controller、serializer、deserializer,分别为控制器,串行化,逆串行化。对象函数__call__也被装饰为WSGI函数,接受上一级WSGI函数的请求,并将上一级Routes后的路由信息(controller=?action=?)通过dispatch方法指定的action分发到controller控制器类所对应的方法,在源码中用到了getattr,动态的获得对象的绑定方法。

      通过上述一系列步骤,就将glance命令请求消息经过路由、分发等步骤送到了控制器类所对应的action方法中,让glance得以进一步地执行客户发来的请求命令。

前面通过三章的篇幅,为大家讲解了glance/common/wsgi.py这个文件,主要实现了一个web框架的大部分功能。因为OpenStack的组件都是基于同一套rackspace框架的,这对于我们今后学习Nova,Cinder等其他OpenStack都是颇有益处的。所以今后如有Nova等组件的源码探秘,此部分也不再会单独分析,将把经历多投入到其他方面。

分享到:
评论

相关推荐

    paraview-glance-源码.rar

    《Paraview-Glance源码解析》 Paraview-Glance是ParaView项目的一个分支,专注于提供轻量级的、基于Web的可视化界面,让用户能够远程访问和交互式地查看大型科学数据。源码分析是理解软件工作原理、进行定制化开发...

    glance 1.1

    下面将详细讨论Glance 1.1版本中的核心功能、设计原则以及它在OpenStack架构中的角色。 1. **核心功能**: - **镜像注册**:Glance 1.1允许用户上传和注册各种类型的虚拟机镜像,如VMDK、QCOW2或RAW格式,以便后续...

    Glance安装配置简介.docx

    Glance是OpenStack云平台中的一个关键组件,主要负责镜像服务,为虚拟机实例提供镜像的存储、检索和管理功能。以下是对Glance安装配置的详细说明: 1. **创建Glance数据库及授权** 在安装Glance之前,需要在MySQL...

    openstack其中四大组件源码

    通过深入学习这四大组件的源码,开发者不仅可以了解OpenStack的基本架构和工作原理,还能对云存储、计算和身份管理有更深入的理解。此外,源码分析对于定制化开发、性能优化以及故障排查都具有重要意义。对于希望...

    OpenStack之镜像服务(Glance)安装

    接着,为这个服务创建三个不同类型的端点(admin、internal、public),这些端点定义了用户和服务之间通信的URL。 7. **配置后端存储系统**:在Glance的配置文件中,需要指定镜像的存储位置,如`[glance_store]`...

    云计算Glance 管理

    云计算Glance管理 云计算Glance管理是云计算领域中的一种重要的镜像管理服务。Glance是OpenStack云计算平台中的一部分,负责管理和维护虚拟机镜像。Glance提供了镜像的注册、存储、检索和删除等功能,确保了云计算...

    Glance监控命令在HP UX上的使用

    ### Glance监控命令在HP-UX上的使用 #### Glance工具概述 Glance是一个功能强大的实时监控工具,专为HP-UX系统设计。它能够提供丰富的系统信息,并以图形模式和文本模式显示,帮助用户更好地理解和管理系统的资源...

    20-理解 Glance1

    Glance的架构包含两个主要的服务进程:glance-api和glance-registry。glance-api对外提供REST API接口,处理用户的请求,如果是元数据操作,它会将请求转发给glance-registry;如果是镜像文件的存取,它会根据配置的...

    Python-Glance是一个用于替代tophtop的跨平台监控工具

    **Python-Glance:跨平台监控工具的创新选择** 在现代IT环境中,系统监控是确保服务稳定性和性能的关键环节。传统的命令行工具如`top`和`htop`虽然功能强大,但它们的交互方式受限于终端界面,无法提供丰富的可视化...

    OpenStack-glance服务-glance-api.conf配置文件

    OpenStack-glance服务-glance-api.conf配置文件,在配置OpenStack的glance服务中,配置文件glance-api.conf需要进行部分修改,进而来适应各种服务,该文件为修改完成的glance-api.conf文件内容。

    004.Glance详解1

    理解Glance的系统架构及其工作原理对于有效地构建和维护OpenStack环境至关重要。 一、系统架构 Glance的系统架构主要包括以下几个核心部分: 1. 存储后端(Backend Storage):Glance支持多种存储后端,如Swift、...

    glance镜像发布

    openstack项目中关于glance的应用与注意事项

    5.2 glance的安装和配置1

    1. 源码加载`admin`用户的环境变量: ``` source /root/admin-openrc ``` 2. 创建Glance用户,指定其属于`default`域,与`service`项目关联,赋予`admin`角色: ``` openstack user create --domain default -...

    实验三 glance镜像服务安装与配置 - 20170862107 -黄国彪1

    实验报告——Glance镜像服务安装与配置 在OpenStack云平台中,Glance是用于管理和提供虚拟机镜像的服务。本实验旨在让学生了解并掌握如何在CentOS7环境下安装和配置Glance服务,以及验证其功能是否正常运作。通过这...

    glance命令使用

    #### 三、常用选项及参数 ##### 1. 基本选项 - **`-j interval`**: 设置屏幕刷新的时间间隔,单位为秒,默认值为5秒。取值范围:1~32767秒。 - **`-p [dest]`** 和 **`-f dest`**: 这两个选项都用于启用连续打印...

    OpenStack架构详解.pdf

    OpenStack 项目架构包括三个子项目:Swift 提供对象存储,Glance 提供 OpenStack Nova 虚拟机镜像的发现、存储和检索,Nova 根据要求提供虚拟服务。 云提供商概念架构是指构建自己的 IaaS 云环境,并将其提供给用户...

    OpenStack的架构详解

    此概念架构分为三个层次: - **展示层**:用户通过Web门户或API与云服务进行交互。这里还包括负载均衡、安全性等功能。 - **逻辑层**:提供云平台的智能和控制功能,如部署、调度、策略管理等。 - **资源层**:提供...

    Openstack映像管理服务Glance.zip

    Glance 项目为 Openstack 提供了用来发现、注册和获取虚拟机映像的服务,提供 RESTful API 用来查询 VM 映像元数据。 标签:Glance

    源码安装openstack软件包

    在"源码安装openstack软件包"的过程中,我们需要对OpenStack的架构和组件有深入理解,并熟悉Linux操作系统、编译工具以及依赖管理。 首先,OpenStack的组件包括Nova(计算)、Glance(镜像服务)、Cinder(块存储)...

Global site tag (gtag.js) - Google Analytics