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

[pipeline:main]  
pipeline = auth instance  
[app:instance]  
paste.app_factory = routers:app_factory  
[filter:auth]  
paste.filter_factory = auth:filter_factory  

首先解析配置文件,pipeline是管道,管道流是由“過濾器認證模塊”auth 和 app 應用程序 instance組成。

app 應用程序的位置是routers文件的app_factory方法

filter 過濾器實現的認證模塊,位置是auth文件的filter_factory方法。

下面的文件分別實現了router.py和auth.py

 2 服務器端

server.py

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

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__方法,其實現是:

 
        
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

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在初始化的時候實現了函數

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方法:

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

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__方法中實現的功能如下:

    @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

 

以查看虛擬機情況的流程為例,分析過程:

  1. 客戶端使用命令:curl - H 'X-Auth-Token:open-sesame ' 127.0.0.1:8080/instances,請求虛擬機信息
  2. server.py中的WSGI服務器一直監聽在127.0.0.1的8080端口,收到客戶端的請求。請求的具體內容就是上圖的"req"打印內容。
  3. WSGI服務通過配置的configure.ini文件,分析出/instancesURL處理的類是COntroller類。
  4. router.py中的app_factory被調用,分析URL和添加對應關系之后,調用Controller類。
  5. Controller類的__call__方法根據 GET方法 + /instance路徑分析出對應的處理函數是index。
  6. 調用index函數,返回結果,判斷返回值,將信息返回給客戶端。

添加虛擬機:

POST http://127.0.0.1:8080/instances

data : name=demo_one

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM