@tony-yin
2018-01-26T23:46:33.000000Z
字数 5554
阅读 992
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 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/RaidCardTool/
如果有所帮助的话,帮忙star
一下哦 ^_^