利用Raid卡工具獲取邏輯盤是否爲SSD

原文地址: http://www.tony-yin.top/2018/...

網上不少獲取一塊盤是否爲SSD的方式都是不靠譜的,不能覆蓋到全部狀況。通常咱們在操做系統上的硬盤都是虛擬出來的邏輯盤,好比/dev/sda這種,它可能對應一塊單獨的物理硬盤,也有可能對應的是幾塊盤組成的raid。咱們有時候想獲取一塊盤的具體信息,好比磁盤類型、插槽號、序列號等等,這時候咱們就得藉助對應的raid卡工具了,最多見的如Megacli,經過邏輯盤找到對應的物理盤,而後讀取信息。html

Raid卡簡介

所謂raid卡,就是爲了更好的統一管理物理硬盤而存在的,在出現單獨的raid卡以前,對硬盤作raid操做,須要cpu完成其中的計算操做,這個會很影響其餘依賴cpu的應用或進程的性能,後來就將raid卡單獨提取出來,而且在其之上存在一個小型cpu供來完成raid相關操做的計算,這其中最多見的raid工具應該非Megacli莫屬了。python

爲何說最多見的呢?由於raid卡工具對應不一樣型號的raid卡是不同,LSI只是一個半導體廠商,負責提供raid芯片,最後還須要集成到服務器廠商的機器上,因此最後的工具仍是由廠商決定和提供,也能夠理解爲特定型號的raid對應各自的工具。git

HBA卡簡介

近來,又出現了一種HBA卡,只從HBA的英文解釋HOST BUS ADAPTER(主機總線適配器)就能看出來,他確定是給主機用的,通常HBA就是給主機插上後,給主機擴展出更多的接口,來鏈接外部的設備。大多數講到HBA卡都是指光纖的HBA卡,給主機提供光纖接口的。也有ISCSIHBA卡,連接ISCSI設備的,從這種功能上說,咱們也能夠把獨立網卡稱爲HBA卡,經過獨立網卡擴展出網口來鏈接外部網絡設備或主機。不過習慣上大部分HBA只是稱光纖卡或者iscsi卡。github

簡而言之,這種HBA卡自己是爲了擴展外部鏈接設備而存在的,可是它具備部分raid功能,與raid卡相比它的優點在於它價格便宜,性價比高;劣勢在於雖然具備raid功能,可是都是基礎的功能,沒有raid卡那麼完善。shell

這篇文章講 raid卡和 HBA卡講的挺好的: HBA卡 和 RAID卡

需求和背景

據我所知,這類工具每每是運維人員用的居多,可是每每開發中也會須要用到。本文經過獲取邏輯盤對應盤的類型展開描述,並藉此講解獲取邏輯盤的一類信息或經過邏輯盤操做對應物理盤。由於這其中的關鍵就是找到邏輯盤和物理盤之間的對應關係。不管是raid卡工具仍是HBA卡工具都是羅列全部硬盤的信息,因此你要從中找到你選擇的邏輯盤所對應的即是重中之重。服務器

邏輯盤對應的物理盤可能爲單獨的硬盤,也多是raid,單獨的能夠直接讀取硬盤類型,raid的話咱們認爲只會將一樣類型的盤作raid,混合的狀況不考慮。網絡

raid卡工具的話,我只對MegacliSas3ircu進行講解,因此閱讀本文前最好有使用以上兩個工具的相關經驗。首先我會根據目前存在的raid卡類型創建一個map關係,而後經過raid卡類型自動獲取對應raid卡工具,每一個raid卡都是一個類,而後裏面的方法都是爲該工具定製化的操做。app

獲取raid卡工具

目前就考慮兩種型號的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

Megaraid工具類

  1. 先經過lsscsi命令獲取邏輯盤是否爲raid
  2. 若是是raid,那麼直接根據lsscsi獲取當前邏輯盤的target id,也就是第三個號,而後經過megacli cfgdsply -aALL獲取全部raid信息,根據邏輯盤的target id對應物理盤中的Target Id找到對應raid,而後只要獲取raid中第一塊物理盤的硬盤類型便可,也就是Media Type,具體參見下方API: get_ld_type
  3. 若是不是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工具類

  1. HBA類用的工具是sas3ircu,首先咱們須要根據命令sas3ircu list獲取全部的controller,而後每次獲取信息都須要遍歷全部controller
  2. 第一步依舊是判斷邏輯盤是否爲raid
  3. 若是是raid,獲取邏輯盤的target id,與之匹配的是sas3ircu中的Initiator at ID字段,找到對應的raid,而後經過獲取其下第一個物理盤的類型,這邊類型字段變成了Drive Type,具體參考下方API: get_ld_type
  4. 若是非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一下哦 ^_^
相關文章
相關標籤/搜索