原文地址: http://www.tony-yin.top/2018/...
網上不少獲取一塊盤是否爲SSD
的方式都是不靠譜的,不能覆蓋到全部狀況。通常咱們在操做系統上的硬盤都是虛擬出來的邏輯盤,好比/dev/sda
這種,它可能對應一塊單獨的物理硬盤,也有可能對應的是幾塊盤組成的raid
。咱們有時候想獲取一塊盤的具體信息,好比磁盤類型、插槽號、序列號等等,這時候咱們就得藉助對應的raid
卡工具了,最多見的如Megacli
,經過邏輯盤找到對應的物理盤,而後讀取信息。html
所謂raid
卡,就是爲了更好的統一管理物理硬盤而存在的,在出現單獨的raid
卡以前,對硬盤作raid
操做,須要cpu
完成其中的計算操做,這個會很影響其餘依賴cpu
的應用或進程的性能,後來就將raid
卡單獨提取出來,而且在其之上存在一個小型cpu
供來完成raid
相關操做的計算,這其中最多見的raid
工具應該非Megacli
莫屬了。python
爲何說最多見的呢?由於raid
卡工具對應不一樣型號的raid
卡是不同,LSI
只是一個半導體廠商,負責提供raid
芯片,最後還須要集成到服務器廠商的機器上,因此最後的工具仍是由廠商決定和提供,也能夠理解爲特定型號的raid
對應各自的工具。git
近來,又出現了一種HBA
卡,只從HBA
的英文解釋HOST BUS ADAPTER
(主機總線適配器)就能看出來,他確定是給主機用的,通常HBA
就是給主機插上後,給主機擴展出更多的接口,來鏈接外部的設備。大多數講到HBA
卡都是指光纖的HBA
卡,給主機提供光纖接口的。也有ISCSI
的HBA
卡,連接ISCSI
設備的,從這種功能上說,咱們也能夠把獨立網卡稱爲HBA
卡,經過獨立網卡擴展出網口來鏈接外部網絡設備或主機。不過習慣上大部分HBA
只是稱光纖卡或者iscsi
卡。github
簡而言之,這種HBA
卡自己是爲了擴展外部鏈接設備而存在的,可是它具備部分raid
功能,與raid
卡相比它的優點在於它價格便宜,性價比高;劣勢在於雖然具備raid
功能,可是都是基礎的功能,沒有raid
卡那麼完善。shell
這篇文章講raid
卡和HBA
卡講的挺好的: HBA卡 和 RAID卡
據我所知,這類工具每每是運維人員用的居多,可是每每開發中也會須要用到。本文經過獲取邏輯盤對應盤的類型展開描述,並藉此講解獲取邏輯盤的一類信息或經過邏輯盤操做對應物理盤。由於這其中的關鍵就是找到邏輯盤和物理盤之間的對應關係。不管是raid
卡工具仍是HBA
卡工具都是羅列全部硬盤的信息,因此你要從中找到你選擇的邏輯盤所對應的即是重中之重。服務器
邏輯盤對應的物理盤可能爲單獨的硬盤,也多是raid
,單獨的能夠直接讀取硬盤類型,raid
的話咱們認爲只會將一樣類型的盤作raid
,混合的狀況不考慮。網絡
raid
卡工具的話,我只對Megacli
和Sas3ircu
進行講解,因此閱讀本文前最好有使用以上兩個工具的相關經驗。首先我會根據目前存在的raid
卡類型創建一個map
關係,而後經過raid
卡類型自動獲取對應raid
卡工具,每一個raid
卡都是一個類,而後裏面的方法都是爲該工具定製化的操做。app
目前就考慮兩種型號的raid
卡,之後有新的再往map
裏面填充就行了。NotSupport
指的是其餘不支持型號的raid
卡和虛擬機。運維
do_shell
是本人封裝的一個在python
中執行shell
命令的方法,你們能夠根據本身的狀況對該方法進行轉換
經過獲取的card mode
,根據map
找到對應的tool
,而後實例化對應的工具類工具
class RaidCardToolFactory(): RaidCardMap = { 'SAS2208': MegaraidTool, 'SAS3008': HBATool, 'NotSupport': NotSupport } def getTool(self): card_model = self.get_raidcard_model() tool = self.RaidCardMap[card_model]() return tool def get_raidcard_model(self): card_model = 'NotSupport' card_info = do_shell("lspci | grep 'LSI Logic'") if card_info == '': return card_model card = card_info.strip().splitlines()[0].split() if 'RAID bus controller' in card_info: card_model = card[10] + card[11] elif 'Attached SCSI controller' in card_info: card_model = card[10] return card_model
lsscsi
命令獲取邏輯盤是否爲raid
;raid
,那麼直接根據lsscsi
獲取當前邏輯盤的target id
,也就是第三個號,而後經過megacli cfgdsply -aALL
獲取全部raid
信息,根據邏輯盤的target id
對應物理盤中的Target Id
找到對應raid
,而後只要獲取raid
中第一塊物理盤的硬盤類型便可,也就是Media Type
,具體參見下方API
: get_ld_type
raid
,那麼直接根據lsscsi
獲取當前邏輯盤的target id
,也就是第三個號,這邊的target id
直接對應megacli
中每一塊單盤中的Device Id
字段,因此根據target id
匹配megacli pdlist aAll
獲取磁盤列表的每一項的Device Id
即可以找到對應的物理盤,具體參見下方API
: get_pd_type
。class MegaraidTool(): def get_disk_type(self, disk_name): scsi_info = do_shell("lsscsi | grep {} -w".format(disk_name)) target_id = scsi_info.split()[0].split(":")[2] serial_nu = scsi_info.split()[3].strip()[2:] if "LSI" in scsi_info: disk_type = self.get_ld_type(target_id, serial_nu) else: disk_type = self.get_pd_type(target_id) return disk_type def get_ld_type(self, target_id, serial_nu): disk_type = '' cmd = MEGACLI + ' cfgdsply -aALL -NoLog|grep -E "Product Name|Target Id|Media Type"' output = do_shell(cmd) adapters = output.split('Product Name') for adapter in adapters: if serial_nu not in adapter: continue lines = adapter.split('\n') for line in lines: if "Target Id: {}".format(target_id) in line: index = lines.index(line) if 'Solid State Device' in lines[index + 1]: disk_type = "SSD" else : disk_type = "HDD" break if disk_type != '': break return disk_type def get_pd_type(self, target_id): disk_type = '' cmd = MEGACLI + ' pdlist aAll | grep -E "Device Id|Media Type"' output = do_shell(cmd, force=True) lines = output.split('\n') if 'Device Id: {}'.format(target_id) not in lines: return '' index = lines.index('Device Id: {}'.format(target_id)) if 'Solid State Device' in lines[index + 1]: disk_type = "SSD" else : disk_type = "HDD" return disk_type
HBA
類用的工具是sas3ircu
,首先咱們須要根據命令sas3ircu list
獲取全部的controller
,而後每次獲取信息都須要遍歷全部controller
;raid
;raid
,獲取邏輯盤的target id
,與之匹配的是sas3ircu
中的Initiator at ID
字段,找到對應的raid
,而後經過獲取其下第一個物理盤的類型,這邊類型字段變成了Drive Type
,具體參考下方API
: get_ld_type
;raid
,我匹配的是sas3ircu
中的Sas Address
字段,那麼邏輯盤的Sas Address
如何獲取呢?這邊我用的方式是經過udev
獲取邏輯盤的symlink
,這裏面有不少address
,而咱們須要的是by-path
,我這邊就簡單作了,看sas3ircu
每一個盤的Sas Address
是否被udev
獲取的symlink
包含,若是包含了,那麼也就匹配到了,而後直接獲取Drive Type
字段就能夠獲得磁盤類型類;具體參考下方API
: get_pd_type
class HBATool(): def get_disk_type(self, disk_name): scsi_info = do_shell("lsscsi | grep {} -w".format(disk_name)) if "LSI" in scsi_info: target_id = scsi_info.split()[0].split(":")[2] disk_type = self.get_ld_type(target_id) else: sas_address = do_cmd('udevadm info --query=symlink --name={}'.format(disk_name)) disk_type = self.get_pd_type(sas_address) return disk_type def get_ld_type(self, target_id): disk_type = '' controllers = self.get_controllers() for controller in controllers: cmd = 'sas3ircu {} display|grep -E "Initiator at ID|Drive Type"'.format(controller) output = do_shell(cmd) if 'Initiator at ID #{}'.format(target_id) in output: lines = output.splitlines() index = lines.index('Initiator at ID #{}'.format(target_id)) if 'HDD' in lines[index + 1]: disk_type = 'HDD' else: disk_type = 'SSD' break return disk_type def get_pd_type(self, sas_address): disk_type = '' controllers = self.get_controllers() for controller in controllers: cmd = 'sas3ircu {} display|grep -E "SAS Address|Drive Type"'.format(controller) output = do_shell(cmd) lines = output.splitlines() for i in xrange(0, len(lines), 2): address = lines[i].split()[-1].replace('-', '') if address in sas_address: if 'HDD' in lines[i + 1]: disk_type = 'HDD' else: disk_type = 'SSD' break if disk_type != '': break return disk_type def get_controllers(self): cmd = 'sas3ircu list | awk \'{print $1}\'' list = do_shell(cmd).splitlines() index = list.index('Index') + 2 controllers = [] for i in range(index, len(list) - 1): controllers.append(list[i]) return controllers
from mcs3.raidcardutils import RaidCardToolFactory tool = RaidCardToolFactory().getTool() disk_type = tool.get_disk_type(disk_name)
其實這其中的關鍵就是先找到每一塊物理盤的惟一標識,而後咱們根據工具獲取列表中的惟一標識字段,獲取邏輯盤對應的信息,就好比上面的Device Id
,對應的是邏輯盤的target id
。
完整代碼地址: https://github.com/tony-yin/R...
若是有所幫助的話,幫忙star
一下哦 ^_^