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配置中就能实现 阅读详情

相关推荐

【Python・统计学】(两)多因素方差分析(原理及代码)

自学笔记,分享给对统计学原理不太清楚但需要在论文中用到的小伙伴,欢迎大佬们补充或绕道。ps:本文不涉及公式讲解(文科生小白友好体质)~(部分定义等来源于知乎) 本文重点:多因素方差分析 【1.多因素方差分析简单原理】 【2.多因素方差分析步骤】 【3.多因素方差分析代码】

TUTO_TUTO的博客 4867

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

手把手教你用运放搭建方波三角波发生器(附Multisim仿真文件)

本文详细解析了使用运算放大器搭建方波和三角波发生器的核心原理与设计步骤。通过剖析迟滞比较器与积分器的联动机制,指导读者进行电路设计、元件选型,并借助Multisim仿真进行参数调优与波形优化。文章提供了从理论分析、虚拟仿真到实物焊接调试的完整实践指南,并附有仿真文件,帮助硬件爱好者与初学者深入掌握这一经典模拟电路设计。

weixin_29165725的博客 640

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

【代码】获取高级行情数据,并通过 qmt 进行实际下单交易,自动实现止盈止损管理

【代码】获取高级行情数据,并通过 qmt 进行实际下单交易,自动实现止盈止损管理

XD1996CD的博客 4110

Charles 抓包工具下载安装及基础使用

本篇内容主讲关于Charles抓包工具,从下载安装以及配置信息,证书的下载安装以及PC端设置代理配置和移动端设备配置代理,阐述关于Charles抓包工具面板的基础使用以及如何进行抓包和设置断点,对于软件测试以及对抓包感兴趣的读者可以翻阅!感谢大家的支持!!!

灵魂学者的博客 2959

安装openstack时碰到的错误

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

gsl371的专栏 2万+

【域控制器EMC】域控制器EMC设计总结

汇总项目设计当中关于EMC的设计要点,主要从原理设计、Layout、结构、外设部分总结。满足要求的器件和合理的电路能降低电磁干扰;正确的布局、接地、信号路径、屏蔽等可以减少电磁辐射。结构件设计也会对EMC性能产生影响。

weixin_42098658的博客 1259

已解决: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

YOLOv9改进,YOLOv9添加CBAM注意力机制

CBAM是一个简单而有效的注意力模块,用于前馈卷积神经网络。给定一个中间特征图,我们的模块按顺序推断两个独立维度(通道和空间)的注意力图,然后将注意力图乘以输入特征图以进行自适应特征细化。由于 CBAM 是一个轻量级的通用模块,因此它可以无缝集成到任何 CNN 架构中,开销可以忽略不计,并且可以与基础 CNN 一起进行端到端训练。论文链接:(CBAM论文)

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 857

基于Python的新闻聚合与推荐系统:抓取多新闻网站内容并根据用户兴趣进行个性化推荐

本文介绍了如何使用Python构建一个新闻聚合与推荐系统,涵盖了从新闻数据抓取、用户兴趣建模到推荐算法实现的全过程。通过爬虫技术抓取新闻网站内容,使用TF-IDF、Word2Vec等算法进行内容分析,并通过推荐算法向用户推送个性化的新闻,最终帮助用户快速获取自己感兴趣的信息。你可以根据具体需求,进一步扩展和优化系统。例如,加入更多的推荐算法、优化爬虫的抓取效率、增强前端展示的互动性等。通过本文的指导,您应该能够构建一个完整的新闻聚合与推荐系统,并为用户提供个性化的新闻推荐服务。

2201_76125261的博客 1515

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

【Inpho精品教程】Inpho简介、安装教程(附Inpho8安装包下载)

本文介绍Trimble旗下Inpho UASMaster航空摄影测量软件,涵盖其核心功能模块(如Match-AT、OrthoMaster、Summit Evolution等)及安装教程。文章详细说明了从安装到汉化破解的全过程,并提供Inpho 8.0.1安装包下载链接与提取码,适用于无人机摄影测量专业用户。

智慧空间实验室 1万+

Glance源码架构探秘(一)

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

熠耀之森 7008

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Glance源码架构探秘(四)

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

熠耀之森 3505

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Glance源码架构探秘

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

ztejiagn的专栏 2114

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、付费专栏及课程。

余额充值