磁盘模块

文章目录

简介

磁盘模块从功能上来说包含两个部分:磁盘名、磁盘位置、背板等磁盘基本信息获取及磁盘灯设置。

从模块上划分为三部分:

  • digidiskmap.py 磁盘名和磁盘位置对应关系模块。
  • digidiskproduct.py 背板厂商判定模块,包含背板上磁盘位置和 phyid 对应关系,包含背板磁盘灯和磁盘状态对应关系。
  • digidisklight.py 磁盘灯设置模块。

设计实现说明

磁盘名和磁盘位置对应关系模块 - digidiskmap.py

盘位对应关系获取的原理依据背板上 phyid 的位置不变化(固件需要一致,因为厂家更新固件时有可能会改变该对应关系)。

在该原理的前提下,将背板上磁盘位置的顺序也规定下来(从下到上,从左到右,依次增加),这样就能生成磁盘位置和 phyid 的对应关系。

背板插入磁盘后,磁盘名称和 phyid 之间也形成对应,这样通过phyid的衔接,就能找到磁盘名称和磁盘位置的对应关系。

如下表:

Disk Location   PhyID   Disk Name
21 22 23 24   0 1 2 3   sdb sdc sdd sde
17 18 19 20 4 5 6 7 sdf sdg sdh sdi
13 14 15 16 8 9 10 11 sdj sdk sdl sdm
9 10 11 12 12 13 14 15 sdn sdo sdp sdq
5 6 7 8 16 17 18 19 sdr sds sdt sdu
1 2 3 4 20 21 22 23 sdv sdw sdx sdy

磁盘位置和 phyid

磁盘位置和 phyid 对应关系的获取,目前是通过 sg3_utils 工具包里的 sg_ses 命令来实现。

执行如下命令,将指定的 phyid 对应的 led 灯点亮,获取磁盘位置和 phyid 之间的对应。

sg_ses --set=fault --index=phyid sg 设备

  • –set=fault 将 phyid 对应位置的 led 灯设置为 fault 状态(红色常亮状态)
  • –index=phyid 指定要设置的 phyid。一般来说,phyid 的索引从 0 开始,如果背板有 24 盘位,那么背板的 phyid 就是 0~23。
  • sg 设备 背板对应的设备,可以通过多种方式获取,最简单的方式是通过 sg3_utils 工具包里的 sg_map 命令获取,没有磁盘对应的 sg 设备就是背板的 sg 设备。如下例,/dev/sg4 就是背板的 sg 设备。
    [root@Storage ~]# sg_map
    /dev/sg0 /dev/sda
    /dev/sg1 /dev/sdb
    /dev/sg2 /dev/sdc
    /dev/sg3 /dev/sdd
    /dev/sg4

磁盘名称和 phyid

磁盘名称和 phyid 之间的对应关系,是通过目录的遍历来完成(/sys/class/sas_device/),先找到插到背板上所有的磁盘。

[root@Storage ~]# ls -1d /sys/class/sas_device/expander-0:0/device/phy-*/port/end_device-*/target*/*/block/*
/sys/class/sas_device/expander-0:0/device/phy-0:0:13/port/end_device-0:0:0/target0:0:0/0:0:0:0/block/sdb
/sys/class/sas_device/expander-0:0/device/phy-0:0:17/port/end_device-0:0:1/target0:0:1/0:0:1:0/block/sdc
/sys/class/sas_device/expander-0:0/device/phy-0:0:21/port/end_device-0:0:2/target0:0:2/0:0:2:0/block/sdd

依次处理:

  1. 每行记录截取到/port/之前的位置,比如”/sys/class/sas_device/expander-0:0/device/phy-0:0:13/port/end_device-0:0:0/target0:0:0/0:0:0:0/block/sdb”,截取的路径为”/sys/class/sas_device/expander-0:0/device/phy-0:0:13”。
  2. 进入截取目录位置,找到子目录”sas_phy”。
  3. 进入”sas_phy”目录,找到以字符”phy-“开始的子目录,一般和第一步截取后目录名相同,这里就是”phy-0:0:13”。
  4. 进入”phy-0:0:13”,读取该目录下的”phy_identifier”文件,获取到的值即为磁盘对应的 phyid。

则磁盘”sdb”对应的 phyid 文件全路径为”/sys/class/sas_device/expander-0:0/device/phy-0:0:13/sas_phy/phy-0:0:13/phy_identifier”,对应的 phyid 为”13”。

背板厂商判定模块 - digidiskproduct.py

背板厂商判定模块其实是 Phyid 和磁盘位置关系的固化,当某个固件的背板把 Phyid 和磁盘位置关系找出来以后,在固件不发生大的改变的情况下,这种对应关系是稳定的,为了避免重复性工作,需要将这种关系固化下来。

这样就又需要一种关系映射,也就是需要一个标示、关键字,python 里讲就是需要一个 key,因为这种关系是同背板固件相关,所以就想着从背板上获取这个标示,最后选择根据背板的 product_id(/sys/class/sas_expander/expander-X/product_id)来判断。

还有一个状态会体现在这个 key 里,背板上的插槽数量,也就是这个背板是多少盘位的(8、12、16 还是 24)。

注意:这里 key 没有直接使用 product_id 的值,因为可读性太差,根据不同的 product_id,生成一个厂家和盘位的组合,这个组合被用来当做 key。

比如 product_id 为 80H10341807A0,根据适配的过程,可以知道这是一款勤诚的 24 盘位的背板,那么 key 就是 CHENBROPHYIDMAP24CHENBRO 表示勤诚,PHYIDMAP 表示这是通过 phyid 找位置的映射(phyid 是 key,位置是 value),24 表示 24 盘位。

CHENBROPHYIDMAP24 = {
'20' : '21','21' : '22','22' : '23','23' : '24',
'16' : '17','17' : '18','18' : '19','19' : '20',
'12' : '13','13' : '14','14' : '15','15' : '16',
'8' : '9', '9' : '10','10' : '11','11' : '12',
'4' : '5', '5' : '6', '6' : '7', '7' : '8',
'0' : '1', '1' : '2', '2' : '3', '3' : '4'
}

磁盘灯设置模块 - digidisklight.py

磁盘灯设置也是使用 sg3_utils 工具包里的 sg_ses 命令来实现(和获取磁盘位置和 phyid 对应关系方法一样)。

模块在通过 phyid 设置 led 灯的基础上进行了扩展,允许通过磁盘位置和磁盘名称来设置 led 灯(对应关系固化前提下)。

sg_ses 命令功能很强大,查看它的帮助信息,可以看到如下:

[root@Storage ~]# sg_ses --help
Usage: sg_ses [--byte1=B1] [--clear=STR] [--control] [--data=H,H...]
[--descriptor=DN] [--enumerate] [--filter] [--get=STR]
[--help] [--hex] [--index=IIA | --index=TIA,II]
[--inner-hex] [--join] [--list] [--nickname=SEN]
[--nickid=SEID] [--page=PG] [--raw] [--set=STR]
[--status] [--verbose] [--version] DEVICE

我们只使用了其中的 led 灯点亮/熄灭功能。

设置磁盘灯命令如下:

sg_ses --set=STR --index=TIA,II DEVICE

清除磁盘灯命令如下:

sg_ses --clear=STR --index=TIA,II DEVICE

通过控制背板的 led 灯闪烁的频率或是常亮,我们可以实现不同的组合,对每个组合进行定义,就能表达我们想要的内容。(由于每个背板固件对 led 灯控制的支持不尽相同,所以实际效果是有出入的,需要保证的一点是 损坏 状态一定要明确的表现出来,以便于坏盘的更换。)

和 phyid 和磁盘位置关系的固化一样,这里也是通过背板厂家来区分不同背板 led 灯对应不同的状态,目前已支持的状态如下:

  • 鲸鲨背板

    {
    '1' : '', #使用中
    '2' : 'missing', #未使用
    '3' : '', #热备
    '4' : '', #重构
    '-2': 'fault', #损坏
    '-1': 'active' #未激活
    }
  • 迎广背板:

    {
    '1' : '', #使用中
    '2' : 'ok', #未使用
    '3' : 'hotspare', #热备
    '4' : 'active', #重构
    '-2': 'fault', #损坏
    '-1': 'rsvddevice' #未激活
    }
  • 勤诚背板:

    {
    '1' : '', #使用中
    '2' : '', #未使用
    '3' : '', #热备
    '4' : '', #重构
    '-2': 'fault', #损坏
    '-1': '' #未激活
    }

使用方法

磁盘模块使用时主要是调用磁盘名和磁盘位置对应关系模块(digidiskmap.py)和磁盘灯设置模块(digidisklight.py),digidiskproduct.py 基本是常量模块,只有在新的背板适配时才会修改。

磁盘名和磁盘位置对应关系模块 - digidiskmap.py

该模块会获取所有的背板和磁盘信息,从固化的磁盘位置和 phyid 映射中查找,匹配成功会返回磁盘和盘位的对应关系,磁盘和 phyid 的对应关系,背板信息。

作用:

获取当前设备的 磁盘名:磁盘位置 对应关系、磁盘名:phyid 对应关系、背板信息

输入:

jsonformat

参数 类型 释义
jsonformat True|False bool 是否以JSON字符串格式返回
输出:

[disknamemap,disknamephymap,expanders]

参数 类型 释义
disknamemap {磁盘名称:磁盘位置} dict 磁盘和盘位对应关系
disknamephymap {磁盘名称:phyid} dict 磁盘和盘位对应关系
expanders {背板编号:{背板信息}} dict 背板信息
示例:
>>> from digidisk import digidiskmap
>>> digidiskmap.get_diskmap(False)
[
   {'sdd': '0-22', 'sdb': '0-14', 'sdc': '0-18'},
   {'sdd': '21', 'sdb': '13', 'sdc': '17'},
   {'0':
       {
           'id': '0',
           'name': 'expander-0:0',
           'count': '24',
           'product': 'CHENBRO',
           'smpdevice': 'sg4',
           'model': '80H10341807A0',
           'sasaddress': '0x5001c45001d099bf',
           'hard': False
       }
   }
]

磁盘灯设置模块 - digidisklight.py

该模块会根据用户传入的 phyid、磁盘位置、磁盘名称,状态等参数,设置或清除对应位置的 led 灯状态。

传入的状态可以为具体的状态值(string),也可以预定义的状态值对应的数字。

磁盘状态

磁盘状态
数字 对应的状态 释义
1 inuse 使用中
2 unuse 未使用
3 spare 热备
4 rebuild 重构
-1 inactive 未激活
-2 broken 损坏

设置磁盘灯状态

setdisklight(**kwargs)

作用:

设置 指定位置整个背板磁盘灯指定状态

说明:
  1. dpid、dlid和dname中的任意一个参数都对应背板上一个固定位置。使用dpid和dlid时,如果未体现背板信息(如:0-X),就需要通过eid或esg等参数来补充。
  2. 未指定dpid、dlid、dname等定位参数但指定esg、eid等背板参数时,设置整个背板。
输入:

键值对

参数 类型 释义
dpid X-X|X,X为数字 string 磁盘对应的phy_identifier编号。格式为0-0,表示expanderid:phyid,如果格式为0,则需要指定eid或esg。
dlid X-X|X,X为数字 string 磁盘对应的位置编号。格式为0-1,表示expanderid:locateid;如果格式为1,则需要指定eid或esg。
dname sdX。 string 磁盘名称。如果指定esg或eid,在对应背板上搜索磁盘;未指定时需遍历所有背板。
esg /dev/sgX,X为数字 string 背板对应的sg设备
eid X,X为数字 string 背板对应的编号
eproduct INWIN|CHENBRO|ESTOR string 背板厂商。和ecount组合,在只提供dlid的时候获取phy_identifier编号。
ecount 8|12|16|24 string 背板盘位
light 1|2|3|4|-1|-2 inuse|unuse|spare|rebuild|inactive|fault missing|fault|active|locate|hotspare|rsvddevice string 磁盘灯状态。参考 磁盘状态
输出:

数字

参数 类型 释义
retcode 0|-1|-2|-3|-4 int 设置磁盘灯结果
释义:
释义
0 成功
-1 参数不足
-2 错误的磁盘灯
-3 未适配背板灯
-4 未适配背板盘位
示例:
#设置phyid为22的位置状态为'-2'(broken)
>>> from digidisk import digidisklight
>>> digidisklight.setdisklight(**{'dpid':'22','esg':'sg4','light':'-2'})
0
#设置磁盘位置为12的状态为broken
>>> digidisklight.setdisklight(**{'dlid':'0-12','light':'broken'})
0
#设置phyid为22的位置状态为broken
>>> digidisklight.setdisklight(**{'dpid':'0-22','light':'broken'})
0
#设置磁盘sdb状态为broken
>>> digidisklight.setdisklight(**{'dname':'sdb','light':'broken'})
0

清除磁盘灯状态

cleardisklight(**kwargs)

作用:

清除 指定位置 或 整个背板 的 磁盘灯 的 指定状态 或 全部状态

说明:
  1. 指定磁盘灯状态时只清除该状态,不指定磁盘灯状态时清除所有状态。
  2. 未指定dpid、dlid、dname等定位磁盘参数但指定esg、eid等背板参数时,清除整个背板。
  3. 需要注意的是,因为背板固件支持的不同,不是所有磁盘状态都有表现在磁盘灯上,这里只能保证 磁盘损坏 时的磁盘灯状态。
输入:

键值对

参数 类型 释义
dpid X-X|X,X为数字 string 磁盘对应的phy_identifier编号。格式为0-0,表示expanderid:phyid,如果格式为0,则需要指定eid或esg。
dlid X-X|X,X为数字 string 磁盘对应的位置编号。格式为0-1,表示expanderid:locateid;如果格式为1,则需要指定eid或esg。
dname sdX。 string 磁盘名称。如果指定esg或eid,在对应背板上搜索磁盘;未指定时需遍历所有背板。
esg /dev/sgX,X为数字 string 背板对应的sg设备
eid X,X为数字 string 背板对应的编号
eproduct INWIN|CHENBRO|ESTOR string 背板厂商。和ecount组合,在只提供dlid的时候获取phy_identifier编号。
ecount 8|12|16|24 string 背板盘位
light 1|2|3|4|-1|-2 inuse|unuse|spare|rebuild|inactive|fault missing|fault|active|locate|hotspare|rsvddevice string 磁盘灯状态。参考 磁盘状态
输出:

数字

参数 类型 释义
retcode 0|-1|-2|-3|-4 int 清除磁盘灯结果
释义:
释义
0 成功
-1 参数不足
-2 错误的磁盘灯
-3 未适配背板灯
-4 未适配背板盘位
示例:
#清除编号为0的背板上所有位置所有状态
>>> from digidisk import digidisklight
>>> digidisklight.cleardisklight(**{'eid':'0'})
0
#清除编号为0的背板上phyid为22位置的所有状态
>>> digidisklight.cleardisklight(**{'dpid':'0-22'})
0
#phyid不包含背板信息时,需要单独指定eid或esg。
>>> digidisklight.cleardisklight(**{'dpid':'22','eid':'0'})
0
#清除磁盘sdb状态broken
>>> digidisklight.cleardisklight(**{'dname':'sdb','light':'broken'})
0