原文地址: 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
一下哦 ^_^