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的原始碼。