#!/usr/bin/env python
# coding=utf-8
from subprocess import Popen, PIPE
import re,json

# import sys

# 20171111修改删除  , 'battery': 'Battery'
_Sensor_type = {'processor': 'Processor', 'memory': 'Memory', 'fan': 'Fan', 'power': 'Power Supply',
                'disk': 'Drive Slot / Bay',
                'temperature': 'Temperature', 'voltage': 'Voltage'}

# 这三个状态不应该列入问题状态中
_State_sensor_no_problem = ['ok', 'na', 'ns']
# 这些状态代表有问题状态,并且每个状态赋予一定权重值用以区别
"""
  lnr : Lower Non-Recoverable 
  lcr : Lower Critical 
  lnc : Lower Non-Critical 
  unc : Upper Non-Critical 
  ucr : Upper Critical 
  unr : Upper Non-Recoverable 
"""
_State_sensor_with_problem = {1: ['unc', 'lnc'], 2: ['ucr', 'lcr'], 4: ['unr', 'lnr']}

_Manufacturer_Mapping_ = {'dell': ('dell',), 'inspur_nf5280': ('inspur', 'nf5280'),
                          'inspur_nf5270': ('inspur', 'nf5270'), 'sugon': ('sugon',),
                          'h3c_R4900': ('R4900',), 'hp380_server': ('380')}

# no sensor 标记
_Sensor_data_error = -2


def exec_command(command, flag=True):
    process = Popen(command, shell=flag, stdout=PIPE, stderr=PIPE)
    stdout, stderr = process.communicate()
    return stdout, stderr


def deal_ipmitool_result(result):
    # print result
    status_list = result.split('\n')  # 以换行符为分割符,结果列表
    no_sensor_flag = 1  # 无传感器标志位,如有至少一个传感器这里会变成0
    serious_count = 0  # 结果中的各类报警累加级别
    state_already_count = []  # 结果中各类报警,分别加入列表
    state_flag = True  # 如果出现其他未知的状态则赋值为false
    error_str = ''  # 本行结果
    for i in status_list:
        if '|' not in i:
            continue
        sigle_list = i.split('|')
        # ['Status           ', ' 60h ', ' ok  ', '  3.1 ', ' Presence detected']
        state = sigle_list[2].strip()  # 选择结果中每行的第三个状态用于判断是否有故障发生
        # 判断state是否为ns,若全为ns则这个type也为空
        if (state != 'ns') and (state != 'na') and (no_sensor_flag == 1):
            no_sensor_flag = 0
        # 如果state不是无问题状态,则去判断是否在问题状态中
        if state not in _State_sensor_no_problem:
            error_str += i + '\n'
            for j in _State_sensor_with_problem:
                if j in state_already_count:
                    continue
                elif state in _State_sensor_with_problem[j]:
                    serious_count += j
                    state_already_count.append(j)
                else:
                    state_flag = False  # 修改stat_flag的值
    if no_sensor_flag == 1:
        return _Sensor_data_error
    elif serious_count != 0:
        return serious_count
    elif not state_flag:  # 根据state_flag值来返回,如果state_flag为0,则
        # 20181204 位置原因导致 的返回 -2
        # return error_str
        return _Sensor_data_error
    return 0


def power_status():
    command = "sudo ipmitool power status"
    stdout, stderr = exec_command(command)
    code = _Sensor_data_error
    if stdout:
        if 'on' in stdout:
            code = 1
        elif 'off' in stdout:
            code = 0
    return code

def sel_log():
    command = "sudo ipmitool sel list"
    stdout, stderr = exec_command(command)
    if stdout:
        stdout = stdout.strip()
        lines = stdout.split('\n')
        return lines[-1]
    else:
        return ''

def get_watts_num():
    # complete_command = "%(command_dir)s -I %(interface)s -H %(ipmi_ip)s -U %(ipmi_user)s -P %(ipmi_password)s sdr | grep -i Watts" % \
    #                    {'command_dir': 'ipmitool', 'interface': g_interface, 'ipmi_ip': g_ipmi_ip,
    #                     'ipmi_user': g_username, 'ipmi_password': g_password}
    complete_command = "sudo ipmitool sdr | grep -i Watts"
    stdout, stderr = exec_command(complete_command)
    if stdout:
        pwr_dict = {}
        # <type 'list'>: ['PSU1_PWR_IN      | 236 Watts         | ok', 'PSU1_PWR_OUT     | 240 Watts         | ok',
        # 'PSU2_PWR_IN      | 244 Watts         | ok', 'PSU2_PWR_OUT     | 252 Watts         | ok']
        pwr_list = stdout.split('\n')[:-1]
        pwr_result = 0
        if len(pwr_list) == 1:
            pwr_result = re.search(r'(\d+)\s*Watts', pwr_list[0], re.IGNORECASE).group(1)
        elif re.search(r'total', stdout, re.IGNORECASE):
            for i in pwr_list:
                if re.search(r'total', i, re.IGNORECASE):
                    pwr_result = int(re.search(r'(\d+)\s*Watts', i, re.IGNORECASE).group(1))
        elif len(pwr_list) == 2:
            for i in pwr_list:
                # print re.search(r'(\d+)\s*Watts', i, re.IGNORECASE).group(1)
                pwr_result += int(re.search(r'(\d+)\s*Watts', i, re.IGNORECASE).group(1))

    return pwr_result

def get_manufacturer():
    try:
        complete_command = "%(command_dir)s  fru|grep -E 'Product Manufacturer|Product Name'" % \
                           {'command_dir': 'sudo ipmitool'}
        stdout, stderr = exec_command(complete_command)
        if stdout:
            for i in _Manufacturer_Mapping_.keys():
                # 标记是否匹配到了相关关键字
                total_match = True
                # 遍历所有关键字一一匹配
                for item in _Manufacturer_Mapping_[i]:
                    retem = re.search(item, stdout, re.IGNORECASE)
                    if retem:
                        pass
                    else:  # 如果没有匹配到,则修改标记
                        total_match = False
                if total_match:
                    return True, i
        elif stderr:
            return False, stderr
    except Exception as e:
        return False, e


# g_username, g_password, g_ipmi_ip, g_interface='lanplus'
class base_server:
    def __init__(self):
        self.base_type = _Sensor_type.keys()

    # 选择使用哪种方式获取ipmi数据,如果在bsaetype中则使用常规方式,
    # 其他类型选择其他方式获取(各个子类中完成)
    def choose_geter(self, item_type):
        if item_type in self.base_type:
            return self.base_get_sensor_data(item_type)
        else:
            return _Sensor_data_error

    # 常规方法获取传感器数据
    def base_get_sensor_data(self, item_type):
        try:
            sensor_command_type = _Sensor_type[item_type]
            complet_command = "%(command_dir)s  sdr type '%(s_type)s' " % \
                              {'command_dir': 'sudo ipmitool', 's_type': sensor_command_type}
            stdout, stderr = exec_command(complet_command)
            if (not stdout) and (not stderr):
                return _Sensor_data_error

            if stderr:
                # 20181204 修改返回值,返回-2
                # return 'ipmitool error'
                return _Sensor_data_error
            return deal_ipmitool_result(stdout)
        except Exception as e:
            return _Sensor_data_error


class dell_server(base_server):
    pass


class inspur_server(base_server):
    def __init__(self):
        self.base_type = _Sensor_type.keys()
        self.additional_type = {'all_state': 'sdr | grep All_Unit_Status'}

    def choose_geter(self, item_type):
        if item_type in self.base_type:
            return self.base_get_sensor_data(item_type)
        elif item_type in self.additional_type:
            return self.additional_get_sensor_data(item_type)
        else:
            return _Sensor_data_error
            # 如果都没有那么返回no sensor

    def additional_get_sensor_data(self, item_type):
        sensor_command = "%(command_dir)s  %(s_type)s " % \
                         {'command_dir': 'sudo ipmitool', 's_type': self.additional_type[item_type]}
        stdout, stderr = exec_command(sensor_command)
        if stdout:
            return deal_ipmitool_result(stdout)
        elif stderr:
            # return False, 'ipmitool error'
            return 7
        elif (not stdout) and (not stderr):
            # return True, 'no sensor'
            return _Sensor_data_error


class sugon_server(base_server):
    def __init__(self):
        self.base_type = _Sensor_type.keys()
        self.additional_type = {'pci_health': "raw 0x3a 0x0a 2 | awk '{print $12}'",
                                'all_state': "raw 0x30 0x23 0x3c 0x00 0x00"}

    def choose_geter(self, item_type):
        if item_type in self.base_type:
            return self.base_get_sensor_data(item_type)
        elif item_type in self.additional_type:
            if item_type == 'pci_health':
                return self.get_allstate_or_pci_sensor_data(item_type)
            elif item_type == 'all_state':
                return self.get_allstate_or_pci_sensor_data(item_type)
        else:
            # return True, 'no sensor'
            return _Sensor_data_error
            # 如果都没有那么返回no sensor

    def get_allstate_or_pci_sensor_data(self, item_type):
        sensor_command = "%(command_dir)s  %(s_type)s " % \
                         {'command_dir': 'sudo ipmitool', 's_type': self.additional_type[item_type]}
        stdout, stderr = exec_command(sensor_command)
        if stdout:
            if '01' in stdout:
                # return True, 'ok'
                return 0
            else:
                # return True, 'problem'
                return 7
        elif stderr:
            # return 'ipmitool error'
            # 20181204 返回数据 -2
            return _Sensor_data_error
        elif (not stdout) and (not stderr):
            return _Sensor_data_error


class h3c_r4900_server:
    def __init__(self):
        self.sensor_type = {'processor': 13, 'memory': 12, 'fan': 8, 'power': 7, 'disk': 9,
                            'temperature': 5, 'voltage': 6, 'battery': -1, 'all_state': 4, 'pci_health': 14}

    def choose_geter(self, item_type):
        if item_type in self.sensor_type:
            return self.get_sensor_data(item_type)
        else:
            return _Sensor_data_error

    def deal_stat(self, state, content):
        try:
            # 从get_sensor_data中获得的返回值中,其中返回state为ok:1,返回problem:0
            # 返回 函数中出错:3,本函数异常:3
            # state, content = get_sensor_data(item_type=d_item_type)
            if state:
                if content == 'ok':
                    return 0
                elif content == 'problem':
                    return 7
                elif content == 'no sensor':
                    return _Sensor_data_error
            else:
                # 20181204 返回数据 -2
                return _Sensor_data_error
        except Exception as e:
            return _Sensor_data_error

    # 获取sensor的实时数据
    def get_sensor_data(self, item_type):
        try:
            complet_command = "%(command_dir)s  raw 0x36 0x05 0x20 0x14 0x00 0x0a " % \
                              {'command_dir': 'sudo ipmitool'}
            process = Popen(complet_command, stdout=PIPE, stderr=PIPE, shell=True)

            stdout, stderr = process.communicate()
            if stdout:
                stdout = stdout.strip()
                stdout = stdout.rstrip('\n')

            elif stderr:
                return _Sensor_data_error

            elif (not stdout) and (not stderr):
                return _Sensor_data_error
            res_list = stdout.split()
            if len(res_list) == 14:
                if self.sensor_type[item_type] != -1:
                    state = res_list[self.sensor_type[item_type] - 1]
                    if state == '00':
                        return self.deal_stat(True, 'ok')
                    else:
                        return self.deal_stat(True, 'problem')
                else:
                    return self.deal_stat(True, 'no sensor')
        except Exception as e:
            return self.deal_stat(False, str(e))


class hp380_server(base_server):
    pass


_Class_mapping_ = {'dell': dell_server, 'inspur_nf5280': inspur_server, 'inspur_nf5270': inspur_server,
                   'sugon': sugon_server,
                   'h3c_R4900': h3c_r4900_server,
                   'hp380_server': hp380_server,
                   'base': base_server
                   }

if __name__ == '__main__':
    props = {"all_state", "disk", "fan", "memory", "pci_health", "power", "processor", "temperature", "voltage"}
    state, device = get_manufacturer()
    if state:
        a = _Class_mapping_[device]()
        states = {"cpname":"hardware_monitor"}
        for prop in props:
            states[prop] = a.choose_geter(prop)
        states["power_status"] = power_status()
        states["sel_log_last_line"] = sel_log()
        states["watts"] = get_watts_num()
        print(json.dumps(states))
    else:
        print('{}')

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

Captcha Code