多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 服務器 > Openstack liberty Glance上傳鏡像源碼分析

Openstack liberty Glance上傳鏡像源碼分析

來源:程序員人生   發布時間:2016-06-08 12:57:13 閱讀次數:4052次

該文同時發布在[ceph中國社區],署名為Thomas

在Openstack中創建云主機,首先得有鏡像,而Glance模塊提供鏡像服務功能,包括:鏡像的發現、檢索及存儲等,主要包括:glance-api和glance-registery兩個服務,分別負責鏡像的存儲和元數據管理。下面基于源碼,分析下鏡像的上傳進程。

上傳鏡像

先通過glance CLI上傳鏡像,來直觀的了解下鏡像上傳的進程:

# glance --debug image-create --file centos-7.0-x64-20g.qcow2 --disk-format raw --container-format bare --visibility public

通過在命令行中開啟--debug,我們可以發現,上傳鏡像進程中glance CLI會發送以下3個不同的要求:
這里寫圖片描述

這里寫圖片描述

這里寫圖片描述

那這3個要求分別干了甚么事呢? 下面我們來逐一分解。

獲得鏡像屬性定義

通過glance/api/v2/router.py.API中定義的路由映照,我們知道上述的第1個要求由glance/api/v2/schemas.py.Controller.image方法處理,以下:

#路由映照,代碼節選 #完全的函數實現,請參考glance/api/v2/router.py.API.__init__ def __init__(self, mapper): #從/etc/glance/schema-image.json文件加載用戶定義屬性 custom_image_properties = images.load_custom_properties() #創建glance/api/v2/schemas.py.Controller實例 schemas_resource = schemas.create_resource(custom_image_properties) #定義路由映照: #curl -X GET /schemas/image -> shemas_resource.image mapper.connect('/schemas/image', controller=schemas_resource, action='image', conditions={'method': ['GET']}) #glance/api/v2/schemas.py.Controller.image """返回1個鏡像屬性字典,結構以下: [ 'name': image, 'properties':xxx 'additionalProperties':xxx 'definitions':xxx 'required':xxx 'links':xxx ] """字典值請看下面的分析進程 def image(self, req): return self.image_schema.raw()

self.image_schemaglance/api/v2/schemas.py.Controller.__init__方法中初始化:

def __init__(self, custom_image_properties=None): self.image_schema = images.get_schema(custom_image_properties)

它進1步調用glance/api/v2/images.py.ImagesController.get_schema方法:

def get_schema(custom_properties=None): #鏡像的基本屬性(是1個字典):id,name,status等的定義及描寫, #通過glance CLI上傳鏡像成功后,這些字段信息會顯示在shell界面上 properties = get_base_properties() """1個包括3個元素的字典列表,像是名字映照束縛 [ {'rel': 'self', 'href': '{self}'}, {'rel': 'enclosure', 'href': '{file}'}, {'rel': 'describedby', 'href': '{schema}'}, ] """ links = _get_base_links() #根據配置/etc/glance/glance-api.conf決定是生成 #PermissiveSchema(默許)還是Schema,區分是PermissiveSchema #多設置了links參數 if CONF.allow_additional_image_properties: schema = glance.schema.PermissiveSchema('image', properties, links) else: schema = glance.schema.Schema('image', properties) #合并用戶自定義屬性 #屬性合并很簡單:先得到兩個屬性集的交集,然后判斷交集的值是不是沖突 #如果值沖突,則拋異常,否則就合并數據集 if custom_properties: for property_value in custom_properties.values(): property_value['is_base'] = False schema.merge_properties(custom_properties) return schema

最后來看看raw方法,實現很簡單:調用父類的Schema返回鏡像屬性字典,同時更新additionalProperties屬性,然后將屬性字典返回給調用者

#glance/schema.py.PermissiveSchema def raw(self): raw = super(PermissiveSchema, self).raw() raw['additionalProperties'] = {'type': 'string'} return raw #glance/schema.py.Schema def raw(self): raw = { 'name': self.name, 'properties': self.properties, 'additionalProperties': False, } if self.definitions: raw['definitions'] = self.definitions if self.required: raw['required'] = self.required if self.links: raw['links'] = self.links return raw

小結:第1個要求獲得了鏡像所支持的屬性字典定義,下面就該根據這些信息來驗證用戶輸入參數了。

更新數據庫

下面來分析第2個要求的處理進程,根據上述的--debug日志和路由映照,我們知道該要求由glance/api/v2/images.py.ImagesController.create方法處理:

@utils.mutating def create(self, req, image, extra_properties, tags): """函數實現比較簡潔,調用`gateway`的方法分別創建`image_factory` 和`image_repo`,后面的try{ }except代碼塊中,分別調用兩個對象的 `new_image`方法進行1系列的校驗和`add`方法添加數據庫條目,最后返 `image`對象給調用者;`gateway`在`ImagesController.__init__`方 法中初始化,是1個`glance/gateway.py.Gateway`實例,其他對象的 實例化也簡單明了,在這里不再表述。根據我們前述的glance CLI命令, 輸入的參數值以下: req:是1個Request對象,包括該次要求的要求信息 image: 是1個字典,包括該次要求的屬性,以下: { 'container_format': u'bare', 'disk_format': u'raw', 'visibility': u'public' } extra_properties: 擴大屬性字典,這里為空 tags:標簽,這里為空 """ image_factory = self.gateway.get_image_factory(req.context) image_repo = self.gateway.get_repo(req.context) #這里省略了,try{ }except異常處理 #實現用戶認證,策略檢查,參數檢查等,具體請看下面的分析 image = image_factory.new_image(extra_properties=extra_properties, tags=tags, **image) #進1步實現相干的檢查,發送消息通知并記錄數據 image_repo.add(image) return image

接著來看看get_image_factory方法:

def get_image_factory(self, context): """根據下面的代碼實現,可以發現各對象間建立了1個調用鏈條: 返回最外層的對象給調用者,調用時逐級調用內部的方法完成相干的操作, 到達最里層對象后,又順著調用鏈逐級返回。其實,后面的`get_repo`方法 也是采取類似的實現,下面的分析中不再贅述。另外`self.store_api`, `self.store_utils`,`self.db_api`等在`__init__`方法中實例化 進程很直接,這里就不再分析了。 """ image_factory = glance.domain.ImageFactory() store_image_factory = glance.location.ImageFactoryProxy( image_factory, context, self.store_api, self.store_utils) quota_image_factory = glance.quota.ImageFactoryProxy( store_image_factory, context, self.db_api, self.store_utils) policy_image_factory = policy.ImageFactoryProxy( quota_image_factory, context, self.policy) notifier_image_factory = glance.notifier.ImageFactoryProxy( policy_image_factory, context, self.notifier) #用戶可以通過`/etc/glance/glance-api.conf中的 #property_protection_file`選項配置屬性策略,默許為disabled if property_utils.is_property_protection_enabled(): property_rules = property_utils.PropertyRules(self.policy) pif = property_protections.ProtectedImageFactoryProxy( notifier_image_factory, context, property_rules) authorized_image_factory = authorization.ImageFactoryProxy( pif, context) else: authorized_image_factory = authorization.ImageFactoryProxy( notifier_image_factory, context) return authorized_image_factory

根據上面的分析,我畫了下面的類圖:
1

2

可以看到*ImageFactoryProxy類都繼承自glance/domain/proxy.py.ImageFactory,通過類名也能夠猜出它的功能:鏡像工廠,那就是用來創建封裝鏡像對象的;各個子類也分別實現:權限檢查、消息通知、策略檢查、配額檢查等。

另外各個*ImageFactoryProxy類都依賴于*ImageProxy類。而各*ImageProxy類都繼承自glance/domain/proxy.py.Image,該類描寫的是鏡像的屬性信息,包括:name,image_id, status等。各*ImageProxy類是對Image的擴大。

各個類的關系弄清楚下了,下面來看看new_image的實現:

#最外層的image_factory = #glance/api/authorization.py.ImageFactoryProxy, 作為調用入口 image = image_factory.new_image(extra_properties=extra_properties, tags=tags, **image)

為更直觀的展現new_image的調用鏈,請看下面的序列圖:

3

序列圖中省略了各個ImageFactoryProxy.new_image方法中的其他處理進程。

可以看到new_image調用從最左側的
glance/api/authorization.py/ImageFactoryProxy1直到最深處(右數第3)的glance/domain/__init__.py/ImageFactory,它返回1個domain/__init__.py.Image對象,然后開始逐層往回
location.py/ImageFactoryProxyauthorization.py/ImageFactoryProxy)調用
glance/domain/proxy.py/Helper.proxy方法,最后的結果是:返回1個經過各個*ImageProxy層層封裝的Image對象,如所示(從里到外):

`__init__.py/Image` <- `location.py/ImagePorxy` <- ...... <- `authoriaztion.py/ImageProxy`

看到上面Image的封裝進程,有無覺得很像TCP/IP協議棧的封包進程呢!有封包,就1定會有解包,下面1起來看看:

""""add方法就是用來解包和封包的 由上面的類圖2,我們知道:image_repo = authorization.py/ImageRepoProxy, 輸入參數image = authorization.py/ImageProxy """ image_repo.add(image)

看圖說話(類圖見上面的圖2):

4

咋1看,該序列圖和上面的很像吧!這就對了。可以看到add調用從最左側的
glance/api/authorization.py/ImageRepoProxy1直到最深處(右數2)的glance/db/__init__.py/ImageRepo,首先調用unproxy完成解包,然后記錄數據庫條目(這個時候可以在Dashboard上看到狀態為’已排隊’),接著開始逐層往回(location.py/ImageRepoProxyauthorization.py/ImageRepoProxy)調用
glance/domain/proxy.py/Helper.proxy方法,和前述ImageFactoryProxy類1樣,各ImageRepoProxy類也順次完成 :權限檢查、屬性配額檢查、策略檢查和信息通知等,最后也是返回1個經過各個*ImageProxy層層封裝的Image對象,以供后續使用。

小結:經過上面的分析,我們知道上傳鏡像進程中的第2個要求,主要完成權限檢查,配額檢查,策略檢查,發布通知和記錄數據庫等操作。下面來看看鏡像文件的上傳進程。

上傳鏡像文件

根據前述glance CLI的debug日志及路由映照,我們可以很容易找到上傳鏡像文件的入口:

#glance/api/v2/image_data.py/ImageDataController.upload @utils.mutating def upload(self, req, image_id, data, size): """ req:是1個Request對象,包括該次要求的詳細信息 image_id:在第2個要求進程中生成的鏡像id, u'079ed99f-e5f6⑷9b1⑻6b4⑹95b56e26bd9' data: 1個Input對象,用來控制后面的鏡像文件數據塊上傳 size:鏡像大小,由于命令行中沒有指定,這里為None 和前面1樣self.gateway在__init__方法中實例化,指向glance/ gateway.py/Gateway。get_repo方法返回和前述類圖2相同的對象 """ image_repo = self.gateway.get_repo(req.context) image = None #省略try{ }except異常處理 #get方法與前述的add方法類似,首先從數據庫取出image_id指向的條目, #封裝成`domain/__init__.py/Image`對象,然后經過層層封裝返回 #`authorization/ImageProxy`對象 image = image_repo.get(image_id) #更新鏡像狀態為saving - ‘保存中’ image.status = 'saving' #省略try{ }except異常處理 #save方法與上面的get方法1樣,逐層調用`ImageRepoProxy`完成相干的 #檢查,通知,最后更新數據庫條目狀態(這個時候可以在Dashboard上看 #到狀態為'保存中') image_repo.save(image) #和上面的save方法類似的處理方式,逐層調用`ImageProxy`的set_data #,在該進程中會檢查用戶配額,發送通知,最后根據glance-api.conf文件 #中配置存儲后端上傳鏡像文件(通過add方法)到指定地方存儲 image.set_data(data, size) #鏡像上傳成功后(在`location.py/set_data方法中上傳文件成功后, #修改狀態為active),更新數據庫狀態為active(這個時候可以在 #Dashboard上看到狀態為'運行中'),終究的信息是這樣的: """ { 'status': 'active', 'name': None, 'checksum': 'd41d8cd98f00b204e9800998ecf8427e', 'created_at': datetime.datetime(2016, 6, 1, 2, 4, 32), 'disk_format': u'raw', 'locations': [{'url': 'rbd://1ee20ded-caae⑷19d⑼fe3- 5919f129cf55/images/079ed99f-e5f6⑷9b1⑻6b4- 695b56e26bd9/snap', 'status': 'active', 'metadata': {}}], 'properties': {}, 'owner': u'25520b29dce346d38bc4b055c5ffbfcb', 'protected': False, 'min_ram': 0, 'container_format': u'bare', 'min_disk': 0, 'is_public': True, 'virtual_size': None, 'id': u'079ed99f-e5f6⑷9b1⑻6b4⑹95b56e26bd9', 'size': 0} """ image_repo.save(image, from_state='saving')

函數說明請查閱上面的注解,save方法與add方法的處理進程很類似,讀者可以根據前面add的序列圖做進1步分析;下面只給出set_data的序列圖:

5

至此,上傳鏡像的進程就分析完了。希望對大家有用。今天是61,在這里祝大家節日快樂!

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 亚洲精品国产自在久久老牛 | 日本高清免费中文字幕不卡 | 国产精品免费一区二区三区 | 国产美女精品自拍 | 日本aaaa级毛片在线看 | 在线欧美一区 | 欧洲美女高清一级毛片 | 国产v亚洲v天堂无码 | 成人性生免费视频 | 欧美日韩亚洲成人 | 爱爱视频网站免费 | 日本在线 | 中文 | 欧美日本高清动作片www网站 | 色综合天天综合网国产成人 | 国产精品无码久久av | 亚洲五月七月丁香缴情 | 77ee成人| 免费伦理片在线观看 | 精品一区二区三区免费 | 国产高清国内精品福利99久久 | 国产精品爱久久久久久久三级 | 欧美视屏 | 亚洲综合网在线 | 色交视频 | 黄大片日本一级在线a | 图片区另类小说 | 韩国三级做爰中文字幕 | 美女牲交毛片一级视频 | 成 人 免费 网站 | 欧美性受xxxx | 国语精品视频在线观看不卡 | 国产v综合v亚洲欧美大另类 | 久久国产精品久久久 | 国产精品无码久久久久 | 人人爽人人爱 | 国产成人精品久久 | 一级特黄色大片 | 亚洲精品久久久久久久久久ty | 亚洲 欧美 小说 | 性欧美性free | 免费观看黄色网址 |