利用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一下哦 ^_^
相关文章
相关标签/搜索