@tony-yin
2018-01-26T15:46:33.000000Z
字数 5554
阅读 1337
Ceph Raid卡
网上很多获取一块盘是否为SSD的方式都是不靠谱的,不能覆盖到所有情况。一般我们在操作系统上的硬盘都是虚拟出来的逻辑盘,比如/dev/sda这种,它可能对应一块单独的物理硬盘,也有可能对应的是几块盘组成的raid。我们有时候想获取一块盘的具体信息,比如磁盘类型、插槽号、序列号等等,这时候我们就得借助对应的raid卡工具了,最常见的如Megacli,通过逻辑盘找到对应的物理盘,然后读取信息。
所谓raid卡,就是为了更好的统一管理物理硬盘而存在的,在出现单独的raid卡之前,对硬盘做raid操作,需要cpu完成其中的计算操作,这个会很影响其他依赖cpu的应用或进程的性能,后来就将raid卡单独提取出来,并且在其之上存在一个小型cpu供来完成raid相关操作的计算,这其中最常见的raid工具应该非Megacli莫属了。
为什么说最常见的呢?因为raid卡工具对应不同型号的raid卡是不一样,LSI只是一个半导体厂商,负责提供raid芯片,最后还需要集成到服务器厂商的机器上,所以最后的工具还是由厂商决定和提供,也可以理解为特定型号的raid对应各自的工具。
近来,又出现了一种HBA卡,只从HBA的英文解释HOST BUS ADAPTER(主机总线适配器)就能看出来,他肯定是给主机用的,一般HBA就是给主机插上后,给主机扩展出更多的接口,来连接外部的设备。大多数讲到HBA卡都是指光纤的HBA卡,给主机提供光纤接口的。也有ISCSI的HBA卡,链接ISCSI设备的,从这种功能上说,我们也可以把独立网卡称为HBA卡,通过独立网卡扩展出网口来连接外部网络设备或主机。不过习惯上大部分HBA只是称光纤卡或者iscsi卡。
简而言之,这种HBA卡本身是为了扩展外部连接设备而存在的,但是它具有部分raid功能,与raid卡相比它的优势在于它价格便宜,性价比高;劣势在于虽然具有raid功能,但是都是基础的功能,没有raid卡那么完善。
这篇文章讲
raid卡和HBA卡讲的挺好的:HBA卡 和 RAID卡
据我所知,这类工具往往是运维人员用的居多,但是往往开发中也会需要用到。本文通过获取逻辑盘对应盘的类型展开描述,并借此讲解获取逻辑盘的一类信息或通过逻辑盘操作对应物理盘。因为这其中的关键就是找到逻辑盘和物理盘之间的对应关系。无论是raid卡工具还是HBA卡工具都是罗列所有硬盘的信息,所以你要从中找到你选择的逻辑盘所对应的便是重中之重。
逻辑盘对应的物理盘可能为单独的硬盘,也可能是raid,单独的可以直接读取硬盘类型,raid的话我们认为只会将同样类型的盘做raid,混合的情况不考虑。
raid卡工具的话,我只对Megacli和Sas3ircu进行讲解,所以阅读本文前最好有使用以上两个工具的相关经验。首先我会根据目前存在的raid卡类型建立一个map关系,然后通过raid卡类型自动获取对应raid卡工具,每个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 tooldef get_raidcard_model(self):card_model = 'NotSupport'card_info = do_shell("lspci | grep 'LSI Logic'")if card_info == '':return card_modelcard = 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_typeraid,那么直接根据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_typedef 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:continuelines = 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"breakif disk_type != '':breakreturn disk_typedef 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_typedef 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'breakreturn disk_typedef 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'breakif disk_type != '':breakreturn disk_typedef get_controllers(self):cmd = 'sas3ircu list | awk \'{print $1}\''list = do_shell(cmd).splitlines()index = list.index('Index') + 2controllers = []for i in range(index, len(list) - 1):controllers.append(list[i])return controllers
from mcs3.raidcardutils import RaidCardToolFactorytool = RaidCardToolFactory().getTool()disk_type = tool.get_disk_type(disk_name)
其实这其中的关键就是先找到每一块物理盘的唯一标识,然后我们根据工具获取列表中的唯一标识字段,获取逻辑盘对应的信息,就比如上面的Device Id,对应的是逻辑盘的target id。
完整代码地址:https://github.com/tony-yin/RaidCardTool/
如果有所帮助的话,帮忙star一下哦 ^_^