Cinder-client 開發(fā)分析

一、簡介

openstack的各個模塊中橡伞,都有相應的客戶端模塊實現(xiàn),其作用是為用戶訪問具體模塊提供了接口晋被,并且也作為模塊之間相互訪問的途徑兑徘。Cinder也一樣,有著自己的cinder-client羡洛。


image.png

二挂脑、argparse

argparse是python用于解析命令行參數(shù)和選項的標準模塊,作為optparse的一個替代被添加到Python2.7欲侮。Cinder-client主要就是調用了argparse這個工具包崭闲,在此先介紹下它的使用。
1.使用步驟
① import argparse
② parser = argparse.ArgumentParser()
③ parser.add_argument()
④ parser.parse_args()

解釋:首先導入該模塊威蕉;然后創(chuàng)建一個解析對象刁俭;然后向該對象中添加你要關注的命令行參數(shù)和選項,每一個add_argument方法對應一個你要關注的參數(shù)或選項韧涨;最后調用parse_args()方法進行解析牍戚;解析成功之后即可使用,下面簡單說明一下步驟2和3氓奈。

方法 ArgumentParser(prog=None, usage=None,description=None, epilog=None, parents=[],formatter_class=argparse.HelpFormatter, prefix_chars='-',fromfile_prefix_chars=None, argument_default=None,conflict_handler='error', add_help=True)
這些參數(shù)都有默認值翘魄,當調用parser.print_help()或者運行程序時由于參數(shù)不正確(此時python解釋器其實也是調用了pring_help()方法)時,會打印這些描述信息舀奶,一般只需要傳遞description參數(shù)暑竟,如上。

方法add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
其中:
name or flags:命令行參數(shù)名或者選項育勺,如上面的address或者-p,--port.其中命令行參數(shù)如果沒給定但荤,且沒有設置defualt,則出錯涧至。但是如果是選項的話腹躁,則設置為None。
nargs:命令行參數(shù)的個數(shù)南蓬,一般使用通配符表示纺非,其中,'?'表示只用一個赘方,'*'表示0到多個烧颖,'+'表示至少一個。
default:默認值窄陡。
type:參數(shù)的類型炕淮,默認是字符串string類型,還有float跳夭、int等類型涂圆。
help:和ArgumentParser方法中的參數(shù)作用相似们镜,出現(xiàn)的場合也一致。
dest:如果提供dest润歉,例如dest="a"模狭,那么可以通過args.a訪問該參數(shù)
action:參數(shù)出發(fā)的動作
store:保存參數(shù),默認
store_const:保存一個被定義為參數(shù)規(guī)格一部分的值(常量)踩衩,而不是一個來自參數(shù)解析而來的值胞皱。
store_ture/store_false:保存相應的布爾值
append:將值保存在一個列表中。
append_const:將一個定義在參數(shù)規(guī)格中的值(常量)保存在一個列表中九妈。
`count:參數(shù)出現(xiàn)的次數(shù)

parser.add_argument("-v", "--verbosity", action="count", default=0, help="increase output verbosity")
version:打印程序版本信息
choice:允許的參數(shù)值

2.范例

import argparse


def parse_args():
    description = '''This is a description of this command.
    bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla'''

    parser = argparse.ArgumentParser(description=description)

    help = 'The addresses to connect.'
    parser.add_argument('addresses', nargs='*', help=help)

    help = 'The port to listen on. Default to a random available port.'
    parser.add_argument('-p', '--port', type=int, help=help)

    help = 'The interface to listen on. Default is localhost.'
    parser.add_argument('--iface', help=help, default='localhost')

    help = 'The number of seconds between sending bytes.'
    parser.add_argument('--delay', type=float, help=help, default=.7)

    help = 'The number of bytes to send at a time.'
    parser.add_argument('--bytes', type=int, help=help, default=10)

    args = parser.parse_args()
    return args


if __name__ == '__main__':
    args = parse_args()

    for address in args.addresses:
        print 'The address is : %s .' % address
        print 'The port is : %d.' % args.port
        print 'The interface is : %s.' % args.iface
        print 'The number of seconds between sending bytes : %f' % args.delay
        print 'The number of bytes to send at a time : %d.' % args.bytes

執(zhí)行結果:

D:\ruijie doc\vmware\testing>python test_parse.py  --help
usage: test_parse.py [-h] [-p PORT] [--iface IFACE] [--delay DELAY]
                     [--bytes BYTES]
                     [addresses [addresses ...]]

This is a description of this command. bla bla bla bla bla bla bla bla bla bla
bla bla bla bla bla

positional arguments:
  addresses             The addresses to connect.

optional arguments:
  -h, --help            show this help message and exit
  -p PORT, --port PORT  The port to listen on. Default to a random available
                        port.
  --iface IFACE         The interface to listen on. Default is localhost.
  --delay DELAY         The number of seconds between sending bytes.
  --bytes BYTES         The number of bytes to send at a time.
D:\ruijie doc\vmware\testing>python test_parse.py --port 10000 --delay 1.2 127.0.0.1 172.16.55.67
The address is : 127.0.0.1 .
The port is : 10000.
The interface is : localhost.
The number of seconds between sending bytes : 1.200000
The number of bytes to send at a time : 10.
The address is : 172.16.55.67 .
The port is : 10000.
The interface is : localhost.
The number of seconds between sending bytes : 1.200000
The number of bytes to send at a time : 10.

三、Cinder-client 指令代碼分析

以cinder storage-show指令作為范例分析:

[root@node1 site-packages]# cinder help storage-show
usage: cinder storage-show [--detail] <id>

Show volume storage details.

Positional arguments:
  <id>      Name or ID of the storage.

Optional arguments:
  --detail  Show detailed information about storage.

輸出結果:


image.png

1.入口

\cinderclient\v2\shell.py定義了指令的入口函數(shù)

@utils.arg('id',
           metavar='<id>',
           help='Name or ID of the storage.')
@utils.arg('--detail',
           action='store_true',
           help='Show detailed information about storage.')
def do_storage_show(cs, args):
    """Show volume storage details."""
    detailed = strutils.bool_from_string(args.detail)
    storage = cs.storages.get(args.id, detailed)
    info = dict()
info.update(storage._info)
# 打印字典雾鬼,并對'pool_info', 'metadatas'的值字典轉換字符串
    utils.print_dict(info, formatters=['pool_info', 'metadatas'])

Cinder storage-show對應shell.py里的do_storage_show函數(shù)萌朱,同樣的,其他指令的定義函數(shù)名字格式都是:以do_作為前綴策菜,分隔符-對應分隔符_晶疼。
do_storage_show函數(shù)的__doc__會成為指令的解釋說明。
@utils.arg定義了指令的參數(shù)又憨,參數(shù)格式可參考parser.add_argument翠霍。

cs.storages指向cinderclient.v2.client.Client里定義的self.storages = storages.StoragesManager(self)

Shell.py里有兩種輸出結果的方式:

print_list

用于輸出對象列表,輸出格式如下蠢莺,類似于常見的表格寒匙,對象的屬性名作為標題。


image.png
def print_list(objs, fields, exclude_unavailable=False, formatters=None, sortby_index=0)

參數(shù):

參數(shù) 說明
objs 要打印的對象列表
fields 規(guī)定每個對象要打印的字段
exclude_unavailable 決定是否把fields里無效的字段刪除躏将,fields里的字段在object里不存在即為無效字段锄弱。
formatters 要格式化的字段
sortby_index 輸出結果排序字段

print_dict

用于輸出字典類型的結果,會把對formatters字段做字典轉字符串的格式化祸憋。

def print_dict(d, property="Property", formatters=None): 

2.manager

一般会宪,我們將某種資源的操作集合定義在一個文件里,比如storage蚯窥,我們定義在\cinderclient\v2\storages.py掸鹅。文件里包含兩個class,一個是Storages拦赠,是storage這個資源的實體類巍沙;另一個是StoragesManager,是storage這個資源的操作管理類矛紫,可定義增刪改查等方法赎瞎。

image.png

比如storage = cs.storages.get(args.id, detailed),調用的是

cinderclient.v2.storages.StoragesManager#get:
def get(self, storage_id, detailed=False):
    storage = self._get("/storages/{storage_id}?detail={detailed}".
                        format(storage_id=storage_id, detailed=detailed),
                        'storage')
    return storage

這里調用了cinderclient.base.Manager#_get(self, url, response_key=None)方法颊咬,這個方法兩個參數(shù)务甥,一個是rest url地址牡辽,一個是url返回值key。比如url="/storages/{storage_id}?detail={detailed}"的返回值是{u'storage': {...}}敞临,那么response_key即’storage’态辛,_get方法會把返回值’storage’的volue轉換成資源類Storages對象。

cinderclient.base.Manager是所有資源manager的基類挺尿,除了_get奏黑,它還定義了其它幾種常用基礎操作函數(shù):
def _create(self, url, body, response_key, return_raw=False, **kwargs): 用于創(chuàng)建資源
def _delete(self, url): 用于刪除資源
def _update(self, url, body, response_key=None, **kwargs): 用于更新資源
def _list(self, url, response_key, obj_class=None, body=None, limit=None, items=None): 用于查詢資源列表
def _get(self, url, response_key=None): 用于查詢單個資源

范例:

    def list(self, storage_name=None, device_id=None,
             volume_backend_name=None, usage=None, nova_aggregate_id=None,
             status=None, detailed=False, project_ids=None):
        url = '/storages'
        filters = {}
        if storage_name:
            filters['storage_name'] = storage_name
        if device_id:
            filters['device_id'] = device_id
        if volume_backend_name:
            filters['volume_backend_name'] = volume_backend_name
        if usage:
            filters['usage'] = usage
        if nova_aggregate_id:
            filters['nova_aggregate_id'] = nova_aggregate_id
        if status:
            filters['status'] = status
        if detailed is True:
            filters['detailed'] = 'true'

        filters = utils.unicode_key_value_to_string(filters)
        if filters:
            params = sorted(filters.items(), key=lambda x: x[0])
            query_string = "?%s" % parse.urlencode(params)
            url = url + query_string

        storages = self._list(url, 'storages')
        return storages

    def get(self, storage_id, detailed=False):
        storage = self._get("/storages/{storage_id}?detail={detailed}".
                            format(storage_id=storage_id, detailed=detailed),
                            'storage')
        return storage

    def create(self, storage_name, device_id, metadata, usage, nova_aggregate_id):
        body = {
            "storage": {
                "storage_name": storage_name,
                "device_id": device_id,
                "metadatas": metadata,
                "usage": usage,
                "nova_aggregate_id": nova_aggregate_id
            }
        }
        return self._create('/storages', body, 'storage')

    def update(self, storage_id, storage_name=None, device_id=None, metadatas=None):
        body = {
            "storage": {
            }
        }
        if storage_name is not None:
            body['storage']['storage_name'] = storage_name
        if device_id is not None:
            body['storage']['device_id'] = device_id
        if metadatas is not None:
            body['storage']['metadatas'] = metadatas
        return self._update('/storages/%s' % storage_id, body, 'storage')

    def delete(self, storage_id):
        return self._delete("/storages/%s" % storage_id)

定義完資源的manager類,要記得在client.py的Client類里引入编矾,提供給shell.py和其他openstack組件調用熟史。比如:


image.png

四、Openstack其他組件調用cinder-client

Openstack組件之間調用窄俏,一般都是通過組件的client提供的接口蹂匹。比如nova的\nova\nova\volume\cinder.py定義了cinder-api的集合類nova.volume.cinder.API。要查詢cinder的volume列表凹蜈,可調用nova.volume.cinder.API#get_all

    @translate_cinder_exception
    def get_all(self, context, search_opts=None):
        search_opts = search_opts or {}
        items = cinderclient(context).volumes.list(detailed=True,
                                                   search_opts=search_opts)
        rval = []
        for item in items:
            rval.append(_untranslate_volume_summary_view(context, item))

        return rval

可以看到荔仁,get_all函數(shù)里調用cinderclient(context).volumes.list(detailed=True, search_opts=search_opts)敢艰,即調用了cinderclient的cinderclient.v2.volumes.VolumeManager#list方法。

當然我們cinder調用nova的方法,也是這樣亥啦。Cinder有\(zhòng)cinder\compute\nova.py醋粟,可通過cinder.compute.nova.API里的方法調用novaclient接口凤价。比如創(chuàng)建卷快照:

    def create_volume_snapshot(self, context, volume_id, create_info):
        nova = novaclient(context, privileged_user=True)
        # pylint: disable=E1101
        nova.assisted_volume_snapshots.create(
            volume_id,
            create_info=create_info)

nova.assisted_volume_snapshots.create即調用novaclient.v2.assisted_volume_snapshots.AssistedSnapshotManager#create褥蚯。

五、cinderclient-ext

安裝:pip install python-brick-cinderclient-ext

cinderclient-ext提供了cinder-client的拓展指令传泊。
入口定義在\brick_cinderclient_ext\__init__.py鼠渺,增加了五個指令:
do_get_connector
do_local_attach
do_local_detach
do_get_volume_paths
do_get_all_volume_paths

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市眷细,隨后出現(xiàn)的幾起案子拦盹,更是在濱河造成了極大的恐慌,老刑警劉巖溪椎,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件普舆,死亡現(xiàn)場離奇詭異,居然都是意外死亡校读,警方通過查閱死者的電腦和手機沼侣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來歉秫,“玉大人蛾洛,你說我怎么就攤上這事。” “怎么了轧膘?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵钞螟,是天一觀的道長。 經常有香客問我谎碍,道長鳞滨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任蟆淀,我火速辦了婚禮拯啦,結果婚禮上,老公的妹妹穿的比我還像新娘熔任。我一直安慰自己褒链,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布疑苔。 她就那樣靜靜地躺著碱蒙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夯巷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天哀墓,我揣著相機與錄音趁餐,去河邊找鬼。 笑死篮绰,一個胖子當著我的面吹牛后雷,可吹牛的內容都是我干的。 我是一名探鬼主播吠各,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼臀突,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贾漏?” 一聲冷哼從身側響起候学,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎纵散,沒想到半個月后梳码,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡伍掀,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年掰茶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜜笤。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡濒蒋,死狀恐怖,靈堂內的尸體忽然破棺而出把兔,到底是詐尸還是另有隱情沪伙,我是刑警寧澤瓮顽,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站焰坪,受9級特大地震影響趣倾,放射性物質發(fā)生泄漏。R本人自食惡果不足惜某饰,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一儒恋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧黔漂,春花似錦诫尽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至减途,卻和暖如春酣藻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鳍置。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工辽剧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人税产。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓怕轿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辟拷。 傳聞我的和親對象是個殘疾皇子撞羽,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內容

  • 第一章 OpenStack基礎 OpenStack管理的資源及提供的服務OpenStack做為一個操作系統(tǒng),...
    sgt_tiger閱讀 12,943評論 4 72
  • ?王越:VMware存儲API整理衫冻,比如核心的存儲池與卷兩者的CURD诀紊。可以參考:VMware in OpenSt...
    笨手笨腳越閱讀 5,671評論 0 2
  • cinder RPC 分析 [TOC] 我們都知道在Cinder內部隅俘,各組件之間通訊是通過RPC api渡紫,比如c...
    笨手笨腳越閱讀 1,819評論 0 3
  • 佛山的傳說 作者:王智恩 編輯配圖:黛馨 位于豫陜交界處的佛山,因秋季漫山都是紅燦燦考赛、透亮亮惕澎、如火一樣燃燒的楓葉而...
    添情閱讀 1,069評論 0 1
  • 應該是第三天,亦或是第三次不明方位與時間的夜色颜骤,已悄然降落唧喉。慘淡的灰黃顏色像一針慢性毒液緩緩地滲染天空,同時夾雜著...
    甲申紀事dcl閱讀 1,640評論 0 3