Nova API服務 之 建立虛擬機器流程(1)
本小節,將以虛擬機器建立請求為例,分析底層Controller類的HTTP請求處理方法。
一、回憶總結
1、處理HTTP請求的核心工作都在底層Controller物件中定義。Resource物件在底層Controller物件的基礎上,實現
數據的轉化工作。
2、Resource物件首相將傳入的物件反序列化。然後將資料交給底層Controller物件中相應的處理方法處理。最後將
底層Controller物件處理方法返回的結果序列化。
二、建立虛擬機器流程
1、以建立虛擬機器請求為例,分析底層controller物件的定義。底層controller類中,處理虛擬機器建立請求的方法是
create方法。
2、servers.Controller類的create方法
每個資源都對應一個底層的Controller類。servers資源的底層Controller類定義在servers包中。處理虛擬機器建立
請求的方法為create方法。定義如下:
(1)、這個類繼承自wsgi.Controller,該類位於nova/nova/api/openstack/wsgi.py。首先為create方法指定了序列class Controller(wsgi.Controller): _view_builder_class = views_servers.ViewBuilder @wsgi.response(202) @wsgi.serialozers(xml=FullServerTemplate @wsgi.deserialozers(xml=CreateDeserializer) def create(self, req, body): #為給定的使用者建立新的虛擬機器 檢查HTTP訊息體是否合法 if not self.is_valid_body(body, 'server'): raise exc.HTTPUnprocessableEntity() #獲取客戶端傳入的虛擬機器引數 context = req.environ['nova.context'] server_dict = body['server'] ... #獲取和檢查虛擬機器名 name = server_dict['name'] self._validate_server_name(name) name = name.strip() #獲取虛擬機器的磁碟映象uuid image_uuid = self._image_from_req_data(body) .... # 獲取客戶端需求的網路 requested_networks = self._determine_requested_networks(server_dict) #獲取和驗證客戶端指定的虛擬機器IP (access_ip_v4, ) = server_dict.get('accessIPv4'), if access_ip_v4 is not None: self._validate_access_ipv4(access_ip_v4) (access_ip_v6, ) = server_dict.get('accessIPv6'), if access_ip_v6 is not None: self._validate_access_ipv6(access_ip_v6) #獲取虛擬機器規格ID flavor_id = self._flavor_id_from_req_data(body) # optional openstack extensions: key_name = self._extract(server_dict, 'os-keypairs', 'key_name') availability_zone = self._extract(server_dict, 'os-availability-zone', 'availability_zone') user_data = self._extract(server_dict, 'os-user-data', 'user_data') self._validate_user_data(user_data) image_uuid_specified = bool(image_uuid) legacy_bdm, block_device_mapping = self._extract_bdm(server_dict, image_uuid_specified) ret_resv_id = False # min_count and max_count are optional. If they exist, they may come # in as strings. Verify that they are valid integers and > 0. # Also, we want to default 'min_count' to 1, and default # 'max_count' to be 'min_count'. min_count = 1 max_count = 1 if self.ext_mgr.is_loaded('os-multiple-create'): ret_resv_id = server_dict.get('return_reservation_id', False) min_count = server_dict.get('min_count', 1) max_count = server_dict.get('max_count', min_count) try: min_count = utils.validate_integer( min_count, "min_count", min_value=1) max_count = utils.validate_integer( max_count, "max_count", min_value=1) except exception.InvalidInput as e: raise exc.HTTPBadRequest(explanation=e.format_message()) if min_count > max_count: msg = _('min_count must be <= max_count') raise exc.HTTPBadRequest(explanation=msg) auto_disk_config = False if self.ext_mgr.is_loaded('OS-DCF'): auto_disk_config = server_dict.get('auto_disk_config') scheduler_hints = {} if self.ext_mgr.is_loaded('OS-SCH-HNT'): scheduler_hints = server_dict.get('scheduler_hints', {}) check_server_group_quota = self.ext_mgr.is_loaded( 'os-server-group-quotas') try: #獲取虛擬機器規格資訊 _get_inst_type = flavors.get_flavor_by_flavor_id inst_type = _get_inst_type(flavor_id, ctxt=context, read_deleted="no") #呼叫compute API建立虛擬機器 (instances, resv_id) = self.compute_api.create(context, ...) ... except UnicodeDecodeError as error: ... #將虛擬機器資訊轉化為字典 server = self._view_builder.create(req, instances[0]) if CONF.enable_instance_password: server['server']['adminPass'] = password #將虛擬機器資訊封裝成ResponseObject物件 robj = wsgi.ResponseObject(server) #新增訪問當前虛擬機器資源的url return self._add_location(robj)
化物件、反序列化物件和預設的HTTP Code。接著我們進入create方法,來分析程式碼。
先來看看context = req.eviron['nova.context']究竟拿到了什麼資訊,這個上下文資訊物件是由類
nova.context.RequestContext例項化而來。我們來把獲取到的context打印出來,這樣方便大家理解。
user_id = afc380206e2549ad930396d9050d20cf project_id = 0e492e86f22e4d19bd523f1e7ca64566 roles = [u'admin', u'KeystoneAdmin', u'KeystoneServiceAdmin'] read_deleted = no remote_address = 172.21.6.145 timestamp = 2013-06-23 16:36:37.399405 request_id = req-f0255b14-833d-4fff-b973-23c35f70ddda auth_token = 7e7bb3cf84ab43269010bb55410064b3 service_catalog = [{u'endpoints': [{u'adminURL': u'http://172.21.5.161:8776/v1/0e492e86f22e4d19bd523f1e7ca64566', u'region': u'RegionOne', u'id': u'753a1ad55e91469794e2eb7ac4c3df92', u'internalURL': u'http://172.21.5.161:8776/v1/0e492e86f22e4d19bd523f1e7ca64566', u'publicURL': u'http://172.21.6.145:8776/v1/0e492e86f22e4d19bd523f1e7ca64566'}], u'endpoints_links': [], u'type': u'volume', u'name': u'cinder'}] instance_lock_checked = False quota_class = None user_name = admin project_name = admin is_admin = True
(2) is_valid_body方法
該方法檢查客戶端傳入的訊息體是否合法,這個方法位於Controller類的基類wsgi.Controller中。is_valid_body方
法首先檢查訊息體中是否含有server欄位,然後檢查server欄位的內容是否為字典。
Nova中,所有的訊息(包括客戶端傳給Nova API伺服器的訊息,以及伺服器返回給客戶端的訊息)都是以資源名作為
鍵值的{key:value}對。
接下來的一系列方法都是獲取並驗證客戶端傳入的虛擬機器引數。其中,server_dict儲存了虛擬機器引數,包括虛擬機器
名、映象uuid、需要的網路、固定ip、虛擬機器規格等等。
(3) _validate_server_name方法
該方法檢查虛擬機器名的長度是否越界。
(4) _validate_access_ipv4&_validate_access_ipv6方法
該方法驗證傳入的固定ip格式是否合法。
(5) _favor_id_from_req_data方法
該方法對HTTP請求中包含的虛擬機器規格id進行過濾解析。所謂規格id就是url包含的id或者uuid的值,如
http://www.foo.com/bar/123?q=4,該方法則返回123。
(6) get_instance_type_get_by_flavor_id方法
該方法位於nova/nova/compute/instance_types.py中,該方法呼叫了nova/nova/db/api.py下的
instance_type_get_by_flavor_id方法,其功能是根據虛擬機器規格id,從資料庫中查詢對應規格資訊後返回。
(7) 呼叫Nova Compute的API處理虛擬機器建立請求。
__init__方法:self.compute_api = compute.API()
Compute API的create方法會返回一個建立虛擬機器資訊列表。列表中的每個元素都是資料庫Model物件。資料庫
Model物件是Nova與資料庫互動的資料格式,不可序列化。
為了便於顯示以及序列化,self._view_builder.create物件的create方法將Model物件的資料轉換為字典。
(8) Nova中,每個底層的Controller物件的_view_builder物件型別都是由_view_builder_class類成員變數指定。
對於server資源的底層Controller物件,其_view_builder_class類成員變數的值為views_servers.ViewBuilder:
_view_builder_class = views_servers.ViewBuilder.
class ViewBuilder(common.ViewBuilder):
def create(self, request, instance):
"""View that should be returned when an instance is created."""
return {
"server": {
"id": instance["uuid"],
"links": self._get_links(request,
instance["uuid"],
self._collection_name),
},
}
create方法返回的是一個關鍵字為server的鍵值對。返回結果中,包含了虛擬機器的uuid,以及虛擬機器的url連結。
三、總結:
Nova API中底層Controller物件定義的HTTP請求的處理方法的小結。
1、檢查客戶端傳入的引數是否合法有效
2、呼叫nova其他子服務的API處理客戶端的HTTP請求。
3、將Nova其他子服務的API返回結果轉化為視覺化的字典。(反序列化)