Files
openGauss-OM/script/base_utils/os/dmidecode_util.py
2023-11-10 09:53:14 +08:00

249 lines
7.0 KiB
Python

# -*- coding:utf-8 -*-
#############################################################################
# Copyright (c) 2023 Huawei Technologies Co.,Ltd.
#
# openGauss is licensed under Mulan PSL v2.
# You can use this software according to the terms
# and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#
# http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS,
# WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
# ----------------------------------------------------------------------------
# Description : Provides a series of methods for parsing 'dmidecode'.
#############################################################################
import subprocess
from enum import Enum
from base_utils.os.cmd_util import CmdUtil
from gspylib.common.ErrorCode import ErrorCode
class DMIType(Enum):
BIOS = 0
SYSTEM = 1
BASEBOARD = 2
CHASSIS = 3
PROCESSOR = 4
MEMORY_CONTROLLER = 5
MEMORY_MODULE = 6
CACHE = 7
PORT_CONNECTOR = 8
SYSTEM_SLOTS = 9
ON_BOARD_DEVICES = 10
OEM_STRINGS = 11
SYSTEM_CONFIGURATION_OPTIONS = 12
BIOS_LANGUAGE = 13
GROUP_ASSOCIATIONS = 14
SYSTEM_EVENT_LOG = 15
PHYSICAL_MEMORY_ARRAY = 16
MEMORY_DEVICE = 17
BIT_MEMORY_ERROR_32_BIT = 18
MEMORY_ARRAY_MAPPED_ADDRESS = 19
MEMORY_DEVICE_MAPPED_ADDRESS = 20
BUILT_IN_POINTING_DEVICE = 21
PORTABLE_BATTERY = 22
SYSTEM_RESET = 23
HARDWARE_SECURITY = 24
SYSTEM_POWER_CONTROLS = 25
VOLTAGE_PROBE = 26
COOLING_DEVICE = 27
TEMPERATURE_PROBE = 28
ELECTRICAL_CURRENT_PROBE = 29
OUT_OF_BAND_REMOTE_ACCESS = 30
BOOT_INTEGRITY_SERVICES = 31
SYSTEM_BOOT = 32
MEMORY_ERROR_64_BIT = 33
MANAGEMENT_DEVICE = 34
MANAGEMENT_DEVICE_COMPONENT = 35
MANAGEMENT_DEVICE_THRESHOLD_DATA = 36
MEMORY_CHANNEL = 37
IPMI_DEVICE = 38
POWER_SUPPLY = 39
ADDITIONAL_INFORMATION = 40
ONBOARD_DEVICES_EXTENDED_INFORMATION = 41
MANAGEMENT_CONTROLLER_HOST_INTERFACE = 42
class DMITypeCategory(Enum):
BIOS = 'bios'
SYSTEM = 'system'
BASEBOARD = 'baseboard'
CHASSIS = 'chassis'
PROCESSOR = 'processor'
MEMORY = 'memory'
CACHE = 'cache'
CONNECTOR = 'connector'
SLOT = 'slot'
class DMIDevice(object):
def __init__(self, src):
self.src = src
self.handle = 'Unknown'
self.dmi_type = 'Unknown'
self.name = 'Unknown'
self.title = 'Unknown'
self.attrs = {}
self._key = None
self._parse()
def __str__(self):
return self.src
def __getitem__(self, item):
return self.attrs.get(item)
def _parse(self):
def _get_level(_line):
if _line.strip() == '':
return -1
_level = 0
for i in range(0, len(_line)):
if _line[i] == '\t':
_level += 1
else:
break
return _level
lines = self.src.split('\n')
for line in lines:
level = _get_level(line)
if level == -1:
continue
elif level == 1:
self._parseAttr(line)
elif level == 2:
self._appendAttrVal(line)
elif line.startswith('Handle'):
self._parseHandle(line)
elif line.find('Information'):
self._parseTitle(line)
elif line.find('Table at') or line.find('End Of Table'):
pass
else:
print('ERROR, UNKNOWN DMIDECODE INFO:', line)
assert False
def _parseHandle(self, line):
# Handle 0x0401, DMI type 4, 48 bytes
assert line.startswith('Handle')
parts = line[:-1].split(',')
self.handle = parts[0].split(' ')[1]
self.dmi_type = parts[1].split(' ')[2]
def _parseTitle(self, line):
self.title = line
self.name = line[:-11]
def _parseAttr(self, line):
parts = line.split(':')
key = parts[0].strip()
value = ':'.join(parts[1:]).strip()
self.attrs[key] = value
self._key = key
def _appendAttrVal(self, line):
if not isinstance(self.attrs[self._key], list):
self.attrs[self._key] = []
self.attrs[self._key].append(line.strip())
class DmiDecodeTable(object):
def __init__(self, src):
self.src = src
self.version = None
self.devices = []
self._iter = 0
self._parse()
def __iter__(self):
self._idx = 0
return self
def __next__(self):
if self._iter >= len(self.devices):
self._iter = 0
raise StopIteration
res = self.devices[self._iter]
self._iter += 1
return res
def _parse(self):
lines = self.src.split('\n')
is_first_part = True
tmp = ''
for line in lines:
if line.strip() == '':
if is_first_part:
is_first_part = False
pass # ignore parse version
else:
self.devices.append(DMIDevice(tmp))
tmp = ''
continue
tmp += (line + '\n')
def __str__(self):
return self.src
class DmidecodeUtil(object):
@staticmethod
def getDmidecodeTableByType(dmitype=None):
"""
execute dmidecode [-t type] and get the parsed result: DmiDecodeTable.
:param dmitype: dmi type. None | int | str | DMIType | DMITypeCategory
:return: DmiDecodeTable
"""
if dmitype is None:
cmd = CmdUtil.getDmidecodeCmd()
elif isinstance(dmitype, DMIType) or isinstance(dmitype, DMITypeCategory):
cmd = f'{CmdUtil.getDmidecodeCmd()} -t {dmitype.value} '
elif isinstance(dmitype, int) or isinstance(dmitype, str):
cmd = f'{CmdUtil.getDmidecodeCmd()} -t {dmitype} '
else:
assert False
status, output = subprocess.getstatusoutput(cmd)
if status != 0:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % str(output))
return DmiDecodeTable(output)
@staticmethod
def getDmidecodeTable():
"""
execute dmidecode and get the parsed result: DmiDecodeTable.
:return: DmiDecodeTable
"""
return DmidecodeUtil.getDmidecodeTableByType()
@staticmethod
def getDmidecodeVersion():
"""
execute dmidecode --version and get the result.
:return: dmidecode --version
"""
cmd = f'{CmdUtil.getDmidecodeCmd()} --version'
status, output = subprocess.getstatusoutput(cmd)
if status != 0:
raise Exception(ErrorCode.GAUSS_514["GAUSS_51400"] % cmd + " Error: \n%s" % str(output))
return output
if __name__ == '__main__':
dmidecode = DmidecodeUtil.getDmidecodeTable()
for item in dmidecode:
print(item)