云计算国产化之路 vnc登录 文件系统直通(virtio-9p) 扩展qemu接口 gpg WARNING 珍藏博客 虚拟内存情况dommemstat分析 免密码自动登录脚本 Linux网桥 测试网段IP占用情况 Linux 进程状态 systemc强制依赖 调试openstack ut uefi p2v 重做ubuntu内核 virsh创建虚拟机简介 virtio IO路径 虚拟化层升级后磁盘无法卸载卷 vmtouch使用 Taint flags 主机和虚拟机文件共享处理的几种方法 kvm分析工具 kvm中对磁盘的io cache 虚拟化不同导致的guestos中软件安装差异(未解决) 设备直通(PCI Assignment)到底是咋整的 virtio到底是咋整的 内核启动参数 虚拟化实时性提升(零)之配置步骤 中断虚拟化(pic)到底是咋整的 中断虚拟化(apic)到底是咋整的 Raid卡配置丢失导致服务器无法启动 tainted kernels cpu stuck for 23s问题分析 虚拟化实时性提升(一)之hostOS切换为强实时系统 内存虚拟化到底是咋整的 qemu-kvm中vcpu虚拟化到底是咋整的 风河虚拟化技术点分析 使用qga的好处 qemu迁移代码分析 虚拟机串口配置及其导出到主机pts和console.log System-based I/O vs. Raw I/O 虚拟机使用Hugepage(大页) 硬件辅助分页(hardware assisted paging) 修改centos7默认启动项目 virtio的工作流程——kernel中virtio-pci初始化(2) virtio的工作流程——qemu中virtio-backend初始化(1) qmp ceilometer取不到memory.usage指标 Virtio-Balloon超详细分析 slabtop输出 虚拟机磁盘cache导致的host os kernel崩溃 虚拟机cpu和memory性能优化测评 PCI配置空间(PCI Configuration Space) centos下网卡设备直通(VT-dpci passthrough)遇到的问题及其解决思路 libguestfs详解 yum卸载软件包及其依赖 通过原始Centos ISO来定制自己的ISO centos下网卡设备直通(VT-d,pci passthrough) (占位符)window虚拟机中拔盘如何通知到libvirt和qemu后端的 cirrus漏洞分析CVE-2017-2615 XSA-208 qcow2随笔 控制寄存器概览 ceilometer对接postgresql 解压initrd和vmlinuz qemu guest agent验证 QEMU升级指南(待续) ubuntu中kdump的配置 qemu(2.3)接口梳理 热迁移导致的FC存储场景下的multipath卷残留问题分析 virsh命令(4)secret,snapshot,pool,volume部分 virsh命令(3)之interface,filter,network virsh命令(2)monitor,host,nodedev部分 virsh命令(1)之domain部分 QEMU内存管理之FlatView模型(QEMU2.0.0) ovirt基于sanock的高可用(主机粒度HA) Sanlock防脑裂场景功能测试用例 gnocchi配置及与ceilometer对接指南 make patch for libvirt in centos centos使用sanlock指导 高可用nfs资料 ubuntu14中使用sanlock指导 LVM操作指南 sanlock相关功能验证流程汇总 make patch for libvirt in ubuntu libvirt.so.0-version `LIBVIRT_PRIVATE_1.2.7' not found gdb debug libvirt 基于ubuntu社区源码包编译libvirt compile libvirt(centos) No PCI buses available nfs lead to Linux halt nfs install and config anti-virus for cloud platform nova fetch image from glance(something about _base) token auth process ovs入门指南 virt software anti-virus something about ceilometer disk sample context interview questions openstack vm injection openstack Restful and RPC murano 概览 创建虚拟机流程(compute节点)之网络创建 创建虚拟机流程之compute_api之虚拟机实例填充之配额检测 创建虚拟机流程之compute_api之基本参数生成 创建虚拟机流程之compute_api 创建虚拟机流程(主) 创建虚拟机之image 创建虚拟机流程之准备网桥 创建虚拟机流程之virt 创建虚拟机流程之compute节点 CI/CD研发流程之工程创建 CI/CD研发流程之代码合入 CI/CD研发流程之UT(单元测试) 向openstack社区合入代码记 openstack/ceilometer/gnocchi杂谈 影子页表原理 mem_add(exec.c) qemu编译安装调试 openstack/ceilometer/gnocchi之Grafana简介 openstack wiki etcd openstack计量ceilometer openstack计费cloudKitty enventlet backdoor USB 安装VMWARE ESX pycharm设置指南 无法执行modprobe -a kvm-intel解决办法 QEMU配置项 网络不通小记 libvirt之XML(虚拟机定义文件) openstack-horizon 证书认证 ceilometer与ceph对接 openstack定时任务剖析(TODO) 服务器重启后mongodb进程无法启动 ubuntu14下新增openstack服务到service的导引 ERROR 1045(28000)-数据库连不上 Python两个内置函数—locals和globals unknown exit, hardware reason 31

openstack Restful and RPC

2016年05月12日

简介

OpenStack的通信方式有两种,一种是基于HTTP协议的RESTFul API方式,另一种则是RPC调用。

两种通信方式的应用场景有所不同:
RESTFul API主要用于各组件之间的通信(如nova与glance的通信)
RPC用于同一组件中不同模块间的通信(如nova组件中nova-compute与nova-scheduler)。

Restful

基础知识

rest构建在HTTP协议之上(其实这俩都是一个哥牵头搞出来的)

rest处理流程由HTTP请求、解析HTTP请求、发送HTTP响应等一系列活动组成
如果使用rest需要进行上述动作,可以想象整个过程十分繁杂
所以,将上述活动屏蔽起来,对外展现一个统一的接口(也就是wsgi,Web Server Gateway Interface)。

这样,只要按照wsgi规范实现对应的接口,就可以使用rest服务了。
开发者专注于开发自己的业务流程就可以了。

WSGI

想使用wsgi,我们首先要明白wsgi只是一个规范
它规定了组件,组件间的接口等

让我们先看下wsgi的三个组件:

  • Application
  • Server
  • client

三个组件间消息流向为:
client发送请求给server,server转发这个请求给application.
然后application进行一系列的操作后,将响应返送给server,server再将相应转给client.
server只起到一个中转的作用。

Application

Application是具体干活的组件,当有请求的时候会调用对应Application处理消息。

因此,Application要能被调用,即Callable。
换句话说,它应该是一个函数或者定义了__call__方法的对象,__call__方法的签名是这样的:

def __call__(environ: Dict[String, Any], start_response: (String, List) -> Any)): 
    Iterable[String]

Server

如前文所述: Server唯一的任务就是接收来自 client 的请求,然后将请求传给 application,最后将 application 的response 传递给 client

简单例子

from eventlet import wsgi  
import eventlet  
def hello_world(env, start_response):  
    start_response('200 OK', [('Content-Type', 'text/plain')])  
    return ['Hello, World!\r\n']  
wsgi.serve(eventlet.listen(('', 8090)), hello_world)  

本例中hello_world是一个Application
使用eventlet.wsgi生成的server调用hello_world
然后返回结果

中间件(Middleware)

有些情况下,请求不会直接流向Application
而是经历一系列的中间件处理,如下图

oenstack源码剖析

几个库

openstack中使用了一系列的库,组合完成wsgi功能,如下:

  • Paste.deploy
    Paste Deployment是用于发现和配置WSGI appliaction和server的插件。
    对于WSGI application,用户提供一个单独的函数(loadapp),用于从配置文件或者python egg中加载WSGI application。

  • webob
    Request和Response处理。
    简单理解为从HTTP中抽取并组装成Request对象。

  • eventlet.wsgi
    eventlet提供一个WSGI server的功能

  • routes.Mapper

    connect()方法,将url和controller建立链接
    routematch()匹配到返回一个router对象,匹配不到,返回None

服务启动

以nova-api服务为例,在setup.cfg中可以看到nova-api服务入口如下

main方法中,主要流程为,构造出一个WSGIService对象,交付给launcher去启动

WSGIService初始化的时候,会使用Paste.deploy.loadapp这个插件加载wsgi的配置文件(/etc/nova/api-paste.ini)
(具体加载过程见api-paste.ini解析小节)

最终是使用的Paste.deploy

然后使用加载的app作为参数,构造出wsgi.Server对象

launcher启动的时候,会调用到wsgi.Server的start方法

也就孵化了个线程,去执行eventlet.wsgi.server方法

至此,wsgi服务启动 服务启动了socket去监听端口(默认8774),当有http请求时候进入消息处理阶段

api-paste.ini解析

刚刚看到加载app是通过Paste.deploy
与Paste.deploy的交互式通过api-paste.ini
下面我们看下解析api-paste.ini的解析过程

[composite:osapi_compute]  #入口会是这里 
  use = call:nova.api.openstack.urlmap:urlmap_factory #调用urlmap_factory方法,后面几行作为入参传入
  /: oscomputeversions
  /v1.1: openstack_compute_api_v2
  /v2: openstack_compute_api_v2
  /v2.1: openstack_compute_api_v21
  /v3: openstack_compute_api_v3

调用nova.api.openstack.urlmap:urlmap_factory方法,将后面四行作为参数
urlmap_factory以此加载这几个composite,组装成urlmap字典

以openstack_compute_api_v2为例

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth2 = compute_req_id faultwrap sizelimit noauth2 ratelimit osapi_compute_app_v2
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2

nova.api.auth:pipeline_factory方法根据在nova.conf中配置的认证策略选择到不同的处理

这假设auth_strategy配置的为keystone
则会选到下面这条处理链

keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2

首先会加载osapi_compute_app_v2(下一小节单独分析)

然后用前面的filter依次装饰osapi_compute_app_v2 注意是逆向,keystonecontext(ratelimit(osapi_compute_app_v2)),类似穿了多层衣服。

消息处理的时候,再一层层脱衣服。

osapi_compute_app_v2加载

[app:osapi_compute_app_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

调用nova.api.openstack.compute:APIRouter.factory方法
实际上是调用的父类nova.api.openstack.APIRouter的factory方法
也就是其__init__方法

  • ExtensionManager初始化
    加载nova.api.openstack.compute.legacy_v2.contrib目录下除了init外的py文件
    每个py文件内有个同名类,这里将同名类,放置到ExtensionManager队列中
    实现Extension的加载


    调用nova.api.openstack.compute.legacy_v2.ExtensionManagerd的init方法

    其中,CONF.osapi_compute_extension为默认:
    nova.api.openstack.compute.legacy_v2.contrib.standard_extensions
    进而调用父类的_load_extensions()->load_extension()

    这里factory为nova.api.openstack.compute.legacy_v2.contrib.standard_extensions()
    self为ExtensionManager初始化

    load_standard_extensions会把包路径下的文件一个个加载进来

    这里以Admin_actions为例

    可见同多数的extension一样,都继承自nova.api.openstack.ExtensionDescriptor
    而ExtensionDescriptor在初始化的时候会将自己注册给ExtensionManager
    看下ExtensionManager的register()会发现,是把Extension放到self.extensions里

    到这里ExtensionManager初始化完成,至此,ExtensionManager的exensions中缓存加载的extension.

  • nova.api.openstack.APIRouter->_setup_routes
    将url和controller建立对应关系
    不同资源之间建立层级父子关系

  • nova.api.openstack.APIRouter->_setup_ext_routes()
    添加extension的资源相关

  • _setup_extensions()
  • super(APIRouter, self).init(mapper)
    routes.middleware.RoutesMiddleware,将接受到的url,自动调用map.match()方法
    将url进行路由匹配并将结果存入request请求的环境变量[‘wsgiorg.routing_args’]
    最后会调用其第一个参数给出的函数接口,即self.dispatch。

请求处理篇

keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2

这里 [filter:compute_req_id] paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory

会依次调用call方法

#############
# OpenStack #
#############

v3与v2版本差异

v3版本不再区分core api和extension api
所有的都通过extension api方式提供

加载的时候,读取配置文件setup.cfg中nova.api.v3.extensions部分

也就是说v3或者v2.1使用的代码目录是这里

v2版本的实现代码是这里

api-paste.ini全集

[composite:osapi_compute]  #入口会是这里         
use = call:nova.api.openstack.urlmap:urlmap_factory #调用urlmap_factory方法,后面几行作为入参传入
/: oscomputeversions
/v1.1: openstack_compute_api_v2
/v2: openstack_compute_api_v2
/v2.1: openstack_compute_api_v21
/v3: openstack_compute_api_v3

[composite:openstack_compute_api_v2]
use = call:nova.api.auth:pipeline_factory
noauth2 = compute_req_id faultwrap sizelimit noauth2 ratelimit osapi_compute_app_v2
keystone = compute_req_id faultwrap sizelimit authtoken keystonecontext ratelimit osapi_compute_app_v2
keystone_nolimit = compute_req_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v2

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

[composite:openstack_compute_api_v3]
use = call:nova.api.auth:pipeline_factory_v21
noauth = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3
noauth2 = request_id faultwrap sizelimit noauth_v3 osapi_compute_app_v3
keystone = request_id faultwrap sizelimit authtoken keystonecontext osapi_compute_app_v3

[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory

[filter:compute_req_id]
paste.filter_factory = nova.api.compute_req_id:ComputeReqIdMiddleware.factory

[filter:faultwrap]
paste.filter_factory = nova.api.openstack:FaultWrapper.factory

[filter:noauth2]
paste.filter_factory = nova.api.openstack.auth:NoAuthMiddleware.factory

[filter:noauth_v3]
paste.filter_factory = nova.api.openstack.auth:NoAuthMiddlewareV3.factory

[filter:ratelimit]
paste.filter_factory = nova.api.openstack.compute.limits:RateLimitingMiddleware.factory

[filter:sizelimit]
paste.filter_factory = oslo_middleware:RequestBodySizeLimiter.factory

[filter:legacy_v2_compatible]
paste.filter_factory = nova.api.openstack:LegacyV2CompatibleWrapper.factory

[app:osapi_compute_app_v2]
paste.app_factory = nova.api.openstack.compute:APIRouter.factory

[app:osapi_compute_app_v21]
paste.app_factory = nova.api.openstack.compute:APIRouterV21.factory

[app:osapi_compute_app_v3]
paste.app_factory = nova.api.openstack.compute:APIRouterV3.factory

[pipeline:oscomputeversions]
pipeline = faultwrap oscomputeversionapp

[app:oscomputeversionapp]
paste.app_factory = nova.api.openstack.compute.versions:Versions.factory

##########
# Shared #
##########

[filter:keystonecontext]
paste.filter_factory = nova.api.auth:NovaKeystoneContext.factory

[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory

RPC

(TODO)待分析rabbitmq