Glance源码架构探秘(三)

Glance源码架构探秘(二) Glance源码架构探秘(一) Glance源码架构探秘(二) Glance源码架构探秘(三) Glance源码架构探秘(四) 上一章的最后,为大家介绍了Glance服务的对外启动接口/bin/glance-api,其中最用要的部分就是通过server = eventlet.wsgi.Server()生成了一个http server,并通过server.start()启动了 阅读详情

Glance源码架构探秘(一)

Glance源码架构探秘(二)

Glance源码架构探秘(三)

Glance源码架构探秘(四)


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

其实,简单的说,Glance及其他OpenStack的组件和大多数的web service一样,也是实现了一个MVC的框架的(关于MVC框架的概念,并不是本文的重点,可自行展开阅读),这个框架称之为RackSpace框架。包括消息路由,控制器Controller、action等等。

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

Routes用法非常清晰明了

# 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>', 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

@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等等。

下面我们看Glance的源码节选分析

我们先来看router.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函数进行调用。该思想可参见我的另一篇文章Python可调用对象__call__方法的用法分析。routes.middleware是routes组件中另外一个重要的模块,他可以从上层wsgi程序中接收request请求的URL,并自动调用map.match()方法,将URL进行消息路由,并返回路由的结果。路由结果将会被存入request请求的环境变量['wsgiorg.routing_args']中。最后会调用其第一个参数给出的函数接口,继续下一级的WSGI调用,代码中就是self._dispatch。

这层的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 deserialization
                             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

Resource这个类可以对请求解串行化,或串行化响应信息,并可以分发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等组件的源码探秘,此部分也不再会单独分析,将把经历多投入到其他方面。


后面几章将开始具体分析glance在接到请求命令后,如何进行镜像的上传,下载,更新等,同样包括数据库和镜像元数据更新等的操作,其中用到了许多非常棒的设计模式,敬请期待!






Openstack Glance源码架构解析 这段时间捣鼓了一下Glance源代码,还是有收获的,修改了部分代码实现了支持多个ceph存储后端的功能。这个功能是不是个伪需求都还待定,反正也就当磨练了。 关于支持多个ceph存储后端的功能,稍微说一下 需要实现的功能就是在命令中行上传镜像,通过指定集群将镜像上传到不同ceph集群中。在通过nova创建虚拟机的时候肯定也需要能够使用这些创建虚拟机,当然这在计算节点的nova配置中就能实现 阅读详情

相关推荐

IEC 62056协议栈深度拆解:从物理层握手到应用层AARQ,一次完整的DLMS通讯抓包分析

本文深入解析IEC 62056协议栈(DLMS/COSEM)的全流程通信机制,从物理层握手到应用层AARQ建立,提供详细的抓包分析和实战指南。涵盖RS-485配置、HDLC帧解析、OBIS编码解读等核心内容,并附有常见故障排查技巧,助力开发者高效实现电能表数据采集。

weixin_29182481的博客 312

Openstack glance服务配置错误

Ubuntu open stack安装配置glance ,上传image时,报错. 500 Internal Server Error: The server has either erred or is incapable of performing the requested operation. (HTTP 500)

cynosure617的博客 1067

海康工业相机SDK开发实战:从环境搭建到实时图像采集(附避坑指南)

本文详细介绍了海康工业相机SDK在Windows平台上的开发实战流程,涵盖从环境搭建、运行时库路径配置到实时图像采集的全过程。重点解析了MVS SDK部署、设备连接、参数设置及图像处理等核心环节,并提供了实用的避坑指南和错误排查方法,帮助开发者构建稳定的机器视觉系统。

weixin_29248611的博客 846

HTTP 500 Internal Server Error: 错误的解决方法

创建openstack镜像的时候报错。HTTP 500 Internal Server Error: The server has either erred or is incapable of performing the requested operation 查看cat /var/log/glance/api.log日志显示如下。 2022-02-13 11:18:53.201 5691 ERROR glance.common.wsgi six.reraise(type(de_ref..

weixin_54628931的博客 9070

西门子1200之PID用法与控制

西门子PID加热试验

gyxgyx789的博客 6259

双目相机立体匹配算法概述(含Python代码)

立体匹配任务是计算机视觉中的一个重要问题,旨在从一对具有相同场景的图像中估计每个像素的视差(disparity)。本文对现有的传统算法和深度学习算法进行了综述,以便于各位选择合适的立体匹配算法用于深度估计或三维建模。

m0_59257547的博客 8293

安装openstack时碰到的错误

目录 安装keystone identity时遇到的错误信息 glance验证操作错误信息 计算节点安装openstack-nova-compute找不到包 openstack-nova-compute安装后服务起不来 openstack-nova-compute安装后验证没有输出 dashboard安装后打不开 OpenStack云平台涉及到的相关服务进程的日志记录的默认存放地址 总结

gsl371的专栏 2万+

YOLOv8+BiFPN双向特征金字塔:多尺度目标检测精度提升28%的实战教程

双向特征金字塔网络(BiFPN)是一种强化多尺度特征融合支持“自顶向下+自底向上”的双向特征流动,同时保留不同尺度的细节信息;引入加权融合机制,自动学习不同特征的重要性权重;裁剪冗余节点,在轻量化的同时提升融合效率。

m0_64661770的博客 492

已解决:openstack:上传glance镜像报错:“500 Internal Server Error”

500 Internal Server Error: The server has either erred or is incapable of performing the requested operation. (HTTP 500) glance配置文件没有问题 端口以及服务没有问题 数据库用户没有问题 但报错!!! 事已至此,那就先看看报错日志怎么说吧 [root@chensyk ~]# cd /var/log/glance [root@chensyk glance]# ll total 60

chensay的博客 8140

Qt(C++)使用QChart动态显示3个设备的温度变化曲线

Qt的QChart是一个用于绘制图表和可视化数据的类。提供了一个灵活的、可扩展的、跨平台的图表绘制解决方案,可以用于各种应用程序,如数据分析、科学计算、金融交易等。

1917

VMware报错系列:虚拟机配置文件(.vmx)损坏或丢失---修复

虚拟机配置文件(.vmx)损坏或丢失---修复

weixin_54626591的博客 7012

kolla 安装openstack问题

https://www.cnblogs.com/chaofan-/p/11715402.html 销毁重新部署时,出现错误:MariaDB cluster exists but is stopped 检查出错节点的docker volume 是否没有清理干净 错误1: 检查环境时,no module named docker pip install docker 错误2:环境检查时,nova任务时报错TASK [nova : Ensuring config directories exist.

qq_42533216的博客 5983

达梦数据库修改最大连接数

达梦数据库的最大连接数推荐配置与服务器内存有关。不应设置得过大,否则容易导致出现OOM。文件中整型的参数值。DSC环境下,除了特殊参数以外,其他参数值会在OK节点上同步。返回值:当前DM.INI文件中对应的参数值。功能说明:返回DM.INI文件中。:DM.INI文件中的参数名。

Sebastien23的博客 3336

Glance源码架构探秘(一)

Glance源码架构探秘(一) Glance源码架构探秘(二) Glance源码架构探秘(三) Glance源码架构探秘(四) 前言 从本章开始,将会陆续为大家分享有关OpenStack各组件模块代码架构的探秘。首先从OpenStack的镜像管理模块Glance开始,原因是Glance只负责镜像的上传,下载等管理,功能对比Nova模块来说相对比较少,便于代码结构的分析。还

熠耀之森 7008

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Glance源码架构探秘(四)

Glance源码架构探秘(一) Glance源码架构探秘(二) Glance源码架构探秘(三) Glance源码架构探秘(四) 最近感情生活颇不顺利,耽搁了很长时间。今天抽出时间来给大家继续分享Glance源码架构探秘,详细阐述glance镜像操作部分。 前几章,我们花了很大的篇幅,讨论了Glance服务的WSGI框架部分,包括网络编程eventlet库,绿化的w

熠耀之森 3505

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Glance源码架构探秘

http://blog.youkuaiyun.com/networm3/article/details/8651324 Glance只负责镜像的上传,下载等管理。 Glance项目提供虚拟机镜像的查找,注册和重现,使用RESTful接口接受虚拟机镜像管理的查询请求。 从F版开始使用的API V2,相对于V1版大大简化了流程,将glance-api与glance-registry合并在了一

ztejiagn的专栏 2114

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Glance源码结构分析

一 Glance源码目录结构[root@localhost glance]# tree -L 2 . ├── api-ref │ └── source ├── etc │ ├── glance-api.conf │ ├── glance-api-paste.ini │ ├── glance-cache.conf │ ├── glance-glare.conf │ ├── g...

实践求真知 1196

Glance源码深入解读

OpenStack是目前主流的开源云计算平台,它通过解耦的架构分别提供了计算、快存储、镜像、网络、认证等服务,其中镜像服务是六大核心组件之一。Glance实现了OpenStack平台的Image service,为云平台提供镜像上传、下载和管理等功能,通过对Glance源码的深入解读,让我们更深层次得认识这个简单而又复杂的镜像服务。 Glance项目全部由Python编写,读者需要掌握Pyt

zhuangshu_feng'‘每天进步一点点 3244

Openstack liberty Glance上传镜像源码分析

该文同时发布在[ceph中国社区],署名为Thomas 在Openstack中创建云主机,首先得有镜像,而Glance模块提供镜像服务功能,包括:镜像的发现、检索及存储等,主要包括:glance-api和glance-registery两个服务,分别负责镜像的存储和元数据管理。下面基于源码,分析下镜像的上传过程。上传镜像先通过glance CLI上传镜像,来直观的了解下镜像上传的过程:# glanc

梦幻之巅 1万+

Glance源码架构深度解析:Swift与Go混合开发Quick Look插件的设计之道

Glance 是一款 All-in-one 的 macOS Quick Look 插件,能让 Finder、Spotlight 与 Quick Look 直接预览 macOS 原生不支持的多种文件格式。本文深度解析 Glance 源码架构,带你读懂它如何以 Swift 与 Go 混合开发的巧妙设计,把语法高亮、Markdown 渲染、压缩包浏览等能力统一装进一个轻量插件中。无论你是想学习 macO

gitblog_00773的博客 1031

openstack创建虚拟机源码分析三(Glance下载镜像)

控制节点上可以查看glance的服务 glance-registry,负责处理image的metadata ...

TinaSprunt的开发笔记 1630

Glance源码

Glance项目全部由Python编写,读者需要掌握Python语法和wsgi、evenlet、webob、paste等类库,生产环境的镜像一般存在分布式存储中因此还会涉及部分Ceph基础知识。 作用与用法 深入学习一个项目前,我们要了解这个项目的作用和使用方法。Glance提供了镜像上传和下载功能,也就是说管理员可以通过Glance来上传镜像,而普通用户可以通过Glance下

zhuangshu_feng'‘每天进步一点点 938
上一篇: Linux的IO复用
下一篇: Linux下如何知道文件被那个进程写
Ethan_熠森张
博客等级 码龄18年 124粉丝 51原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值