1. 程式人生 > >OpenStack之RESTful API呼叫(二)

OpenStack之RESTful API呼叫(二)

接著上面的文章,我們繼續來談RESTful API。我們知道RESTful API訪問的URL都稱之為“資源”。一個資源可能是一個集合,也可能是一個個體。要實現複雜的功能,不可能只通過一條URL來完成,因此必須定義多條URL,如何定義多條URL也是RESTful API要考慮的問題。

在OpenStack中,一個虛擬機器的管理包括建立、查詢、更新和刪除等操作,使用者可以通過傳送HTTP請求來實現虛擬機器的管理,我們下面就來分析怎樣來實現這樣一個WSGI服務。

我們用instances來表示虛擬機器的集合,每一個instance(虛擬機器例項)具有全域性唯一的UUID。在WSGI中,要實現URL對映,主要依靠Mapper和Controller兩個類。Mapper類用於實現URL對映,當收到使用者的請求時,Mapper類會根據使用者請求的URL和方法來確定處理的方法。而Controller類,則是實現處理HTTP請求的各種方法。Mapper類是routes包中定義好的,Controller類需要自己實現。

還是先來看api-paste.ini配置檔案

[pipeline:main]
pipeline = auth instance
[app:instance]
paste.app_factory = routes:app_fatory
[filter:auth]
paste.filter_factory = middleware:Auth.factory
從配置檔案可以看到,該WSGI服務使用了auth過濾器和instance應用程式兩個部件。其中auth過濾器和上篇文章用到的過濾器一樣,其作用是驗證使用者的身份。instance應用程式對應routers包的app_factory工廠方法。

所以我們重點來看instance應用,核心功能都在這裡了。

def app_factory(global_config,**local_config):
    return Router()
該工廠方法返回了一個Router物件,來看一下Router類。
class Router(object):
    def __init__(self):
        #建立Mapper物件,Mapper用於URL的解析
        self.mapper = routes.Mapper()
        #向Mapper物件中新增URL對映
        self.add_routes()
        self._router = routes.middleware.RoutesMiddleware(self._dispatch,self.mapper)
    @wsgify(RequestClass=webob.Request)
    def __call__(self,request):
        return self._router
    def add_routes(self):
        controller = controllers.Controller()
        #新增URL對映
        self.mapper.connect("/instances",controller=controller,action="create",
                            conditions=dict(method=["POST"]))
        self.mapper.connect("/instances/{instance_id}",controller=controler,action="show"
                            condition=dict(method=["GET"]))
        self.mapper.connect("/instances/{instance_id}",controller=controller,action="update"
                            condition=dict(method=["PUT"]))
        self.mapper.connect("/instances/{instance_id}",controller=controller,action="delete"
                            condition=dict(method=["DELETE"]))
    @wsgify(RequestClass=webob.Request)
    def _dispatch(request):
        #獲取URL的解析結果
        match = request.environ['wsgiorg.routing_args'][1]
        if not match:
            return _err()
        #獲取URL對應的controller
        app = match['controller']
        return app

這是一個可呼叫的類,__call__方法很簡單,就是返回_router變數。當伺服器接收到HTTP請求時,__call__方法被呼叫,會轉而呼叫_router。_router變數定義在Router類的初始化方法中。可以看到add_routes方法中添加了4條URL對映,分別實現對虛擬機器的“增、刪、改、查”操作。這裡呼叫了mapper物件的connect方法。routes包中的RoutesMiddleware是一個可呼叫的物件,它首先通過mapper物件解析資訊,然後將解析結果傳遞給_dispatch方法。

最後來看Controller類的實現,從上面的分析可以看到,伺服器接收到HTTP請求後,先經過Mapper類的對映解析,最終後呼叫Controller類的__call__方法。

class Controller(object):
    @wsgify(RequestClass=webob.Request)
    def __call__(self,request):
        #獲取URL的解析結果
        arg_dict = request.environ['wsgiorg.routing_args'][1]
        #獲取處理方法
        action = arg_dict.pop('action')
        #搜尋controller類中定義的方法
        method = getattr(self,action)
        #呼叫方法處理HTTP請求
        result = method(request,**arg_dict)
        if result is None:
            return webob.Response(body='',status='204 Not Found',
                                  headerlist=[('Content-Type','application/json')])
        else:
            if not isinstance(result,basestring):
                result = simplejson.dumps(result)
            return result
對於上述定義的4條URL對映資訊所對應的方法就不一一展開了,這裡只給出create方法(建立虛擬機器)和show方法(查詢虛擬機器)。
class Controller(object):
    def create(self,request):
        name = request.params['name']
        if name:
            inst_id = str(uuid.uuid4())
            inst = {'id':instance_id,'name':name}
            self.instances[inst_id] = inst
            return {'instance':inst}
    def show(self,request,instance_id):
        inst = self.instances.get(instance_id)
        return {'instance':inst}
WSGI服務啟動後,可以在另一個終端運用curl進行測試。其中create方法可以應用“curl -H “X-Auth-Token:open-sesame” -X POST --data "name=new-inst" 127.0.0.1:8080/instances”進行測試;show方法可以應用“curl -H “X-Auth-Token:open-sesame” -X GET 127.0.0.1:8080/instances/{instance_id}”進行測試。

至此,OpenStack中基於RESTful API的呼叫已介紹完畢,當然比起OpenStack的原始碼,這只是一個很簡單的實現。有興趣的朋友可以繼續去讀OpenStack的原始碼。