Python常用脚本

获取磁盘及raid配置

用法如下:

# python check_disk.py -c
/a0/v0 RAID1 1.090 TB Optimal  /dev/sda /
/a0/c8/d0 /e8/s0 1.090 TB Online (SAS)HDD /D0/S0/R0
/a0/c8/d1 /e8/s1 1.090 TB Online (SAS)HDD /D0/S0/R1

更多详细的用法可以-h查看提示
#  python check_disk.py -h
usage: check_disk.py [-h] [-i | -I | -c | -o [/an/cn/dn] | -f [/an/cn/dn] | -r
                     | -d | -delvd [/an/vn]]

optional arguments:
  -h, --help            show this help message and exit
  -i, --inspect         默认选项, 输出==check_disk故障信息
  -I, --inspecttype     输出故障信息
  -c, --checkdisk       输出所有的pd和vd信息
  -o [/an/cn/dn], --onblink [/an/cn/dn]
                        进行亮灯,
                        当不指定参数时只进行故障盘亮灯,
                        指定参数时进行指定的盘亮灯.
  -f [/an/cn/dn], --offblink [/an/cn/dn]
                        进行灭灯,
                        当不指定参数时只灭自动亮的灯,
                        指定参数时进行指定盘灭灯.
  -r, --recordpderr     记录报错盘信息
  -d, --diskdetail      格式化输出磁盘详细信息
  -delvd [/an/vn]       删除指定vd

完整代码如下:

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

from __future__ import print_function
import os
import re
import json
import sys
import tempfile
import time
import datetime
import subprocess
import copy
import traceback

def exit(num=0):
    sys.exit(num)
statelist = ["Online", "JBOD", "configured(good)", "configured(good), Spun dow", "Unconfigured(good)",
             "Rebuild", "Ready", "Okay", "Optimal", "Online (JBOD)", "OK"]
proc_dir = "/tmp/diskerr"
config = {
    # 保存控制器相关信息
    "controllerjs": proc_dir + "/Controller.js",
    # 保存vd pd 相关信息
    "diskinfofilejs": proc_dir + "/diskinfo.js",
    # 保存pd详细信息
    "pdinfofilejs": proc_dir + "/pdinfo.js",
    # 每天保存一份pd 报错信息
    "pderrfile": proc_dir + "/pderr",
    # 记录换盘是故障盘数据
    "replacefile": proc_dir + "/replace",
    # 记录换盘后挂载盘数据
    "replaceagofile": proc_dir + "/replace_ago"
}


def humanSort(list):
    # slist= sorted(list)
    def tryint(s):                       # 将元素中的数字转换为int后再排序
        try:
            return int(s)
        except ValueError:
            return s

    def str2int(v_str):                # 将元素中的字符串和数字分割开
        return [tryint(sub_str) for sub_str in re.split('([0-9]+)', v_str)]

    def sort_humanly(v_list):    # 以分割后的list为单位进行排序
        return sorted(v_list, key=str2int)
    return sort_humanly(sorted(list))

# 转换时间格式到字符串(天) 年月日
def human_date(date=None):
    if not date:
        assert isinstance(date, datetime)
    else:
        date = datetime.datetime.today()
    return date.strftime('%Y%m%d')


# 将字符串转换为时间
def parse_time(value):
    if isinstance(value, str):
        if len(value) == 8:
            return datetime.datetime.strptime(value, '%Y%m%d')
        if len(value) == 10:
            return datetime.datetime.strptime(value, '%Y-%m-%d')
        elif len(value) == 19:
            return datetime.datetime.strptime(value, '%Y-%m-%d %H:%M:%S')
    raise TypeError('Expect a datetime.datetime value')


class humanJson():
    @classmethod
    def load(self, file_handle):
        return self._byteify(
            json.load(file_handle, object_hook=self._byteify),
            ignore_dicts=True
        )

    @classmethod
    def loads(self, json_text):
        return self._byteify(
            json.loads(json_text, object_hook=self._byteify),
            ignore_dicts=True
        )

    @classmethod
    def _byteify(self, data, ignore_dicts=False):
        if sys.version[0] == "3":
            return data
        # if this is a unicode string, return its string representation
        if isinstance(data, unicode):
            return data.encode('utf-8')
        # if this is a list of values, return list of byteified values
        if isinstance(data, list):
            return [self._byteify(item, ignore_dicts=True) for item in data]
        # if this is a dictionary, return dictionary of byteified keys and values
        # but only if we haven’t already byteified it
        if isinstance(data, dict) and not ignore_dicts:
            return {
                self._byteify(key, ignore_dicts=True): self._byteify(value, ignore_dicts=True)
                for key, value in data.iteritems()
            }

        # if it’s anything else, return it in its original form
        return data


class RaidError(Exception):
    def __init__(self, msg, stat):
        super(RaidError, self).__init__(msg, stat)
        self.msg = msg
        self.stat = stat

    def __str__(self):
        return "RaidError: %s\nError Code: %s" % (self.msg, self.stat)


class OsCmd():
    def __init__(self, cmd, timeout=20):
        # 创建临时文件
        self.cmd = cmd
        self.timeout = timeout
        self.f = tempfile.SpooledTemporaryFile(max_size=10 * 1000)
        fileno = self.f.fileno()
        self.proc = subprocess.Popen(
            cmd, shell=True, stdout=fileno, stderr=fileno)

    def data(self):
        try:
            start_time = time.time()
            while self.proc.poll() is None:
                time.sleep(0.1)
                now_time = time.time()
                if (now_time - start_time) > self.timeout:
                    self.proc.terminate()
                    raise RaidError(
                        "{} command timeout".format(self.cmd), "124")
                    break
            self.f.seek(0)
            lines = self.f.read().strip()
            if sys.version_info[0] >= 3:
                d = lines.decode('utf-8')
            else:
                d = lines
            return d
        except Exception:
            self.proc.terminate()
            raise RaidError("{} command ERR".format(self.cmd), "125")
        finally:
            if self.f:
                self.f.close()


def install_cmd(raid_cmd=""):
    # 进行安装命令
    if raid_cmd != '':
        # res =  OsCmd("sudo lsb_release -a 2>&1")
        res = OsCmd("sudo cat /etc/*-release 2>&1").data()
        if 'Debian' in res:
            raidCmdRes = OsCmd("sudo dpkg -s %s 2>&1" % (raid_cmd)).data()
            if 'install ok installed' not in raidCmdRes:
                OsCmd("sudo apt-get -y --allow-unauthenticated install %s 2>&1" %
                      (raid_cmd)).data()

            smartmontoolsRes = OsCmd("sudo dpkg -s smartmontools 2>&1").data()
            if 'install ok installed' not in smartmontoolsRes:
                OsCmd(
                    "sudo apt-get install smartmontools -y --allow-unauthenticated  2>&1").data()
        elif 'CentOS' in res or 'Red Hat' in res or 'Kylin' in res:
            # elif 'CentOS' in res:
            if raid_cmd == 'megacli':
                raid_cmd = 'MegaCli'

            raidCmdRes = os.popen(
                "sudo rpm -qa %s  2>&1" % (raid_cmd)).read()
            raidCmdRes2 = os.popen(
                "whereis %s|awk -F ':' '{print $NF}' 2>&1" % (raid_cmd)).read()
            if raid_cmd not in raidCmdRes and raid_cmd not in raidCmdRes2:
                if 'Red Hat' in res and raid_cmd == 'MegaCli':
                    print("s--")
                    OsCmd(
                        "sudo yum -y install MegaCli.i386 --enablerepo=netease-self").data()
                    OsCmd(
                        "sudo ln -s /opt/MegaRAID/MegaCli/MegaCli64 /usr/sbin/megacli 2>/dev/null;exit 0").data()
                else:
                    OsCmd("sudo yum -y install %s 2>&1" % (raid_cmd)).data()
            elif 'MegaCli-8.00.46-1.i386' in raidCmdRes or  'MegaCli-8.07.14-1.noarch' in raidCmdRes:
                if not os.path.exists("/usr/sbin/megacli"):
                    OsCmd(
                        "sudo ln -s /opt/MegaRAID/MegaCli/MegaCli64 /usr/sbin/megacli").data()

            smartmontoolsRes = OsCmd("sudo rpm -qa smartmontools 2>&1").data()
            if 'smartmontools' not in smartmontoolsRes:
                OsCmd("sudo yum install smartmontools -y").data()
        else:
            raise RaidError("Please confirm the system version", "127")


class CmdLsblk():
    @classmethod
    def out(self):
        self.pvs = self.islvm()
        util_linux_verlion = OsCmd("sudo fdisk -v|awk '{print $NF}'").data()
        util_linux_verlionList = util_linux_verlion.split(".")
        if int(util_linux_verlionList[0]) >= 2 and int(util_linux_verlionList[1]) >= 27:
            blockList = self.lsblk2_27()
        else:
            blockList = self.lsblk()
        return blockList

    @classmethod
    def islvm(self):
        try:
            disk_lvm = OsCmd(
                "sudo pvs 2> /dev/null|awk '{print $1}'|grep -v -E  'PV|nvme|failed'|| exit 0").data()
        except Exception:
            disk_lvm = ""

        finally:
            return disk_lvm

    @classmethod
    def lsblk2_27(self):
        get_pci = OsCmd(
            "ls  -l /sys/block/|grep sd|awk -F '->' '{print $2}'").data()
        blockList = []
        # block = OsCmd("ls  -l /sys/block/|grep sd|awk -F '->' '{print $2}'").data()
        blockdevices = humanJson.loads(
            OsCmd("lsblk -O -J").data())["blockdevices"]
        for d in blockdevices:
            blockdeviceDict = {}
            # 获取逻辑盘符
            kname = d.get("name").strip()
            if "nvme" in kname or "sd" not in kname:
                continue
            blockdeviceDict["name"] = "/dev/" + kname
            # 获取挂载点,只是其中之一
            #
            mount = d.get("mountpoint")
            if not mount and d.get("children"):
                for children in d.get("children"):
                    if children.get("mountpoint"):
                        mount = children.get("mountpoint").strip()

                        break
            if self.pvs and blockdeviceDict["name"] in self.pvs:
                mount = "lvm"
            blockdeviceDict["mount"] = mount

            blockdeviceDict["vendor"] = d.get("vendor").strip()
            blockdeviceDict["model"] = d.get("model").strip()
            blockdeviceDict["sn"] = d.get("serial").strip()
            try:
                blockdeviceDict["wwn"] = d.get("wwn").strip()
            except Exception:
                blockdeviceDict["wwn"] = ""
            blockdeviceDict["hctl"] = d.get("hctl").strip()
            pci = re.findall("\.\..*%s" % (kname), get_pci)[0]
            if "pci" in pci:
                blockdeviceDict["pci"] = re.findall("\.\..*%s" % (kname), get_pci)[0].split("/")[4].replace("0000:", '')
            else:
                continue
            blockList.append(blockdeviceDict)
        return blockList

    @classmethod
    def lsblk(self):
        blockList = []
        get_pci = OsCmd(
            "ls  -l /sys/block/|grep sd|awk -F '->' '{print $2}'").data()
        get_disk = OsCmd(
            "sudo  lsblk -o NAME,TYPE,MOUNTPOINT,TYPE,MODEL|grep -i ' disk '|grep -v nvme").data().strip()
        get_part = OsCmd(
            "sudo  lsblk -o NAME,TYPE,MOUNTPOINT,TYPE,MODEL|grep -i part|grep -v nvme").data().strip()
        for disk in get_disk.split("\n"):
            blockdeviceDict = {}
            d = disk.split("disk")
            # 获取逻辑盘符
            kname = d[0].strip()
            if "nvme" in kname or "sd" not in kname:
                continue
            blockdeviceDict["name"] = "/dev/" + kname

            # 获取挂载点
            mount = d[1].strip()
            if not mount:
                for part in re.findall(".*%s.*" % (kname), get_part):
                    p = part.split("part")
                    if p[1].strip():
                        mount = p[1].strip()
                        break
            if self.pvs and blockdeviceDict["name"] in self.pvs:
                mount = "lvm"
            blockdeviceDict["mount"] = mount

            block = self.diskcmd(kname)
            blockdeviceDict["vendor"] = block["vendor"]
            blockdeviceDict["model"] = block["model"]
            blockdeviceDict["sn"] = block["sn"]
            try:
                blockdeviceDict["wwn"] = d.get("wwn").strip()
            except Exception:
                blockdeviceDict["wwn"] = ""
            blockdeviceDict["hctl"] = block["hctl"]
            pci = re.findall("\.\..*%s" % (kname), get_pci)[0]
            if "pci" in pci:
                blockdeviceDict["pci"] = re.findall("\.\..*%s" % (kname), get_pci)[0].split("/")[4].replace("0000:", '')
            else:
                continue
            blockList.append(blockdeviceDict)
        return blockList

    @classmethod
    def diskcmd(self, kname):
        disk = {}
        # 并行执行命令
        vendor = OsCmd(
            "cat /sys/class/block/%s/device/vendor" % (kname))
        model = OsCmd("cat /sys/class/block/%s/device/model" % (kname))
        #sn = OsCmd("sudo smartctl -a /dev/%s|grep -i Serial|awk '{print $NF}' || echo " % (kname))
        sn = OsCmd(
            "sudo udevadm info --query=all --name=/dev/%s|awk -F '=' ' /ID_SCSI_SERIAL|ID_SERIAL_SHORT/{print $2}'" % (kname))
        #sn = OsCmd("cat /sys/class/block/%s/device/inquiry" % (kname))
        wwn = OsCmd(
            "cat /sys/class/block/%s/device/wwid|awk -F '.' '{print $NF}'" % (kname))
        hctl = OsCmd("ls /sys/class/block/%s/device/bsg" % (kname))
        # 获取命令执行结果
        disk["vendor"] = vendor.data()
        disk["model"] = model.data()
        SN = sn.data().split("\n")
        if len(SN) > 1:
            disk["sn"] = SN[-1]
        else:
            disk["sn"] = SN[0]
        disk["wwn"] = "0x" + wwn.data()
        disk["hctl"] = hctl.data()
        return disk


class MegaCli():
    def __init__(self):
        install_cmd("megacli")
        self.Disklist = CmdLsblk.out()
        self.ContList = []  # 定义控制器信息
        self.PDList = {}  # 所有PD信息
        self.VDList = {}  # 所有VD信息

    def get_Cont_List(self):
        '''
        [{"ContId":"0","PCI":"af:00.0"}]
        '''
        ContList = []
        getcontlist = OsCmd("sudo megacli  -AdpGetPciInfo -aall").data()
        for cont in getcontlist.strip().split("PCI information for"):
            if cont and "Controller" in cont:
                continfo = {}
                continfo["ContId"] = re.findall(
                    "Controller.*", cont)[0].split(" ")[1].strip()
                PCI = re.findall("Bus Number.*", cont)[0].split(":")[1].strip()
                if len(PCI) == 1:
                    continfo["PCI"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["PCI"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
        self.ContList = ContList
        return ContList

    def get_pdinfo(self, pd, ContId):
        diskinfo = {}
        AID = ContId
        EID = re.findall("Enclosure Device ID.*", pd)[0].split(":")[1].strip()
        if EID == "N/A":
            EID = "00"
        SID = re.findall("Slot Number.*", pd)[0].split(":")[1].strip()

        CID = EID
        DID = SID
        # diskinfo["acd"] = ("/a%s/c%s/d%s/e%s/s%s" % (diskinfo["CID"], diskinfo["DID"], diskinfo["ContId"], diskinfo["EID"], diskinfo["SID"]))
        diskinfo["ACD"] = ("/a%s/c%s/d%s" % (AID, CID, DID))
        diskinfo["ES"] = ("/e%s/s%s" % (EID, SID))
        # 获取wwn
        try:
            diskinfo["WWN"] = "0x" + \
                re.findall("WWN.*", pd)[0].split(":")[1].strip()
        except Exception:
            diskinfo["WWN"] = ""
        # 获取state
        try:
            State = re.findall(
                "Firmware state.*", pd)[0].split(":")[1]
            diskinfo["State"] = re.split(", Spun Up", State)[0].strip()
        except Exception:
            diskinfo["State"] = "NO"
        # 获取media_err
        try:
            diskinfo["Media_err"] = re.findall(
                "Media Error Count.*", pd)[0].split(":")[1].strip()
        except Exception:
            diskinfo["Media_err"] = "0"
        # 获取other
        try:
            diskinfo["Other_err"] = re.findall(
                "Other Error Count.*", pd)[0].split(":")[1].strip()
        except Exception:
            diskinfo["Other_err"] = "0"
        # 获取failure
        try:
            diskinfo["Failure"] = re.findall(
                "Predictive Failure Count.*", pd)[0].split(":")[1].strip()
        except Exception:
            diskinfo["Failure"] = "0"
        # 获取

        try:
            diskinfo["Size"] = re.findall(
                "Raw Size.*", pd)[0].split(":")[1].split("[")[0].strip()
        except Exception:
            diskinfo["Size"] = "NO"
        # 获取类型
        try:
            Intf = re.findall("PD Type.*", pd)[0].split(":")[1].strip()
            if "Hard Disk Device" in pd:
                Med = "HDD"
            else:
                Med = "SSD"
            diskinfo["Type"] = ("(%s)%s" % (Intf, Med))
        except Exception:
            diskinfo["Type"] = "NO"

        try:
            try:
                DEVID = re.findall("Device Id.*", pd)[0].split(":")[1].strip()
                smart = OsCmd(
                    "sudo smartctl -a -d megaraid,%s /dev/sda" % (DEVID)).data()
                diskinfo["SN"] = re.findall(
                    "Serial.*", smart)[0].split(":")[-1].strip()
                diskinfo["Model"] = re.findall(
                    "Product:.*|.*Device Model.*", smart)[0].split(":")[-1].strip()
                if "SSD" in diskinfo["Type"]:
                    if "Media_Wearout_Indicator" in smart:
                        diskinfo["Wearout"] = re.findall(
                            ".*Media_Wearout_Indicator.*", smart)[0].split()[3].strip()
                    elif "Unknown_SSD_Attribute" in smart:
                        diskinfo["Wearout"] = re.findall(
                            ".*202 *Unknown_SSD_Attribute.*", smart)[0].split()[3].strip()
                    elif "Percentage" in smart:
                        diskinfo["Wearout"] = re.findall(
                            ".*Unknown_SSD_Attribute.*", smart)[0].split()[3].strip()
            except Exception:
                Model = re.findall(
                    "Inquiry Data.*", pd)[0].split(":")[1].strip().split()
                diskinfo["SN"] = '-'.join(Model)
                diskinfo["Model"] = '-'.join(Model)
        except Exception:
            diskinfo["SN"] = ''
            diskinfo["Model"] = ''
        # 获取DSR
        try:
            Diskid = re.findall(
                "Drive's position: DiskGroup: \d+, Span: \d+, Arm: \d+", pd)[0].strip()
            DiskGroup = re.split(":|\,", Diskid)
            diskinfo['DSR'] = ("/D%s/S%s/R%s" % (DiskGroup[2].strip(),
                               DiskGroup[4].strip(), DiskGroup[6].strip()))
        except Exception:
            diskinfo['DSR'] = ''
        diskinfo["diskName"] = ""
        diskinfo["Mount"] = ""

        # print(json.dumps(devInfo, indent= 2).replace('\"',''))
        return diskinfo

    def get_PD_List(self):
        '''
        { "/c0/d0/a0/e10/s1":{},
          "/c0/d0/a0/e10/s2":{},
        }
        '''
        Disklist = self.Disklist
        PDList = {}
        getPdinfo = OsCmd("sudo megacli -pdlist -aall").data()
        for pdinfo in getPdinfo.strip().split("Adapter"):
            if pdinfo and "#" in pdinfo:
                ContId = re.findall(
                    "#\\d+", pdinfo)[0].split('#')[1].strip()  # 获取raid卡号
                # 以Enclosure Device ID为分隔符获取pd信息
                disklist = re.findall(
                    "Enclosure Device ID[\\s\\S]*?Drive Temperature", pdinfo)
                for pd in disklist:
                    diskinfo = self.get_pdinfo(pd, ContId)
                    # PDList.append(diskinfo)
                    for lb in Disklist:
                        if lb["sn"] and lb["wwn"] and (str(lb["sn"]) in str(diskinfo["SN"]) or diskinfo["WWN"] == lb["wwn"]):
                            diskinfo["diskName"] = lb["name"]
                            diskinfo["Mount"] = lb["mount"]
                    PDList[diskinfo["ACD"]] = diskinfo
        self.PDList = PDList
        return PDList

    def get_vdinfo(self, ContId, PCI):
        Disklist = self.Disklist
        try:
            getvdinfo = OsCmd(
                "sudo megacli -showsummary -a%s | sed -n '/Virtual Drives/,$p'" % (ContId)).data()
            if not getvdinfo:
                getvdinfo = OsCmd(
                    "sudo megacli -showsummary -aall | sed -n '/Virtual Drives/,$p'").data()
            # VDinfo= []
            VDinfo = {}
            for vdinfo in getvdinfo.strip().split("\n\n"):
                if vdinfo and "Virtual drive" in vdinfo:
                    vd = {}
                    vd["ContId"] = ContId
                    vd["PCI"] = PCI
                    vd['TYPE'] = "RAID" + \
                        re.findall("RAID Level.*",
                                   vdinfo)[0].split(":")[1].strip()
                    vd['State'] = re.findall(
                        "State.*", vdinfo)[0].split(":")[1].strip()
                    vd['Cache'] = ""
                    # getcache= OsCmd(" sudo megacli -ldgetprop -cache -L%s -a%s"% (vd['VD'],ContId))
                    # if "WriteBack" in getcache:
                    #     vd['Cache'] = "WB"
                    # elif "WriteThrough" in getcache:
                    #     vd['Cache'] = "WT"
                    vd['Size'] = re.findall(
                        "Size.*", vdinfo)[0].split(":")[1].strip()
                    VD = re.findall("Virtual drive.*",
                                    vdinfo)[0].split(":")[1].strip()
                    vd['VD'] = re.split(" ", VD)[2]
                    vd['AV'] = ("/a%s/v%s" % (vd["ContId"], vd['VD']))
                    vd['PDs'] = []
                    vd["diskName"] = ""
                    vd["Mount"] = ""
                    for dl in Disklist:
                        tid = re.split(":", dl["hctl"])[-2]
                        if (str(dl["pci"]) == str(vd["PCI"]) or str(vd["PCI"] == "00:00.0")) and str(tid) == str(vd["VD"]):
                            vd["diskName"] = dl["name"]
                            vd["Mount"] = dl["mount"]
                    # VDinfo.append(vd)
                    VDinfo[vd['AV']] = vd
            return VDinfo
        except Exception:
            return {}

    def get_VD_List(self):
        Disklist = self.Disklist
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList

        VDList = {}
        # 获取控制器id
        for cont in ContList:
            ContId = cont["ContId"]
            PCI = cont["PCI"]
            VDinfo = self.get_vdinfo(ContId, PCI)

            getpds = OsCmd("sudo megacli -ldpdinfo -a%s " % (ContId)).data()
            vd_list = re.split("Virtual Drive: \d+ \(Target ", getpds)
            for vd in vd_list:
                if vd and "Id:" in vd:
                    id = re.findall("Id: \d+\)",
                                    vd)[0].split(":")[1].split(")")[0].strip()
                    AV = ("/a%s/v%s" % (ContId, id))
                    if VDinfo:
                        vdinfo = VDinfo[AV]
                    else:
                        vdinfo = {}
                        vdinfo["ContId"] = ContId
                        vdinfo["PCI"] = PCI
                        vdinfo['TYPE'] = "RAID"
                        vdinfo['State'] = "Optimal"
                        vdinfo['Size'] = ''
                        vdinfo['VD'] = id
                        vdinfo['AV'] = AV
                        vdinfo['PDs'] = []
                        vdinfo["Cache"] = ""
                        vdinfo["diskName"] = ""
                        vdinfo["Mount"] = ""
                        for dl in Disklist:
                            tid = re.split(":", dl["hctl"])[-2]
                            if str(dl["pci"]) == str(vdinfo["PCI"]) and str(tid) == str(vdinfo["VD"]):
                                vdinfo["diskName"] = dl["name"]
                                vdinfo["Mount"] = dl["mount"]
                        # VDinfo.append(vd)
                        vdinfo = vdinfo
                    disklist = re.findall(
                        "Enclosure Device ID[\\s\\S]*?Drive Temperature", vd)
                    for pd in disklist:
                        # smart=Oscmd.dir_data(sudo smartctl -a -d megaraid,25 /dev/sda|egrep -i "Media_Wearout_Indicator|Serial Number:|Product:|Device Model")
                        pdinfo = self.get_pdinfo(pd, ContId)
                        # try:
                        #     slot = pdinfo["ES"].split("/s")[-1]
                        #     smart = OsCmd("sudo smartctl -a -d megaraid,%s %s" % (slot, vdinfo["diskName"]))
                        #     pdinfo["SN"] = re.findall("Serial.*", smart)[0].split(":")[-1].strip()
                        #     pdinfo["Model"] = re.findall("Product:.*|.*Device Model.*", smart)[0].split(":")[-1].strip()
                        #     if "SSD" in pdinfo["Type"]:
                        #         pdinfo["Wearout"] = re.findall(".*Media_Wearout_Indicator.*", smart)[0].split()[3].strip()
                        # except Exception:
                        #     pass
                        vdinfo["PDs"].append(pdinfo)
                    VDList[AV] = vdinfo
        self.VDList = VDList
        return VDList


class Arcconf():
    def __init__(self):
        install_cmd("arcconf")
        self.Disklist = CmdLsblk.out()
        self.ContList = []  # 定义控制器信息
        self.PDList = {}  # 所有PD信息
        self.VDList = {}  # 所有VD信息

    def get_Cont_List(self):
        '''
        [{"ContId":"0","PCI":"af:00.0"}]
        '''
        ContList = []
        ret = OsCmd("sudo lspci|grep -i Adaptec").data()
        if re.findall(".*SAS/PCIe 2.*", ret):
            ContId = 0
            for cont in re.findall(".*SAS/PCIe 2.*", ret):
                ContId = ContId + 1
                PCI = re.split(":", cont)[0]
                continfo = {}
                continfo["ContId"] = ContId
                if len(PCI) == 1:
                    continfo["PCI"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["PCI"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
        else:
            getcontlist = OsCmd("sudo arcconf list").data()
            for cont in re.findall("Controller \d+:", getcontlist):
                ContId = re.findall("\d", cont)[0]
                getcontinfo = OsCmd(
                    "sudo arcconf getconfig %s ad" % (ContId)).data()
                continfo = {}
                continfo["ContId"] = ContId
                PCI = re.findall(
                    "PCI Address.*", getcontinfo)[0].split(":")[-3].strip()
                if len(PCI) == 1:
                    continfo["PCI"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["PCI"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
        self.ContList = ContList
        return ContList

    def get_PD_List(self):
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList
        Disklist = self.Disklist
        # PDList= []
        PDList = {}
        for cont in ContList:
            ContId = cont["ContId"]
            getPdinfo = OsCmd("sudo arcconf getconfig %s pd" % (ContId)).data()
            for pd in re.split("Device #\d+", getPdinfo):
                if 'Device is a Hard drive' not in pd:
                    continue
                diskinfo = {}
                AID = ContId

                eidlot = re.findall("Reported Location.*",
                                    pd)[0].split(":")[1].strip()
                try:
                    EID = re.findall(
                        "Enclosure \d+", eidlot)[0].split()[-1].strip()
                except Exception:
                    if re.findall("Enclosure Direct Attached", eidlot):
                        EID = "01"
                    else:
                        EID = "00"
                try:
                    SID = re.findall(
                        "Slot \d+", eidlot)[0].split(" ")[-1].strip()
                except Exception:
                    SID = "00"
                CD = re.findall("Reported Channel,Device.*",
                                pd)[0].split(" ")[-1].strip()
                DID = re.split(",|\(", CD)[1].strip()
                CID = re.split(",|\(", CD)[0].strip()
                # diskinfo["acd"] = ("/c%s/d%s/a%s/e%s/s%s" % (diskinfo["CID"], diskinfo["DID"], diskinfo["ContId"], diskinfo["EID"], diskinfo["SID"]))
                diskinfo["ACD"] = ("/a%s/c%s/d%s" % (AID, CID, DID))
                diskinfo["ES"] = ("/e%s/s%s" % (EID, SID))
                # wwn
                try:
                    diskinfo["WWN"] = "0x" + \
                        re.findall("World-wide name.*",
                                   pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["WWN"] = ""
                # state
                try:
                    diskinfo["State"] = re.findall(
                        "State.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["State"] = "NO"
                # media
                try:
                    diskinfo["Media_err"] = re.findall(
                        "Media Failures.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Media_err"] = "0"
                # other
                try:
                    diskinfo["Other_err"] = re.findall(
                        "Other Time Out Errors.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Other_err"] = "0"
                # failuer
                try:
                    diskinfo["Failure"] = re.findall(
                        "Predictive Failures.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Failure"] = "0"
                # model
                try:
                    diskinfo["Model"] = re.findall(
                        "Model.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Model"] = "0"
                # sn
                try:
                    diskinfo["SN"] = re.findall(
                        "Serial number.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["SN"] = "0"
                # size
                try:
                    diskinfo["Size"] = re.findall(
                        "Total Size.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Size"] = "NO"
                # type
                try:
                    intf = re.findall("Transfer Speed.*",
                                      pd)[0].split(":")[1].strip()
                    Intf = re.split(" ", intf)[0].strip()
                    med = re.findall("SSD.*", pd)[0].split(":")[1].strip()
                    if "NO" in med:
                        Med = 'SSD'
                    else:
                        Med = 'HDD'
                    diskinfo["Type"] = ("(%s)%s" % (Intf, Med))
                except Exception:
                    diskinfo["Type"] = "NO"
                diskinfo["DSR"] = ""
                diskinfo["diskName"] = ""
                diskinfo["Mount"] = ""
                for lb in Disklist:
                    if lb["sn"] and (str(lb["sn"]) in str(diskinfo["SN"]) or diskinfo["WWN"] == lb["wwn"]):
                        diskinfo["diskName"] = lb["name"]
                        diskinfo["Mount"] = lb["mount"]
                PDList[diskinfo["ACD"]] = diskinfo
                # PDList.append(diskinfo)
        self.PDList = PDList
        return PDList

    def get_VD_List(self):
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList
        Disklist = self.Disklist

        if not self.PDList:
            PDList = self.get_PD_List()
        else:
            PDList = self.PDList

        # VDList= []
        VDList = {}
        for cont in ContList:
            ContId = cont["ContId"]
            PCI = cont["PCI"]
            getVdinfo = OsCmd("sudo arcconf getconfig %s ld" % (ContId)).data()
            for vd in re.split("\n\n\n", getVdinfo):
                if "Logical Device number" not in vd:
                    continue
                vdinfo = {}
                vdinfo["ContId"] = ContId
                vdinfo["PCI"] = PCI
                vdinfo["TYPE"] = "RAID" + \
                    re.findall("RAID level.*", vd)[0].split(":")[1].strip()
                vdinfo["State"] = re.findall(
                    "Status of Logical Device.*", vd)[0].split(":")[1].strip()
                vdinfo["Cache"] = ""
                vdinfo["Size"] = re.findall(
                    "Size  .*", vd)[0].split(":")[1].strip()
                vdinfo["VD"] = re.findall(
                    "Logical Device number \d+", vd)[0].split()[-1].strip()
                vdinfo["AV"] = ("/a%s/v%s" % (vdinfo["ContId"], vdinfo["VD"]))
                vdinfo['PDs'] = []
                for Device in re.findall("Device \d+.*", vd):
                    try:
                        AID = ContId
                        EID = re.findall(
                            "Enclosure:\d+", Device)[0].split(":")[-1].strip()
                        SID = re.findall(
                            "Slot:\d+", Device)[0].split(":")[-1].strip()
                        ES = ("/e%s/s%s" % (EID, SID))
                        for acd in PDList:
                            pd = PDList[acd]
                            ad = re.findall("/a\\d+", acd)[0].strip("/a")
                            if str(ad) == str(AID) and str(pd["ES"]) == str(ES):
                                vdinfo["PDs"].append(pd)
                    except Exception:
                        AID = ContId
                        DID = re.findall(
                            "Device \d+", Device)[0].split(" ")[-1].strip()
                        acd = ("/a%s/c%s/d%s" % (AID, 0, DID))
                        vdinfo["PDs"].append(PDList[acd])

                if "Disk Name" in vd:
                    vdinfo["diskName"] = re.findall(
                        "Disk Name.*", vd)[0].split(":")[1].strip()
                else:
                    vdinfo["diskName"] = ""
                if "Mount Points" in vd:
                    mount = re.findall(
                        "Mount Points.*", vd)[0].split(":")[1].strip()
                    vdinfo["Mount"] = re.split(" ", mount)[0]
                else:
                    vdinfo["Mount"] = ""

                if vdinfo["diskName"] == "":
                    for dl in Disklist:
                        lid = re.split(":", dl["hctl"])[-1]
                        if str(dl["pci"]) == str(vd["PCI"]) and str(lid) == str(vd["VD"]):
                            vdinfo["diskName"] = dl["name"]
                            vdinfo["Mount"] = dl["mount"]
                    # VDList.append(vdinfo)
                if 'No' in vdinfo["diskName"]:
                    vdinfo["diskName"] = ""
                if 'No' in vdinfo["Mount"]:
                    vdinfo["Mount"] = ""
                VDList[vdinfo["AV"]] = vdinfo
        self.VDList = VDList
        return VDList


class Arcconf2():
    def __init__(self):
        install_cmd("arcconf")
        self.Disklist = CmdLsblk.out()
        self.ContList = []  # 定义控制器信息
        self.PDList = {}  # 所有PD信息
        self.VDList = {}  # 所有VD信息

    def get_Cont_List(self):
        '''
        [{"ContId":"0","PCI":"af:00.0"}]
        '''

        ContList = []
        ContId = 0
        ret = OsCmd("sudo lspci|grep -i Adaptec").data()
        for cont in re.findall(".*SAS/PCIe 2.*", ret):
            ContId = ContId + 1
            PCI = re.split(":", cont)[0]
            continfo = {}
            continfo["ContId"] = ContId
            if len(PCI) == 1:
                continfo["PCI"] = ("0%s:00.0" % (PCI))
            else:
                continfo["PCI"] = ("%s:00.0" % (PCI))
            ContList.append(continfo)
        self.ContList = ContList
        return ContList

    def get_PD_List(self):
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList

        Disklist = self.Disklist
        # PDList= []
        PDList = {}
        for cont in ContList:
            ContId = cont["ContId"]
            getPdinfo = OsCmd("sudo arcconf getconfig %s pd" % (ContId)).data()
            for pd in re.split("Device #\d+", getPdinfo):
                if 'Device is a Hard drive' not in pd:
                    continue
                diskinfo = {}
                AID = ContId
                try:
                    eidlot = re.findall("Reported Location.*", pd)[0].split(":")[1].strip()
                    EID = re.findall("Enclosure \d+", eidlot)[0].split()[-1].strip()
                    SID = re.findall("Slot \d+", eidlot)[0].split(" ")[-1].strip()
                except Exception:
                    EID = "00"
                    SID = "00"
                CD = re.findall("Reported Channel,Device.*",
                                pd)[0].split(" ")[-1].strip()
                DID = re.split(",|\(", CD)[1].strip()
                CID = re.split(",|\(", CD)[0].strip()
                diskinfo["ACD"] = ("/a%s/c%s/d%s" % (AID, CID, DID))
                diskinfo["ES"] = ("/e%s/s%s" % (EID, SID))
                # wwn
                try:
                    diskinfo["WWN"] = "0x" + \
                        re.findall("World-wide name.*",
                                   pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["WWN"] = ""

                # state
                try:
                    diskinfo["State"] = re.findall(
                        "State.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["State"] = "NO"
                diskinfo["Media_err"] = "0"
                diskinfo["Other_err"] = "0"
                diskinfo["Failure"] = "0"
                # model
                try:
                    diskinfo["Model"] = re.findall(
                        "Model.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Model"] = "0"
                try:
                    diskinfo["SN"] = re.findall(
                        "Serial number.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["SN"] = "NO"
                # type
                try:
                    diskinfo["Size"] = re.findall(
                        "  Size.*|Total Size.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Size"] = "NO"
                try:
                    intf = re.findall("Transfer Speed.*",
                                      pd)[0].split(":")[1].strip()
                    Intf = re.split(" ", intf)[0].strip()
                    diskinfo["Type"] = Intf  # sata
                except Exception:
                    diskinfo["Type"] = "NO"
                diskinfo["DSR"] = ""
                diskinfo["diskName"] = ""
                diskinfo["Mount"] = ""
                for lb in Disklist:
                    if lb["sn"] and (str(lb["sn"]) in str(diskinfo["SN"]) or diskinfo["WWN"] == lb["wwn"]):
                        diskinfo["diskName"] = lb["name"]
                        diskinfo["Mount"] = lb["mount"]
                PDList[diskinfo["ACD"]] = diskinfo
                # PDList.append(diskinfo)
        self.PDList = PDList
        return PDList

    def get_VD_List(self):
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList
        PDList = self.get_PD_List()

        Disklist = self.Disklist
        if not self.PDList:
            PDList = self.get_PD_List()
        else:
            PDList = self.PDList

        VDList = {}
        for cont in ContList:
            ContId = cont["ContId"]
            PCI = cont["PCI"]
            getVdinfo = OsCmd("sudo arcconf getconfig %s ld" % (ContId)).data()
            for vd in re.split("\n\n", getVdinfo):

                if "Logical device number" not in vd and "Logical Device number" not in vd:
                    continue
                vdinfo = {}
                vdinfo["ContId"] = ContId
                vdinfo["PCI"] = PCI
                TYPE = "RAID" + \
                    re.findall("RAID level.*", vd)[0].split(":")[1].strip()
                if "Simple_volume" in TYPE:
                    vdinfo["TYPE"] = "RAID0"
                else:
                    vdinfo["TYPE"] = TYPE
                vdname = re.findall(
                    "Logical [d,D]evice name .*:.*", vd)[0].split(":")[1].strip()
                if "JBOD" in vdname:
                    vdinfo["State"] = "JBOD"
                else:
                    vdinfo["State"] = re.findall(
                        "Status of [l,L]ogical [d,D]evice.*", vd)[0].split(":")[1].strip()
                vdinfo["Cache"] = ""
                vdinfo["Size"] = re.findall(
                    "Size  .*", vd)[0].split(":")[1].strip()
                vdinfo["VD"] = re.findall(
                    "Logical [d,D]evice number \d+", vd)[0].split()[-1].strip()
                vdinfo["AV"] = ("/a%s/v%s" % (vdinfo["ContId"], vdinfo["VD"]))
                vdinfo['PDs'] = []
                for Device in re.findall("Segment \d+.*", vd):
                    AID = ContId
                    EID = re.findall(
                        "Enclosure:\d+", Device)[0].split(":")[-1].strip()
                    SID = re.findall(
                        "Slot:\d+", Device)[0].split(":")[-1].strip()
                    ES = ("/e%s/s%s" % (EID, SID))
                    for acd in PDList:
                        pd = PDList[acd]
                        ad = re.findall("/a\\d+", acd)[0].strip("/a")
                        if str(ad) == str(AID) and str(pd["ES"]) == str(ES):
                            vdinfo["PDs"].append(pd)
                vdinfo["diskName"] = ""
                vdinfo["Mount"] = ""
                for dl in Disklist:
                    lid = re.split(":", dl["hctl"])[-2]
                    if str(dl["model"]) == str(vdname) and str(lid) == str(vdinfo["VD"]):
                        vdinfo["diskName"] = dl["name"]
                        vdinfo["Mount"] = dl["mount"]
                # VDList.append(vdinfo)
                VDList[vdinfo["AV"]] = vdinfo
        self.VDList = VDList
        return VDList


class Sas2icu():
    def __init__(self):
        install_cmd("sas2ircu")
        self.Disklist = CmdLsblk.out()
        self.ContList = []  # 定义控制器信息
        self.PDList = {}  # 所有PD信息
        self.VDList = {}  # 所有VD信息

    def get_Cont_List(self):
        '''
        [{"ContId":"0","PCI":"af:00.0"}]
        '''
        ContList = []
        try:
            getcontlist = OsCmd(
                "sudo sas2ircu list|grep -i '^ *[0-9]'").data().strip()
            for cont in re.split("\n", getcontlist):
                continfo = {}
                continfo["ContId"] = cont.split()[0]
                pciinfo = cont.split()[4]
                PCI = re.split("h:", pciinfo)[1]
                if len(PCI) == 1:
                    continfo["PCI"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["PCI"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
            self.ContList = ContList
        except Exception:
            ContId = -1
            ret = OsCmd("sudo lspci|grep -i SAS").data()
            for cont in re.findall(".*SAS.*", ret):
                ContId = ContId + 1
                PCI = re.split(":", cont)[0]
                continfo = {}
                continfo["ContId"] = ContId
                if len(PCI) == 1:
                    continfo["PCI"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["PCI"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
            self.ContList = ContList
        return self.ContList

    def get_PD_List(self):
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList

        Disklist = self.Disklist
        PDList = {}
        VDList = {}
        for cont in ContList:
            ContId = cont["ContId"]
            PCI = cont["PCI"]
            getinfo = OsCmd("sudo sas2ircu %s DISPLAY" % (ContId)).data()
            # pd信息
            getPdinfo = re.findall(
                "Physical device information[\\s\\S]*Enclosure information", getinfo)
            for pd in getPdinfo[0].split("\n\n"):
                if 'Device is a Hard disk' not in pd:
                    continue
                diskinfo = {}
                AID = ContId
                EID = re.findall("Enclosure .*", pd)[0].split(":")[1].strip()
                SID = re.findall("Slot #.*", pd)[0].split(":")[1].strip()
                CID = EID
                DID = SID
                # diskinfo["acd"] = ("/c%s/d%s/a%s/e%s/s%s" % (diskinfo["CID"], diskinfo["DID"], diskinfo["ContId"], diskinfo["EID"], diskinfo["SID"]))
                diskinfo["ACD"] = ("/a%s/c%s/d%s" % (AID, CID, DID))
                diskinfo["ES"] = ("/e%s/s%s" % (EID, SID))
                # 获取wwn
                try:
                    diskinfo["WWN"] = "0x" + \
                        re.findall("GUID.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["WWN"] = "NO"
                # 获取size
                try:
                    Size = re.findall("Size.*", pd)[0].split(":")[1].strip()
                    diskinfo["Size"] = re.split("/", Size)[0].strip() + "MB"
                except Exception:
                    diskinfo["Size"] = "NO"
                # 获取状态
                try:
                    diskinfo["State"] = re.findall(
                        "State.*", pd)[0].split(":")[1].strip().split(" ")[0].strip()
                except Exception:
                    diskinfo["State"] = "NO"
                diskinfo["Media_err"] = 0
                diskinfo["Other_err"] = 0
                diskinfo["Failure"] = 0
                # 获取磁盘型号
                try:
                    diskinfo["Model"] = re.findall(
                        "Model Number.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Model"] = "NO"
                # 获取磁盘sn
                try:
                    diskinfo["SN"] = re.findall(
                        "Serial No.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["SN"] = "NO"
                # 获取磁盘类型
                try:
                    Intf = re.findall(
                        "Protocol.*", pd)[0].split(":")[1].strip()
                    Med = re.findall(
                        "Drive Type.*", pd)[0].split(":")[1].strip()
                    diskinfo["Type"] = ("(%s)%s" %
                                        (Intf, re.split("_", Med)[-1]))
                except Exception:
                    diskinfo["Type"] = "NO"

                diskinfo["DSR"] = ""
                diskinfo["diskName"] = ""
                diskinfo["Mount"] = ""
                for lb in Disklist:
                    if lb["sn"] and (str(lb["sn"]) == str(diskinfo["SN"]) or str(diskinfo["WWN"]) == str(lb["wwn"])):
                        diskinfo["diskName"] = lb["name"]
                        diskinfo["Mount"] = lb["mount"]
                        break
                PDList[diskinfo["ACD"]] = diskinfo
            # vd信息
            getVdinfo = re.findall(
                "IR Volume information[\\s\\S]*Physical device information", getinfo)
            for vd in re.split("IR volume \d+", getVdinfo[0]):
                vdinfo = {}
                if 'Volume ID' not in vd:
                    continue
                vdinfo["ContId"] = ContId
                vdinfo["PCI"] = PCI
                vdinfo['TYPE'] = re.findall(
                    "RAID level.*", vd)[0].split(":")[1].strip()
                vdinfo['State'] = re.findall(
                    "Status of volume.*", vd)[0].split(":")[1].strip().split(" ")[0].strip()  # Okay
                vdinfo['Cache'] = ''
                vdinfo['Size'] = re.findall(
                    "Size.*", vd)[0].split(":")[1].strip() + "MB"
                vdinfo["VD"] = re.findall(
                    "Volume ID.*", vd)[0].split(":")[1].strip()
                vdinfo['AV'] = ("/a%s/v%s" % (vdinfo["ContId"], vdinfo['VD']))
                vdinfo['PDs'] = []
                for acd in re.findall("PHY.*", vd):
                    CID = re.findall("PHY.*", acd)[0].split(":")[1].strip()
                    DID = re.findall("PHY.*", acd)[0].split(":")[-1].strip()
                    ACD = ("/a%s/c%s/d%s" % (AID, CID, DID))
                    vdinfo['PDs'].append(PDList[ACD])
                vdinfo['diskName'] = 'NO'
                vdinfo['Mount'] = 'NO'
                VDList[vdinfo['AV']] = vdinfo
        self.PDList = PDList
        self.VDList = VDList
        return PDList

    def get_VD_List(self):
        if not self.VDList:
            self.get_PD_List()
        return self.VDList


class Ssacli():
    def __init__(self):
        install_cmd("ssacli")
        self.ContList = []  # 定义控制器信息
        self.PDList = {}  # 所有PD信息
        self.VDList = {}  # 所有VD信息

    def get_Cont_List(self):
        '''
        [{"ContId":"0","PCI":"af:00.0"}]
        '''
        ContList = []
        getcontlist = OsCmd("sudo ssacli ctrl all show detail").data()
        for cont in getcontlist.strip().split("Smart Array"):
            if cont and "Slot" in cont:
                continfo = {}
                continfo["ContId"] = re.findall(
                    "Slot:.*", cont)[0].split(":")[1].strip()
                PCI = re.findall(
                    "PCI Address.*", cont)[0].split(":")[-2].strip()
                if len(PCI) == 1:
                    continfo["PCI"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["PCI"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
        self.ContList = ContList
        return ContList

    def get_PD_List(self):
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList
        Disklist = self.Disklist
        # PDList= []
        PDList = {}
        for cont in ContList:
            ContId = cont["ContId"]
            getPdinfo = OsCmd(
                "sudo ssacli ctrl slot=%s pd all show detail" % (ContId)).data()
            for pd in re.split("physicaldrive", getPdinfo):
                if 'Port' not in pd:
                    continue

                diskinfo = {}
                try:
                    AID = ContId
                    Port = re.findall("Port.*", pd)[0].split(":")[1].strip()
                    Box = re.findall("Box.*", pd)[0].split(":")[1].strip()
                    Bay = re.findall("Bay.*", pd)[0].split(":")[1].strip()
                    EID = Port+Box
                    SID = Bay
                except Exception:
                    EID = "00"
                    SID = "00"
                DID = SID
                CID = EID
                # diskinfo["acd"] = ("/c%s/d%s/a%s/e%s/s%s" % (diskinfo["CID"], diskinfo["DID"], diskinfo["ContId"], diskinfo["EID"], diskinfo["SID"]))
                diskinfo["ACD"] = ("/a%s/c%s/d%s" % (AID, CID, DID))
                diskinfo["ES"] = ("/e%s/s%s" % (EID, SID))
                # wwn
                try:
                    diskinfo["WWN"] = "0x" + \
                        re.findall("WWID.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["WWN"] = ""
                # state
                try:
                    diskinfo["State"] = re.findall(
                        "Status.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["State"] = "NO"
                # media
                diskinfo["Media_err"] = "0"
                # other
                diskinfo["Other_err"] = "0"
                # failuer
                diskinfo["Failure"] = "0"
                # model
                try:
                    diskinfo["Model"] = re.findall(
                        "Model.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Model"] = "0"
                # sn
                try:
                    diskinfo["SN"] = re.findall(
                        "Serial Number.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["SN"] = "0"
                # size
                try:
                    diskinfo["Size"] = re.findall(
                        "Size:.*", pd)[0].split(":")[1].strip()
                except Exception:
                    diskinfo["Size"] = "NO"
                # type
                try:
                    Interface_Type = re.findall(
                        "Interface Type.*", pd)[0].split(":")[1].strip()
                    Intf = re.split(" ", Interface_Type)[-1].strip()
                    if "Solid State" in Interface_Type:
                        Med = 'SSD'
                    else:
                        Med = 'HDD'
                    diskinfo["Type"] = ("(%s)%s" % (Intf, Med))
                except Exception:
                    diskinfo["Type"] = "NO"
                diskinfo["DSR"] = ""
                diskinfo["diskName"] = ""
                diskinfo["Mount"] = ""
                for lb in Disklist:
                    if lb["sn"] and (str(lb["sn"]) in str(diskinfo["SN"]) or diskinfo["WWN"] == lb["wwn"]):
                        diskinfo["diskName"] = lb["name"]
                        diskinfo["Mount"] = lb["mount"]
                PDList[diskinfo["ACD"]] = diskinfo
                # PDList.append(diskinfo)

        self.PDList = PDList
        return PDList

    def get_VD_List(self):
        if not self.ContList:
            ContList = self.get_Cont_List()
        else:
            ContList = self.ContList
        PDList = self.get_PD_List()

        if not self.PDList:
            PDList = self.get_PD_List()
        else:
            PDList = self.PDList

        # VDList= []
        VDList = {}
        for cont in ContList:
            ContId = cont["ContId"]
            PCI = cont["PCI"]
            getVdinfo = OsCmd(
                " sudo ssacli ctrl slot=%s ld all show detail" % (ContId)).data()
            getconfig = OsCmd(
                " sudo ssacli ctrl slot=%s show config" % (ContId)).data()
            for vd in re.split("Array", getVdinfo):
                if "Logical Drive" not in vd:
                    continue
                vdinfo = {}
                vdinfo["ContId"] = ContId
                vdinfo["PCI"] = PCI
                vdinfo["TYPE"] = "RAID" + \
                    re.findall("Fault Tolerance.*",
                               vd)[0].split(":")[1].strip()
                vdinfo["State"] = re.findall(
                    "Status:.*", vd)[0].split(":")[1].strip()
                vdinfo["Cache"] = ""
                vdinfo["Size"] = re.findall(
                    "Size.*", vd)[0].split(":")[1].strip()
                vdinfo["VD"] = re.findall(
                    "Logical Drive:.*", vd)[0].split()[-1].strip()
                vdinfo["AV"] = ("/a%s/v%s" % (vdinfo["ContId"], vdinfo["VD"]))
                vdinfo['PDs'] = []
                if "physicaldrive" in vd:
                    for Device in re.findall("physicaldrive.*", vd):
                        AID = ContId
                        devid = re.findall(
                            "physicaldrive.*", Device)[0].split(" ")[1].strip()
                        Port = devid.split(":")[0].strip()
                        Box = devid.split(":")[1].strip()
                        Bay = devid.split(":")[2].strip()
                        CID = Port+Box
                        DID = Bay
                        ACD = ("/a%s/c%s/d%s" % (AID, CID, DID))
                        vdinfo["PDs"].append(PDList[ACD])
                else:
                    for pds in re.split("Array", getconfig):
                        if re.findall(" logicaldrive %s.*" % (vdinfo["VD"]), pds):
                            for Device in re.findall("physicaldrive.*", pds):
                                AID = ContId
                                devid = re.findall(
                                    "physicaldrive.*", Device)[0].split(" ")[1].strip()
                                Port = devid.split(":")[0].strip()
                                Box = devid.split(":")[1].strip()
                                Bay = devid.split(":")[2].strip()
                                CID = Port+Box
                                DID = Bay
                                ACD = ("/a%s/c%s/d%s" % (AID, CID, DID))
                                vdinfo["PDs"].append(PDList[ACD])
                if "Disk Name" in vd:
                    vdinfo["diskName"] = re.findall(
                        "Disk Name:.*", vd)[0].split(":")[1].strip()
                else:
                    vdinfo["diskName"] = ""
                if "Mount Points" in vd:
                    mount = re.findall("Mount Points:.*",
                                       vd)[0].split(":")[1].strip()
                    vdinfo["Mount"] = re.split(",| ", mount)[0]
                else:
                    vdinfo["Mount"] = ""
                VDList[vdinfo["AV"]] = vdinfo
        self.VDList = VDList
        return VDList


# 判断故障盘
class FaultDiskInfo():
    def getFailedPD(self, OtherPdList):

        msg = {"state": 0, "media_err": 0, "other_err": 0,
               "failuer": 0, "wearout": 100, "dropDiskNum": 0, "errtotal": 0}
        data = {}

        for pdid in humanSort(OtherPdList):
            pd = OtherPdList.get(pdid)
            msg["errtotal"] = msg["errtotal"] + \
                int(pd["Media_err"]) + \
                int(pd["Other_err"]) + int(pd["Failure"])
            if pd["State"] not in statelist or (pd["diskName"] and not pd["Mount"]) or (not pd["diskName"] and not pd["Mount"]):
                if "good" in pd["State"]:
                    continue
                # 盘状态不在statelist 和 盘没有盘符,和挂载点,认为为故障盘
                msg["state"] = msg["state"] + 1
                data[pdid] = pd

            elif int(pd["Media_err"]) > 0 or int(pd["Other_err"]) > 0 or int(pd["Failure"]) > 0 or (pd.get("Wearout") and int(pd["Wearout"]) < 30):
                # 盘有media_err other_err failuer 和固态硬盘寿命小于30的为故障盘
                if str(pdid) not in str(data.keys()):
                    data[pdid] = pd

                if int(pd["Media_err"]) > int(msg["media_err"]):
                    msg["media_err"] = int(pd["Media_err"])

                if int(pd["Other_err"]) > int(msg["other_err"]):
                    msg["other_err"] = int(pd["Other_err"])

                if int(pd["Failure"]) > int(msg["failuer"]):
                    msg["failuer"] = int(pd["Failure"])

                if pd.get("Wearout") and int(pd["Wearout"]) < int(msg["wearout"]):
                    msg["wearout"] = int(pd["Wearout"])
        return msg, data

    def getFaultVirDisk(self, VDList):
        msg = {"state": 0, "media_err": 0, "other_err": 0,
               "failuer": 0, "wearout": 100, "dropDiskNum": 0, "errtotal": 0}
        data = {}

        # 判断vd报错
        for vid in humanSort(VDList):
            vd = VDList[vid]
            # 判断vd的状态
            if vd["State"] not in statelist:
                # 如果状态不对
                msg["state"] = msg["state"] + 1
                data[vid] = vd
            # 判断改磁盘下的pd是否有err报错
            else:
                for pd in vd["PDs"]:
                    msg["errtotal"] = msg["errtotal"] + \
                        int(pd["Media_err"]) + \
                        int(pd["Other_err"]) + int(pd["Failure"])
                    # 将在vd中的pd进行过来
                    if pd["State"] not in statelist or int(pd["Media_err"]) > 0 or int(pd["Other_err"]) > 0 or int(pd["Failure"]) > 0 or (pd.get("Wearout") and int(pd["Wearout"]) < 30):
                        # 判断报错的vd信息是否已经记录,没记录进行记录
                        if str(vid) not in str(data.keys()):
                            data[vid] = vd
                        # 巡检输出最大报错
                        if int(pd["Media_err"]) > int(msg["media_err"]):
                            msg["media_err"] = int(pd["Media_err"])

                        if int(pd["Other_err"]) > int(msg["other_err"]):
                            msg["other_err"] = int(pd["Other_err"])

                        if int(pd["Failure"]) > int(msg["failuer"]):
                            msg["failuer"] = int(pd["Failure"])

                        if pd.get("Wearout") and int(pd["Wearout"]) < int(msg["wearout"]):
                            msg["wearout"] = int(pd["Wearout"])
        return msg, data

    def getDropDisk(self, PDList):
        msg = {"state": 0, "media_err": 0, "other_err": 0,
               "failuer": 0, "wearout": 100, "dropDiskNum": 0, "errtotal": 0}
        data = {}

        ACD1 = ""
        for ACD in humanSort(PDList):
            if ACD1:
                # 判断是否为有不连续的盘
                D1 = ACD1.split("/d")[-1]
                D2 = ACD.split("/d")[-1]
                AC1 = re.findall("/a\\d+/c\\d+|/a\\d+/c\\d+I\\d+", ACD1)[0]
                AC2 = re.findall("/a\\d+/c\\d+|/a\\d+/c\\d+I\\d+", ACD)[0]
                if str(AC1) == str(AC2) and int(D2) - int(D1) == 2:
                    msg["dropDiskNum"] = msg["dropDiskNum"] + 1
                    data[ACD1] = PDList[ACD1]
                    data[ACD] = PDList[ACD]
            ACD1 = ACD
        return msg, data


# 格式化输出
class FormatOutput():
    def pdout(self, pd):
        if pd.get("Wearout") is None:
            Wearout = ""
        else:
            Wearout = "Wearout:{}".format(pd.get("Wearout"))

        # 判断是否有media、other以及Failure报错,如果没有报错则不输出这三项
        if int(pd["Media_err"]) == 0 and int(pd["Other_err"]) == 0 and int(pd["Failure"]) == 0:
            value = (
                pd.get("ACD"),
                pd.get("ES"),
                pd.get("Size"),
                pd.get("State"),
                pd.get("Type"),
                pd.get("DSR"),
                Wearout,
                pd.get("diskName"),
                pd.get("Mount")
            )
            msg = '{} {} {} {} {} {} {} {} {}'.format(*tuple(value))
        else:
            value = (
                pd.get("ACD"),
                pd.get("ES"),
                pd.get("Size"),
                pd.get("State"),
                pd.get("Type"),
                pd.get("DSR"),
                Wearout,
                pd.get("Media_err"),
                pd.get("Other_err"),
                pd.get("Failure"),
                pd.get("diskName"),
                pd.get("Mount")
            )
            msg = '{} {} {} {} {} {} {} Media_err:{} Other_err:{} Failure:{} {} {}'.format(
                *tuple(value))
        print(msg)

    def vdout(self, VD, sign=False):
        # sign 是否进格式化
        # VirDiskInfoList = ["AV", "TYPE", "Size", "State", "Cache", "diskName", "Mount"]
        value = (
            VD["AV"],
            VD["TYPE"],
            VD["Size"],
            VD["State"],
            VD["Cache"],
            VD["diskName"],
            VD["Mount"]
        )
        if sign:
            if VD["State"] not in statelist:
                msg = '\033[1;34m{} {} {} \033[5;31m{}\033[1;34m {} {} {}\033[0m'.format(
                    *tuple(value))
            else:
                msg = '\033[1;34m{} {} {} {} {} {} {}\033[0m'.format(
                    *tuple(value))
        else:
            msg = '{} {} {} {} {} {} {}'.format(*tuple(value))
        print(msg)

        for pd in VD["PDs"]:
            self.pdout(pd)


# 自动亮灯,灭灯
class AutoBlink():
    def __init__(self):
        self.raidType = getRaidtype()

    def FaultVDAutoBlink(self, VDList):
        _, faultvd = FaultDiskInfo().getFaultVirDisk(VDList)
        autoPdBlink = []
        if faultvd:
            for vid in faultvd:
                # 判断是raid几
                vd = faultvd.get(vid)
                raidnum = str(vd["TYPE"])
                if (raidnum == "RAID0" and not vd.get("Mount")) or (raidnum == "RAID1" and len(vd["PDs"]) > 1) or (raidnum == "RAID10" and len(vd["PDs"]) % 2 == 0):
                    # raid0 并且没有挂载,可以直接亮
                    # 如果raid1没有掉盘的,可以直接换
                    # raid10 如果没有掉盘的,可以直接换
                    pds = []
                    for pd in vd["PDs"]:
                        if pd["State"] not in statelist or int(pd["Media_err"]) > 0 or int(pd["Other_err"]) > 0 or int(pd["Failure"]) > 0:
                            pds.append(pd)
                    if len(pds) == 1:
                        # 如果故障盘为一个的话可以直接换,否则不能直接换
                        autoPdBlink.extend(pds)
                    # elif len(pds) > 1:
                    #     print("有多块盘报错, 不满足自动亮灯条件")
        return autoPdBlink

    def FaultPDAutoBlink(self, OtherPdList):
        autoPdBlink = []
        _, faultpd = FaultDiskInfo().getFailedPD(OtherPdList)
        if faultpd:
            for pid in faultpd:
                pd = faultpd[pid]
                if pd["State"] not in statelist:
                    # 如果盘状态不对的话,可以直接换
                    # pdBlinkNum.append(pd["ACD"])
                    autoPdBlink.append(pd)
                elif pd["diskName"] and not pd["Mount"]:
                    # pdBlinkNum.append(pd["ACD"])
                    autoPdBlink.append(pd)
                # else:
                #     print("%s 有报错,不满足自动亮灯条件,请人工操作" % (pd["ACD"]))
        return autoPdBlink

    def DropDiskAutoBlink(self, PDList):
        _, otherfaultpd = FaultDiskInfo().getDropDisk(PDList)
        if otherfaultpd:
            return otherfaultpd.values()
        else:
            return []

    def pdAutoBlink(self, VDList, OtherPdList):
        autoPdBlink = []
        autoPdBlink.extend(self.FaultVDAutoBlink(VDList))
        autoPdBlink.extend(self.FaultPDAutoBlink(OtherPdList))
        return autoPdBlink

    def onBlink(self, acd='', pd={}):
        # print(re.findall("/a\\d+/c\\d+I\\d+/d\\d+", acd))
        if not acd:
            raise RaidError("Please enter the correct slot number", "127")
        elif not re.findall("/a\\d+/c\\d+/d\\d+", acd) and not re.findall("/a\\d+/c\\d+I\\d+/d\\d+", acd):
            raise RaidError(
                "Please enter the correct slot number format: /a0/c32/d1", "127")

        aid = re.findall("/a\\d+", acd)[0].replace("/a", '').strip()
        cid = re.findall("/c\\d+", acd)[0].replace("/c", '').strip()
        did = re.findall("/d\\d+", acd)[0].replace("/d", '').strip()
        try:
            box = re.findall("I\\d+", acd)[0].replace("I", '').strip()
        except Exception:
            box = ""
        acd = str(acd)
        if self.raidType == "megacli":
            ret = OsCmd(
                "sudo megacli -PdLocate -start -PhysDrv[%s:%s] -a%s || exit 0" % (cid, did, aid)).data()
        elif self.raidType == "arcconf2":
            ret = os.popen(
                "sudo nohup arcconf IDENTIFY %s DEVICE %s %s 2>/dev/null &" % (aid, cid, did)).read()
            # print("%s 无法亮灯,请人工操作" % (acd))
            # exit(0)
        elif self.raidType == "arcconf":
            ret = OsCmd("sudo arcconf IDENTIFY %s DEVICE %s %s  TIME 120" %
                        (aid, cid, did)).data()
        elif self.raidType == "sas2icu":
            ret = OsCmd("sudo sas2ircu %s locate %s:%s on" %
                        (aid, cid, did)).data()
        elif self.raidType == "ssacli":
            ret = OsCmd("sudo ssacli ctrl slot=%s pd %sI:%s:%s modify led=on" %
                        (aid, cid, box, did)).data()
            if not ret:
                ret = "success"
        else:
            print("未适配自动亮灯")

        if "uccess" in ret:
            if pd and str(acd) == str(pd.get("ACD")):
                print("\n故障磁盘已亮灯,磁盘信息如下:")
                FormatOutput().pdout(pd)
            else:
                print("%s 盘, 已亮灯" % (acd))
        else:
            if pd and str(acd) == str(pd.get("ACD")) and pd["State"] not in statelist:
                print("磁盘亮灯失败, 磁盘应该有故障灯,磁盘信息如下,麻烦确认后操作:")
                FormatOutput().pdout(pd)
            else:
                print("亮灯失败,请人工操作")

    def offBlink(self, acd=''):
        if not acd:
            raise RaidError("Please enter the correct slot number", "127")
        elif not re.findall("/a\\d+/c\\d+/d\\d+", acd) and not re.findall("/a\\d+/c\\d+I\\d+/d\\d+", acd):
            raise RaidError(
                "Please enter the correct slot number format: /a0/c32/d1", "127")

        aid = re.findall("/a\\d+", acd)[0].replace("/a", '').strip()
        cid = re.findall("/c\\d+", acd)[0].replace("/c", '').strip()
        did = re.findall("/d\\d+", acd)[0].replace("/d", '').strip()
        try:
            box = re.findall("I\\d+", acd)[0].replace("I", '').strip()
        except Exception:
            box = ""
        acd = str(acd)
        if self.raidType == "megacli":
            ret = OsCmd(
                "sudo megacli -PdLocate -stop -PhysDrv[%s:%s] -a%s || exit 0" % (cid, did, aid)).data()
        elif self.raidType == "arcconf2":
            ret = os.popen(
                "echo ''|sudo arcconf IDENTIFY %s DEVICE %s %s 2>/dev/null " % (aid, cid, did)).read()
            # print("%s 无法灭灯,请人工操作" % (acd))
            # exit(0)
        elif self.raidType == "arcconf":
            ret = OsCmd("sudo arcconf IDENTIFY %s DEVICE %s %s  TIME 1" %
                        (aid, cid, did)).data()
        elif self.raidType == "sas2icu":
            ret = OsCmd("sudo sas2ircu %s locate %s:%s off" %
                        (aid, cid, did)).data()
        elif self.raidType == "ssacli":
            ret = OsCmd("sudo ssacli ctrl slot=%s pd %sI:%s:%s modify led=off" %
                        (aid, cid, box, did)).data()
            if not ret:
                ret = "success"
        else:
            print("未适配自动灭灯")
        if "uccess" in ret:
            print("%s 盘, 已灭灯" % (acd))
        else:
            print(ret)
            print("灭灯失败,请人工操作")
            exit(0)


# 获取控制器信息,未使用
class Controller():
    def getContPciAndId(self):
        ControlleList = []
        ControllerDict = self.SaveControllerInfo()
        for raidcmd in ControllerDict:
            if raidcmd == "updata_time":
                continue
            for cont in ControllerDict.get(raidcmd):
                res = {}
                res["PCI"] = cont.get("PCI")
                res["ContId"] = cont.get("ContId")
                ControlleList.append(res)
        return ControlleList

    def SaveControllerInfo(self):
        f = config.get("Controllerjs")
        # 获取系统启动时间
        since = os.popen("who -b|awk '{print $(NF-1)}'").read().strip()
        systemUpSinceTime = datetime.datetime.strptime(since, '%Y-%m-%d')
        if os.path.exists(f):
            # 文件存在
            Controllerjs = open(f, "r")
            ControllerDict = json.load(Controllerjs)
            Controllerjs.close()
            updata_time_str = ControllerDict.get("updata_time")
            updata_time = datetime.datetime.strptime(
                updata_time_str, '%Y-%m-%d')
            if updata_time > systemUpSinceTime:
                return ControllerDict
        newTime = datetime.datetime.now().strftime('%Y-%m-%d')
        ControllerDict = {"updata_time": newTime}
        pciDict = self.PciInfo()
        for raidcmd in pciDict.keys():
            ControllerDict[raidcmd] = []
            if raidcmd == "megacli":
                Contid = self.MegaRAID()

            elif raidcmd == "arcconf":
                Contid = self.Adaptec()

            elif raidcmd == "arcconf2":
                Contid = self.Adaptec2()

            elif raidcmd == "sas2ircu":
                Contid = self.Sas()
            ContInfoList = pciDict[raidcmd]
            for cont in ContInfoList:
                for c in Contid:
                    if c.get('pci') == cont.get('PCI'):
                        cont['ContId'] = c.get("contid")
                ControllerDict[raidcmd].append(cont)

        Controllerjs = open(f, "w")
        json.dump(ControllerDict, Controllerjs)
        Controllerjs.close()
        return ControllerDict

    def PciInfo(self):
        ControllerDict = {}
        cmd = "sudo lspci |grep -E 'Adaptec|MegaRAID|SAS'|awk '{print $1}'"
        for pci in os.popen(cmd).readlines():
            pci = str(pci).strip("\n")
            res = {"PCI": pci}
            cmd = "sudo lspci -v -s {} ".format(str(pci))
            pciInfo = os.popen(cmd).readlines()
            for line in pciInfo:
                line = str(line).strip("\n")
                if re.search("Subsystem: ", line):
                    res["Subsystem"] = line.split(
                        "Subsystem: ")[1].strip()
                if re.search("Kernel driver in use:", line):
                    res["Kernel_driver"] = line.split(
                        "Kernel driver in use:")[1].strip()
                if re.search("Flags:", line):
                    res["Flags"] = line.split("Flags: ")[1].strip()
            if res["Kernel_driver"] == "megaraid_sas":
                res["RaidCmd"] = "megacli"
            elif res["Kernel_driver"] == "smartpqi":
                res["RaidCmd"] = "arcconf"
            elif res["Kernel_driver"] == "aacraid":
                res["RaidCmd"] = "arcconf2"
            elif res["Kernel_driver"] == "mpt2sas":
                res["RaidCmd"] = "sas2ircu"
            elif res["Kernel_driver"] == "mpt3sas":
                res["RaidCmd"] = "storcli"
            key = res["RaidCmd"]
            if key in ControllerDict.keys():
                ControllerDict[key].append(res)
            else:
                ControllerDict[key] = []
                ControllerDict[key].append(res)
        return ControllerDict

    def MegaRAID(self):
        ControllerDict = []
        getcontlist = os.popen("sudo megacli  -AdpGetPciInfo -aall").read()
        for cont in getcontlist.strip().split("PCI information for"):
            if cont and "Controller" in cont:
                res = {}
                for line in str(cont).split("\n"):
                    if re.search("Controller", line):
                        res["contid"] = line.split("Controller ")[1].strip()
                    elif re.search("Bus Number      :", line):
                        bus_num = line.split("Bus Number      : ")[1].strip()
                        if len(bus_num) == 1:
                            res["pci"] = "0{}:00.0".format(bus_num)
                        else:
                            res["pci"] = "{}:00.0".format(bus_num)
                ControllerDict.append(res)
        return ControllerDict

    def Adaptec(self):
        '''
        [{"ContId":"0","PCI":"af:00.0"}]
        '''
        ContList = []
        getcontlist = os.popen("sudo arcconf list").read()
        for cont in re.findall("Controller \d+:", getcontlist):
            ContId = re.findall("\d", cont)[0]
            getcontinfo = os.popen(
                "sudo arcconf getconfig %s ad" % (ContId)).read()
            res = {"contid": ContId}
            for line in str(getcontinfo).split("\n"):
                if re.search("PCI Address", line):
                    PCI = line.split(":")[-3].strip()
                    # PCI = re.findall("PCI Address.*", getcontinfo)[0].split(":")[-3].strip()
                    if len(PCI) == 1:
                        res["pci"] = ("0%s:00.0" % (PCI))
                    else:
                        res["pci"] = ("%s:00.0" % (PCI))
            ContList.append(res)
        print(json.dumps(ContList))
        return ContList

    def Adaptec2(self):
        ContList = []
        ContId = 0
        ret = os.popen("sudo lspci|grep -i Adaptec").read()
        for cont in re.findall(".*SAS/PCIe 2.*", ret):
            ContId = ContId + 1
            PCI = re.split(":", cont)[0]
            continfo = {}
            continfo["contid"] = ContId
            if len(PCI) == 1:
                continfo["pci"] = ("0%s:00.0" % (PCI))
            else:
                continfo["pci"] = ("%s:00.0" % (PCI))
            ContList.append(continfo)
        return ContList

    def Sas(self):
        ContList = []
        try:
            getcontlist = os.popen(
                "sudo sas2ircu list|grep -i '^ *[0-9]'").read().strip()
            for cont in re.split("\n", getcontlist):
                continfo = {}
                continfo["contid"] = cont.split()[0]
                pciinfo = cont.split()[4]
                PCI = re.split("h:", pciinfo)[1]
                if len(PCI) == 1:
                    continfo["pci"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["pci"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
            self.ContList = ContList
        except Exception:
            ContId = -1
            ret = os.popen("sudo lspci|grep -i SAS").read()
            for cont in re.findall(".*SAS.*", ret):
                ContId = ContId + 1
                PCI = re.split(":", cont)[0]
                continfo = {}
                continfo["contid"] = ContId
                if len(PCI) == 1:
                    continfo["pci"] = ("0%s:00.0" % (PCI))
                else:
                    continfo["pci"] = ("%s:00.0" % (PCI))
                ContList.append(continfo)
        return ContList


######################################################
#  数据获取
######################################################
# 数据记录
def saveFile(data, output=False):
    PDList = data.get('PDList')
    VDList = data.get('VDList')

    if not os.path.exists(proc_dir):
        os.mkdir(proc_dir)
    OsCmd("sudo chmod 777 %s" % (proc_dir)).data()
    OsCmd("sudo chmod 666 %s/*" % (proc_dir)).data()

    # 保存vd pd 相关信息
    diskinfofile = open(config["diskinfofilejs"], "w")
    json.dump(data, diskinfofile)
    diskinfofile.close()

    # 保存pd和挂载点,磁盘信息
    pdinfo = copy.deepcopy(PDList)
    for vid in humanSort(VDList):
        vd = VDList[vid]
        pds = vd.get("PDs")
        for p in pds:
            pd = copy.deepcopy(p)
            pd["Mount"] = vd["Mount"]
            pd["diskName"] = vd["diskName"]
            pd["VD"] = vid
            pd["VDTYPE"] = vd["TYPE"]
            pd["VDSIZE"] = vd["Size"]
            pdinfo[pd["ACD"]] = pd
    pdinfofile = open(config["pdinfofilejs"], "w")
    json.dump(list(pdinfo.values()), pdinfofile)
    pdinfofile.close()
    if output:
        print(json.dumps(list(pdinfo.values()), indent=4))


# 获取raid卡类型
def getRaidtype():
    # 获取raid卡型号
    try:
        getPci = OsCmd(
            'sudo lspci |grep -i -E  " SAS|Adaptec|LSI|Gen9|raid"').data()
    except Exception:
        raise RaidError(
            "The raid card model is not suitable, or there is no raid card", "127")
    Kernel_drivers = []
    pciList = getPci.split('\n')
    for pci in pciList:
        pci_id = pci.split(" ")[0]
        kernel_driver = OsCmd(
            "sudo lspci -v -s %s |awk  -F ':' '/Kernel driver in use/{ print $NF }'" % (pci_id)).data()
        Kernel_drivers.append(kernel_driver)

    driver = list(set(Kernel_drivers))
    if "MegaRAID" in getPci or "megaraid_sas" in driver:
        raidType = "megacli"
    elif ('Adaptec' in getPci and "PCIe 2" in getPci) or "aacraid" in driver:
        raidType = "arcconf2"
    elif 'Adaptec' in getPci or "smartpqi" in driver:
        raidType = "arcconf"
    elif 'LSI' in getPci or "mpt2sas" in driver:
        raidType = "sas2icu"
    elif 'Gen9' in getPci:
        raidType = "ssacli"
    elif "mpt3sas" in driver:
        raidType = "storcli"
        raise RaidError(
            "storcli Unadapted", "127")
    else:
        raise RaidError("other err", "124")
    return raidType


# 获取vd pd等输出信息
def get_vd_pd_info(output=False):
    raidType = getRaidtype()
    data = {}
    if raidType == "megacli":
        raid = MegaCli()
    elif raidType == "arcconf2":
        raid = Arcconf2()
    elif raidType == "arcconf":
        raid = Arcconf()
    elif raidType == "sas2icu":
        raid = Sas2icu()
    elif raidType == "ssacli":
        raid = Ssacli()
    else:
        raise RaidError(
            "The raid card model is not suitable, or there is no raid card", "127")

    # 获取信息
    if not raid.VDList:
        VDList = raid.get_VD_List()
    else:
        VDList = raid.VDList
    if not raid.PDList:
        PDList = raid.get_PD_List()
    else:
        PDList = raid.PDList
    # 获取不在vd重点pd
    OtherPdList = {}
    vdpd = []
    for vdinfo in humanSort(VDList):
        vd = VDList[vdinfo]
        for pd in vd["PDs"]:
            vdpd.append(pd["ACD"])
    for key in humanSort(PDList):
        pd = PDList[key]
        if pd["ACD"] not in vdpd:
            OtherPdList[pd["ACD"]] = pd

    data["VDList"] = VDList
    data["PDList"] = PDList
    data["OtherPdList"] = OtherPdList
    data["raidType"] = raidType
    saveFile(data, output=output)
    return data


######################################################
#  功能
######################################################
# 故障盘亮灯
def faultOnBlink():
    data = get_vd_pd_info()
    PDList = data.get('PDList')
    VDList = data.get('VDList')
    OtherPdList = data.get('OtherPdList')
    Blink = AutoBlink()
    pdAutoBlinkList = Blink.pdAutoBlink(VDList, OtherPdList)
    DropDiskAutoBlinkList = Blink.DropDiskAutoBlink(PDList)
    pdBlinkNum = []
    if pdAutoBlinkList:
        print("以下《 %s 》块盘故障, 更换时请按照硬件变更工单进行更换。" % (len(pdAutoBlinkList)))
        for pd in pdAutoBlinkList:
            Blink.onBlink(acd=pd.get("ACD"), pd=pd)
            pdBlinkNum.append(pd.get("ACD"))

    # 判断其他pd报错,例如掉盘进行亮灯
    if DropDiskAutoBlinkList:
        print("以下盘, slot号不连续,中间有掉盘, 两侧灯已亮, 更换中间一块,更换前请灭灯确认")
        for pd in DropDiskAutoBlinkList:
            Blink.onBlink(pd["ACD"])
            pdBlinkNum.append(pd.get("ACD"))

    if not pdBlinkNum:
        print("不满足自动亮灯要求,请人工进行亮灯")
    # 记录自动亮灯信息
    blinkfile = open("/tmp/diskerr/blink", "w")
    json.dump(pdBlinkNum, blinkfile)
    blinkfile.close()
    OsCmd("sudo chmod 666 /tmp/diskerr/*").data()


# 自助亮灯
def onBlink(acd):
    Blink = AutoBlink()
    Blink.onBlink(acd)


# 故障盘灭灯
def faultOffBlink():
    if os.path.exists("/tmp/diskerr/blink"):
        blinkfile = open("/tmp/diskerr/blink", "r")
        blink = json.load(blinkfile)
        blinkfile.close()
        if blink:
            Blink = AutoBlink()
            for pd in blink:
                acd = str(pd)
                Blink.offBlink(acd)
        else:
            print("无自动亮灯的盘, 无法进行自动灭灯")
    else:
        print("非自动亮灯, 无法自动灭灯")
        exit(0)


# 自助灭灯
def offBlink(acd):
    Blink = AutoBlink()
    Blink.offBlink(acd)


# 记录可以更换的报错盘信息,用于判断更换了那块盘
def recordPdErr():
    data = get_vd_pd_info()
    PDList = data.get('PDList')
    VDList = data.get('VDList')
    OtherPdList = data.get('OtherPdList')
    Blink = AutoBlink()
    pdAutoBlinkList = Blink.pdAutoBlink(VDList, OtherPdList)
    DropDiskAutoBlinkList = Blink.DropDiskAutoBlink(PDList)
    model = ""
    for pd in DropDiskAutoBlinkList:
        if pd["Model"] == model:
            pdAutoBlinkList.append(pd)
            model == pd["Model"]
    if os.path.exists(config["replacefile"]):
        OsCmd("cp %s %s" % (config["replacefile"],
              config["replaceagofile"])).data()
    replacefile = open(config["replacefile"], "w")
    json.dump(pdAutoBlinkList, replacefile)
    replacefile.close()


# 日常巡检
class inspect():
    def __init__(self, cmdtype="nss"):
        self.inspect(cmdtype)
        pass

    # 巡检舒服报错信息
    def inspect(self, cmdtype):
        # 巡检
        dict = get_vd_pd_info()
        PDList = dict.get('PDList')
        VDList = dict.get('VDList')
        OtherPdList = dict.get('OtherPdList')
        raidType = dict["raidType"]

        msg = {"state": 0, "media_err": 0, "other_err": 0,
               "failuer": 0, "wearout": 100, "dropDiskNum": 0, "erradd": 0, "errtotal": 0}
        FaultDisk = FaultDiskInfo()
        vd_msg, vd_data = FaultDisk.getFaultVirDisk(VDList)
        pd_msg, pd_data = FaultDisk.getFailedPD(OtherPdList)
        dD_msg, dD_data = FaultDisk.getDropDisk(PDList)
        # errtotal
        msg["errtotal"] = int(vd_msg["errtotal"]) + int(pd_msg["errtotal"])
        # 状态
        msg["state"] = int(vd_msg["state"]) + int(pd_msg["state"])
        # media_err
        if int(vd_msg["media_err"]) > int(pd_msg["media_err"]):
            msg["media_err"] = int(vd_msg["media_err"])
        else:
            msg["media_err"] = int(pd_msg["media_err"])
        # other_err
        if int(vd_msg["other_err"]) > int(pd_msg["other_err"]):
            msg["other_err"] = int(vd_msg["other_err"])
        else:
            msg["other_err"] = int(pd_msg["other_err"])
        # failuer"
        if int(vd_msg["failuer"]) > int(pd_msg["failuer"]):
            msg["failuer"] = int(vd_msg["failuer"])
        else:
            msg["failuer"] = int(pd_msg["failuer"])
        # wearout"
        if int(vd_msg["wearout"]) < int(pd_msg["wearout"]):
            msg["wearout"] = int(vd_msg["wearout"])
        else:
            msg["wearout"] = int(pd_msg["wearout"])
        # 掉盘
        msg["dropDiskNum"] = int(dD_msg["dropDiskNum"])
        
        data = {"VD": vd_data, "PD": pd_data, "dropPD": dD_data, "msg": msg}

        # 判断报错值是否进行增加
        msg["erradd"] = self.errReport(data)
        if cmdtype == "nss":
            # 巡检输出报错信息
            print("==check_disk")
            print("state=%d,mediaErr=%d,otherErr=%d,failuer=%d,dropDiskNum=%d,erradd=%d,wearout=%d" % (
                msg["state"], msg["media_err"], msg["other_err"], msg["failuer"], msg["dropDiskNum"], msg["erradd"], msg["wearout"]))
            print("raid: %s" % (raidType))
        
        if data.get("VD"):
            for vid in data.get("VD"):
                vd = data["VD"][vid]
                print("\n%s  %s Disk failure. The failure information is as follows:" % (
                    vd["diskName"], vd["Mount"]))
                FormatOutput().vdout(vd)

        if data.get("PD"):
            for pid in data.get("PD"):
                pd = data["PD"][pid]
                print("\n%s 物理盘有报错,报错信息如下: " % (pd["ACD"]))
                FormatOutput().pdout(pd)

        if data.get("dropPD"):
            print("\n以下盘槽位号不连续,中间可能有掉盘:")
            for pid in data.get("dropPD"):
                pd = data["dropPD"][pid]
                FormatOutput().pdout(pd)
        if cmdtype != "nss":
            if data.get("VD") or data.get("VD") or data.get("dropPD"):
                exit(1)

    # 判断故障是否累加
    def errReport(self, data):
        # 保存故障盘信息
        erradd = 0
        try:
            # 保存报错信息
            new_pd_errf = config["pderrfile"] + "." + \
                datetime.date.today().strftime('%Y%m%d')
            pderrfile = open(new_pd_errf, "w")
            json.dump(data, pderrfile)
            pderrfile.close()

            # 删除10天前的文件
            deldate = (datetime.datetime.today() - datetime.timedelta(days=10))
            fileDateList = OsCmd(
                "ls %s*|awk -F '.' '/pderr/{print $2}'|sort -n" % (config["pderrfile"])).data().split("\n")
            for d in fileDateList:
                if parse_time(d) < deldate:
                    delfile = config["pderrfile"] + "."+d
                    os.remove(delfile)
                else:
                    break

            # 读取以前的报错pd
            old_data_file = config["pderrfile"] + "." + (
                datetime.date.today() - datetime.timedelta(days=7)).strftime("%Y%m%d")
            if os.path.exists(old_data_file):
                old_data_js = open(old_data_file, "r")
                old_data = json.load(old_data_js)
                old_data_js.close()
            else:
                old_data = {}

            # 判断报错信息是否增加
            if data.get("msg") and old_data.get("msg"):
                # 如果以上都不为空
                errtotal = data.get("msg").get("errtotal")
                old_errtotal = old_data.get("msg").get("errtotal")
                if int(errtotal) > int(old_errtotal):
                    erradd = int(errtotal) - int(old_errtotal)
                    return erradd
        except Exception:
            pass
            # raise RaidError("{} command ERR".format(self.cmd), "125")
        return erradd


# 查看所有盘数据
def checkDisk():
    dict = get_vd_pd_info()
    VDList = dict.get('VDList')
    OtherPdList = dict.get('OtherPdList')
    forOut = FormatOutput()
    for vdinfo in humanSort(VDList):
        vd = VDList[vdinfo]
        forOut.vdout(vd, sign=True)

    if OtherPdList:
        print("== == ==  未做raid的盘 == == ==")
        for key in humanSort(OtherPdList):
            pd = OtherPdList[key]
            forOut.pdout(pd)


# 获取磁盘详细信息,输出json
def diskDetail():
    get_vd_pd_info(output=True)


# 删除vd
def deleteVD(AV=''):
        # print(re.findall("/a\\d+/c\\d+I\\d+/d\\d+", acd))
    if not AV:
        raise RaidError("Please enter the correct VD number", "127")
    elif not re.findall("/a\\d+/v\\d+", AV):
        raise RaidError(
            "Please enter the correct VD number format: /a0/v1", "127")
    
    raidType = getRaidtype()
    aid = re.findall("/a\\d+", AV)[0].replace("/a", '').strip()
    vid = re.findall("/v\\d+", AV)[0].replace("/v", '').strip()
    
    VDList={} 
    if os.path.exists(config["diskinfofilejs"]):
        oneDayAgo = (datetime.datetime.today() - datetime.timedelta(days=10))
        fileModificationTime =datetime.datetime.fromtimestamp(os.stat(config["diskinfofilejs"]).st_mtime)    
        if fileModificationTime >= oneDayAgo :
            f = open(config["diskinfofilejs"], "r")
            diskinfo = humanJson.load(f)
            f.close()
            VDList = diskinfo.get("VDList", {})
        else:
            data = get_vd_pd_info()
            VDList = data.get('VDList',{})
    else:
        data = get_vd_pd_info()
        VDList = data.get('VDList',{})
    if str(AV) not in VDList:
        print("未找到此VD信息,请人工确认")
        exit(0)
    vdinfo = VDList.get(AV)
    if vdinfo.get("Mount") is None:
        if raidType == "megacli":
            ret = OsCmd(" sudo megacli -cfglddel -l%s -a%s" % (vid, aid)).data()
            print(ret)
        else:
            print("未适配自动亮灯")
            exit(0)
    else:
        print("指定vd包含有挂载点")


if __name__ == "__main__":
    try:
        try:
            import argparse
            parser = argparse.ArgumentParser()
            # 创建互斥组,是命令每次只能输入一个选项
            group = parser.add_mutually_exclusive_group()
            group.add_argument("-i", '--inspect', dest='inspect', required=False,
                               action='store_true', default="True", help="默认选项, 输出==check_disk故障信息")
            group.add_argument("-I", '--inspecttype', dest='inspecttype',
                               action='store_true', help="输出故障信息")
            group.add_argument("-c", '--checkdisk', dest='checkdisk',
                               action='store_true', help="输出所有的pd和vd信息")
            group.add_argument("-o", '--onblink', metavar="/an/cn/dn", nargs="?",
                               default="False", type=str, help="进行亮灯, 当不指定参数时只进行故障盘亮灯, 指定参数时进行指定的盘亮灯.")
            group.add_argument("-f", '--offblink', metavar="/an/cn/dn", nargs="?",
                               default="False", type=str, help="进行灭灯, 当不指定参数时只灭自动亮的灯, 指定参数时进行指定盘灭灯.")
            group.add_argument("-r", '--recordpderr', dest='record',
                               action='store_true', help="记录报错盘信息")
            group.add_argument("-d", '--diskdetail', dest='diskdetail',
                               action='store_true', help="格式化输出磁盘详细信息")
            group.add_argument("-delvd", metavar="/an/vn", nargs="?", dest='deletevd',default="False", type=str, help="删除指定vd")
            args = parser.parse_args()
            # 选项参数执行的结果
            if args.checkdisk:  # -c 获取磁盘信息
                checkDisk()
                exit(0)
            elif args.record:  # -r 记录报错盘信息 
                recordPdErr()
                exit(0)
            elif args.inspecttype:  # -r 记录报错盘信息
                inspect(cmdtype="instruct")
            elif args.onblink is None:
                # print("故障盘亮灯")
                faultOnBlink()
                exit(0)
            elif args.onblink != "False":
                # print("指定的盘亮灯")
                onBlink(args.onblink)
                exit(0)
            elif args.offblink is None:
                # print("故障盘灭灯")
                faultOffBlink()
            elif args.offblink != "False":
                # print("指定的盘灭灯")
                offBlink(args.offblink)
            elif args.diskdetail:
                # 输出json
                diskDetail()
            elif args.deletevd != "False" and  args.deletevd:
                deleteVD(args.deletevd)
            elif args.inspect:
                inspect()
        except Exception:
            if len(sys.argv) == 1:
                inspect()
            elif len(sys.argv) == 2:
                opt = sys.argv[1]
                if opt == "-i":
                    inspect()
                elif opt == "-I":
                    inspect(cmdtype="instruct")
                elif opt == "-c":
                    checkDisk()
                elif opt == "-r":
                    recordPdErr()
                elif opt == "-o":
                    faultOnBlink()
                elif opt == "-f":
                    faultOffBlink()
                elif opt == "-d":
                    diskDetail()
            elif len(sys.argv) == 3:
                opt = sys.argv[1]
                par = sys.argv[2]
                print(par)
                if opt == "-o":
                    onBlink(par)
                if opt == "-f":
                    offBlink(par)
                if opt == "-delvd":
                    deleteVD(par)
            else:
                raise RaidError("Please specify correct parameters", "127")
    except Exception:
        res = {
            "code": 1,
            "msg": traceback.format_exc(),
            "data": []
        }
        print(traceback.format_exc())

 

TCP计数器

用法如下:

$ python nstat.py
{"tcpext": [{"name": "TcpExtSyncookiesSent", "value": 0}, {"name": "TcpExtListenOverflows", "value": 1211}, {"name": "TcpExtListenDrops", "value": 1211}, {"name": "TcpExtTCPTimeouts", "value": 76853}], "udp": [{"name": "UdpInDatagrams", "value": 321965497}, {"name": "UdpNoPorts", "value": 0}, {"name": "UdpOutDatagrams", "value": 322459373}], "tcp": [{"name": "TcpActiveOpens", "value": 3066741}, {"name": "TcpPassiveOpens", "value": 15037070}, {"name": "TcpAttemptFails", "value": 1189}, {"name": "TcpEstabResets", "value": 23215}, {"name": "TcpRetransSegs", "value": 126661}, {"name": "TcpInErrs", "value": 4}, {"name": "TcpOutRsts", "value": 10787}]}

完整代码如下:

#!/usr/bin/env python
# coding: utf-8
import subprocess, shlex
import re, json
from StringIO import StringIO

TCP_METRICS = ["TcpActiveOpens", "TcpPassiveOpens", "TcpAttemptFails", "TcpEstabResets",
               "TcpRetransSegs", "TcpInErrs", "TcpOutRsts"]
TCPEXT_METRICS = ["TcpExtTCPTimeouts", "TcpExtListenDrops", "TcpExtListenOverflows", "TcpExtSyncookiesSent"]
UDP_METRICS = ["UdpInDatagrams", "UdpOutDatagrams", "UdpNoPorts"]

def get_nstat():
    tcp_data = []
    tcpext_data = []
    udp_data = []
    cmd = "nstat -z"
    p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
    (output, err) = p.communicate()
    f = StringIO(output)
    for line in f.readlines():
        if line.startswith("#kernel"):
            continue
        metric, value, placeholder = map(str.strip, re.split('\s+', line.strip()))
        if metric in TCP_METRICS:
            tcp_data.append({"name": metric, "value": int(value)})
        elif metric in TCPEXT_METRICS:
            tcpext_data.append({"name": metric, "value": int(value)})
        elif metric in UDP_METRICS:
            udp_data.append({"name": metric, "value": int(value)})
    f.close()
    return tcp_data, tcpext_data, udp_data


if __name__ == "__main__":
    res_data = {}
    tcp_data, tcpext_data, udp_data = get_nstat()
    nss_data["tcp"] = tcp_data
    nss_data["tcpext"] = tcpext_data
    nss_data["udp"] = udp_data
    print json.dumps(res_data)