
#!/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('{}')