nova创建虚拟机源码分析系列之四 nova代码模拟
在前面的三篇博文中,介绍了restful和SWGI的实现。结合restful和WSGI配置就能够简单的实现nova服务模型的最简单的操作。
如下的内容是借鉴网上博文,因为写的很巧妙,将nova管理虚拟机的过程刻画十分清楚,所以想自己实现一遍,加深印象。
在上一篇博文中写的URL的对应处理函数,结果是十分简单的return 一个网页。
在openstack当中肯定不会这么简单的处理,毕竟前面的工作只是将路修好,真正的功能还未实现呢!
所以对于nova操作的模拟,要实现的是对虚拟机的增,删,改,查等功能。而这些功能不是在一个return中就能实现的。
nova功能模拟操作的RESTFUl:
URL | 方法 | 描述 |
/instances | GET | 列出集合所有的虚拟机记录 |
/instances | POST | 添加一条虚拟机记录 |
/instances/instance_id | GET | 获取一条虚拟机记录的信息 |
/instances/instance_id | PUT |
更新一条虚拟机的记录 |
/instances/instancd_id | DELETE | 删除一条虚拟机九路 |
在博文中定义的文件如下:
配置WSGI服务器:
1 配置 configure.ini
1 2 3 4 5 6 | [pipeline:main] pipeline = auth instance [app:instance] paste.app_factory = routers:app_factory [filter:auth] paste.filter_factory = auth:filter_factory |
1 | <br>首先解析配置文件,pipeline是管道,管道流是由“过滤器认证模块”auth 和 app 应用程序 instance组成。 |
app 应用程序的位置是routers文件的app_factory方法
filter 过滤器实现的认证模块,位置是auth文件的filter_factory方法。
下面的文件分别实现了router.py和auth.py
2 服务器端
server.py
1 2 3 4 5 6 7 8 9 10 11 12 13 | from wsgiref.simple_server import make_server from paste import httpserver from paste.deploy import loadapp import os if __name__ == '__main__' : configfile = 'configure.ini' appname = 'main' wsgi_app = loadapp( 'config:%s' % os.path.abspath(configfile), appname) server = make_server( 'localhost' , 8000, wsgi_app) server.serve_forever() |
3 filter auth实现程序
auth.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from webob.dec import * from webob import Request,Response from webob import exc class Auth( object ): def __init__(self, app): self.app = app @wsgify def __call__(self, req): print 'Auth class' resp = self.process_request(req) if resp: return resp return self.app(req) @wsgify def process_request(self, req): if req.headers. get ( 'X-Auth-Token' ) != 'open-sesame' : return exc.HTTPForbidden() @wsgify.middleware def filter_factory(app, global_config, **local_config): return Auth(app) |
过滤器的实现,其实现方法是filter_factory,参数有一个app,然后调用Auth方法。Auth方法是类的__call__方法,其实现是:
1 |
1 2 3 4 5 6 7 8 9 | def __call__(self, req): print 'Auth class' 打印了一个字符串 认证具体实现的地方,调用了一个函数。 具体实现就是取出请求报文头中的 'X-Auth-Token' ,判断是不是 'open-sesame' resp = self.process_request(req) if resp: return resp 如果判断通过了,则调用传入的app,具体到本例中就是instance return self.app(req) |
4 app instance实现程序
routers.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | from webob.dec import * from webob import Request,Response import webob.exc from routes import Mapper,middleware import controllers class Router( object ): def __init__(self): self.mapper = Mapper() self.add_routes() self.router = middleware.RoutesMiddleware(self._dispatch, self.mapper) @wsgify def __call__(self, req): return self.router def add_routes(self): controller = controllers.Controller() self.mapper.connect( '/instances' , controller = controller,action = 'create' , conditions = { 'method' : [ 'POST' ]}) self.mapper.connect( '/instances' , controller = controller,action = 'index' , conditions = { 'method' : [ 'GET' ]}) self.mapper.connect( '/instances/{instance_id}' , controller = controller,action = 'show' , conditions = { 'method' : [ 'GET' ]}) self.mapper.connect( '/instances/{instance_id}' , controller = controller,action = 'update' , conditions = { 'method' : [ 'PUT' ]}) self.mapper.connect( '/instances/{instance_id}' , controller = controller,action = 'delete' , conditions = { 'method' :[ 'DELETE' ]}) @staticmethod @wsgify def _dispatch(req): match = req.environ[ 'wsgiorg.routing_args' ][1] if not match: return webob.exc.HTTPNotFound() app = match[ 'controller' ] return app def app_factory(global_config, **local_config): return Router() |
router.py是instance的实现文件。app_factory为处理方法,其调用了Router(),Router()是类Router的__call__()方法。
__call__方法直接返回了对象router,router在初始化的时候实现了函数
1 | middleware.RoutesMiddleware(self._dispatch, self.mapper) |
该函数有两个参数,一个是mapper,一个是_dispatch。传入参数
mapper的作用是在该函数中负责解析URL,根据URL查找到对应的处理函数的类。
_dispath函数就是负责接收mapper解析出来的类,然后调用该类。
可以看到_dispatch从接收到的数据中匹配出app app = match['controller'] ,然后返回了该app,而这个app就是实现nova具体功能的类。对应的类在下面的文件controller中实现。
mapper成员出了作为函数的传入参数之后,还做了一件事情,就是注册了URL的请求和对应方法。简单来说就是注册URL和对应处理函数。
例如:create方法:
1 2 | controller = controllers.Controller() self.mapper.connect( '/instances' , controller = controller,action = 'create' , conditions = { 'method' : [ 'POST' ]}) |
第一行是说变量controller对应的是文件controller.py 中的Controller类。
第二行进行绑定,URL路径是/instances,请求类型是POST,对应的处理方法是 类 Controller中的'create'函数。
5 实际处理函数
controllers.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | import uuid from webob import Request,Response import simplejson from webob.dec import wsgify class Controller( object ): def __init__(self): self.instances = {} for i in range(3): inst_id = str(uuid.uuid4()) self.instances[inst_id] = { 'id' : inst_id, 'name' : 'inst-' + str(i)} #print self.instances @wsgify def create(self, req): print req. params name = req. params [ 'name' ] if name: inst_id = str(uuid.uuid4()) inst = { 'id' : inst_id, 'name' : name} self.instances[inst_id] = inst return { 'instance' : inst} @wsgify def show(self, req, instance_id): inst = self.instances. get (instance_id) return { 'instance ' : inst} @wsgify def index(self, req): return { 'instances' : self.instances.values()} @wsgify def delete(self, req, instance_id): if self.instances. get (instance_id): self.instances.pop(instance_id) @wsgify def update(self, req, instance_id): inst = self.instances. get (instance_id) name = req. params [ 'name' ] if inst and name: inst[ 'name' ] = name return { 'instance' : inst} @wsgify def __call__(self, req): arg_dict = req.environ[ 'wsgiorg.routing_args' ][1] action = arg_dict.pop( 'action' ) del arg_dict[ 'controller' ] method = getattr(self, action) result = method(req, **arg_dict) if result is None: return Response(body= '' ,status= '204 Not Found' ,headerlist=[( 'Content-Type' , 'application/json' )]) else : if not isinstance(result, str): result = simplejson.dumps(result) return result |
终于到了功能具体实现的地方了。当router.py中的_dispatch方法返回了一个app之后,就是调用了该app。这个app就是类名字,同时也是类中的__call__方法。
__call__方法中实现的功能如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @wsgify def __call__(self, req): arg_dict = req.environ[ 'wsgiorg.routing_args' ][1] #获取URL解析结果 action = arg_dict.pop( 'action' ) #获取处理的方法 del arg_dict[ 'controller' ] #删除 controller项,剩下的都是参数列表 method = getattr(self, action) #搜索controller类中定义的方法 result = method(req, **arg_dict) #调用方法,处理HTTP请求 if result is None: #无返回值 return Response(body= '' ,status= '204 Not Found' ,headerlist=[( 'Content-Type' , 'application/json' )]) else :#有返回值 if not isinstance(result, str): result = simplejson.dumps(result) #将返回值转化为字符串 return result |
运行WSGI服务器:
使用请求:
GET http://127.0.0.1:8080/instances
以查看虚拟机情况的流程为例,分析过程:
- 客户端使用命令:curl - H 'X-Auth-Token:open-sesame ' 127.0.0.1:8080/instances,请求虚拟机信息
- server.py中的WSGI服务器一直监听在127.0.0.1的8080端口,收到客户端的请求。请求的具体内容就是上图的"req"打印内容。
- WSGI服务通过配置的configure.ini文件,分析出/instancesURL处理的类是COntroller类。
- router.py中的app_factory被调用,分析URL和添加对应关系之后,调用Controller类。
- Controller类的__call__方法根据 GET方法 + /instance路径分析出对应的处理函数是index。
- 调用index函数,返回结果,判断返回值,将信息返回给客户端。
添加虚拟机:
POST http://127.0.0.1:8080/instances
data : name=demo_one
__EOF__

本文链接:https://www.cnblogs.com/goldsunshine/p/7763395.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理