mirror of
https://opendev.org/x/pyghmi
synced 2026-04-01 07:43:39 +00:00
Merge "Support RS160"
This commit is contained in:
@@ -27,9 +27,10 @@ import pyghmi.ipmi.events as sel
|
||||
import pyghmi.ipmi.fru as fru
|
||||
import pyghmi.ipmi.oem.generic as genericoem
|
||||
from pyghmi.ipmi.oem.lookup import get_oem_handler
|
||||
import pyghmi.ipmi.private.util as pygutil
|
||||
import pyghmi.ipmi.private.util as util
|
||||
from pyghmi.ipmi import sdr
|
||||
|
||||
|
||||
try:
|
||||
from pyghmi.ipmi.private import session
|
||||
except ImportError:
|
||||
@@ -648,18 +649,6 @@ class Command(object):
|
||||
return self._oem.get_inventory_of_component(component)
|
||||
|
||||
def _get_zero_fru(self):
|
||||
# It is expected that a manufacturer matches SMBIOS to IPMI
|
||||
# get system uuid return data. If a manufacturer does not
|
||||
# do so, they should handle either deletion or fixup in the
|
||||
# OEM processing pass. Code optimistically assumes that if
|
||||
# data is returned, than the vendor is properly using it.
|
||||
zerofru = fru.FRU(ipmicmd=self).info
|
||||
if zerofru is None:
|
||||
zerofru = {}
|
||||
guiddata = self.raw_command(netfn=6, command=0x37)
|
||||
if 'error' not in guiddata:
|
||||
zerofru['UUID'] = pygutil.decode_wireformat_uuid(
|
||||
guiddata['data'])
|
||||
# Add some fields returned by get device ID command to FRU 0
|
||||
# Also rename them to something more in line with FRU 0 field naming
|
||||
# standards
|
||||
@@ -668,8 +657,21 @@ class Command(object):
|
||||
device_id['Device Revision'] = device_id.pop('device_revision')
|
||||
device_id['Manufacturer ID'] = device_id.pop('manufacturer_id')
|
||||
device_id['Product ID'] = device_id.pop('product_id')
|
||||
|
||||
zerofru = fru.FRU(ipmicmd=self).info
|
||||
if zerofru is None:
|
||||
zerofru = {}
|
||||
zerofru.update(device_id)
|
||||
return self._oem.process_fru(zerofru)
|
||||
zerofru = self._oem.process_zero_fru(zerofru)
|
||||
# If uuid is not returned in OEM processing,
|
||||
# then it is expected that a manufacturer matches SMBIOS to IPMI
|
||||
# get system uuid return data.
|
||||
if 'UUID' not in zerofru:
|
||||
guiddata = self.ipmicmd.raw_command(netfn=6, command=0x37)
|
||||
if 'error' not in guiddata:
|
||||
zerofru['UUID'] = util.\
|
||||
decode_wireformat_uuid(guiddata['data'])
|
||||
return zerofru
|
||||
|
||||
def get_inventory(self):
|
||||
"""Retrieve inventory of system
|
||||
|
||||
@@ -396,3 +396,6 @@ class OEMHandler(object):
|
||||
:param uid: User ID.
|
||||
"""
|
||||
return False
|
||||
|
||||
def process_zero_fru(self, zerofru):
|
||||
return self.process_fru(zerofru)
|
||||
|
||||
@@ -26,6 +26,17 @@ cpu_fields = (
|
||||
valuefunc=lambda v: str(v) + " MHz"),
|
||||
inventory.EntryField("Reserved", "h", include=False))
|
||||
|
||||
cpu_cmd = {
|
||||
"lenovo": {
|
||||
"netfn": 0x06,
|
||||
"command": 0x59,
|
||||
"data": (0x00, 0xc1, 0x01, 0x00)},
|
||||
"asrock": {
|
||||
"netfn": 0x3a,
|
||||
"command": 0x50,
|
||||
"data": (0x01, 0x01, 0x00)},
|
||||
}
|
||||
|
||||
|
||||
def parse_cpu_info(raw):
|
||||
return inventory.parse_inventory_category_entry(raw, cpu_fields)
|
||||
@@ -36,10 +47,6 @@ def get_categories():
|
||||
"cpu": {
|
||||
"idstr": "CPU {0}",
|
||||
"parser": parse_cpu_info,
|
||||
"command": {
|
||||
"netfn": 0x06,
|
||||
"command": 0x59,
|
||||
"data": (0x00, 0xc1, 0x01, 0x00)
|
||||
}
|
||||
"command": cpu_cmd
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,17 @@ dimm_fields = (
|
||||
inventory.EntryField("reserved", "h", include=False)
|
||||
)
|
||||
|
||||
dimm_cmd = {
|
||||
"lenovo": {
|
||||
"netfn": 0x06,
|
||||
"command": 0x59,
|
||||
"data": (0x00, 0xc1, 0x02, 0x00)},
|
||||
"asrock": {
|
||||
"netfn": 0x3a,
|
||||
"command": 0x50,
|
||||
"data": (0x01, 0x02, 0x01)},
|
||||
}
|
||||
|
||||
|
||||
def parse_dimm_info(raw):
|
||||
return inventory.parse_inventory_category_entry(raw, dimm_fields)
|
||||
@@ -42,11 +53,7 @@ def get_categories():
|
||||
"dimm": {
|
||||
"idstr": "DIMM {0}",
|
||||
"parser": parse_dimm_info,
|
||||
"command": {
|
||||
"netfn": 0x06,
|
||||
"command": 0x59,
|
||||
"data": (0x00, 0xc1, 0x02, 0x00)
|
||||
},
|
||||
"command": dimm_cmd,
|
||||
"workaround_bmc_bug": True
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,19 +33,69 @@ firmware_fields = (
|
||||
inventory.EntryField("WIND", "16s"),
|
||||
inventory.EntryField("DIAG", "16s"))
|
||||
|
||||
asrock_firmware_fields = (
|
||||
inventory.EntryField("Major Firmware Revision", "B"),
|
||||
inventory.EntryField("Minor Firmware Revision", "B"),
|
||||
inventory.EntryField("Auxiliary Firmware Revision", "4s"))
|
||||
|
||||
def parse_firmware_info(raw, bios_versions=None):
|
||||
bytes_read, data = inventory.parse_inventory_category_entry(
|
||||
raw, firmware_fields)
|
||||
del data['Revision']
|
||||
for key in data:
|
||||
yield key, {'version': data[key]}
|
||||
firmware_cmd = {
|
||||
"lenovo": {
|
||||
"netfn": 0x06,
|
||||
"command": 0x59,
|
||||
"data": (0x00, 0xc7, 0x00, 0x00)},
|
||||
"asrock": {
|
||||
"netfn": 0x3a,
|
||||
"command": 0x50,
|
||||
"data": (0x02, 0x00, 0x01)},
|
||||
}
|
||||
|
||||
if bios_versions is not None:
|
||||
yield ("Bios_bundle_ver",
|
||||
{'version': bios_versions['new_img_version']})
|
||||
yield ("Bios_current_ver",
|
||||
{'version': bios_versions['cur_img_version']})
|
||||
bios_cmd = {
|
||||
"lenovo": {
|
||||
"netfn": 0x32,
|
||||
"command": 0xE8,
|
||||
"data": (0x01, 0x01, 0x02)},
|
||||
"asrock": {
|
||||
"netfn": 0x3a,
|
||||
"command": 0x50,
|
||||
"data": (0x02, 0x01, 0x01)},
|
||||
}
|
||||
|
||||
|
||||
def parse_firmware_info(raw, bios_versions=None, asrock=False):
|
||||
fields = firmware_fields
|
||||
|
||||
if asrock:
|
||||
fields = asrock_firmware_fields
|
||||
|
||||
bytes_read, data = inventory.parse_inventory_category_entry(raw, fields)
|
||||
if asrock:
|
||||
major_version = data['Major Firmware Revision']
|
||||
minor_version = data['Minor Firmware Revision']
|
||||
# Asrock RS160 the minor version is Binary Coded Decimal,
|
||||
# convert it to Decimal
|
||||
minor_version = (0xff & (minor_version >> 4)) * 10 + \
|
||||
(0xf & minor_version)
|
||||
aux_reversion = 0
|
||||
if str(data['Auxiliary Firmware Revision']) != '':
|
||||
aux_reversion = ord(data['Auxiliary Firmware Revision'])
|
||||
|
||||
bmc_version = "%s.%s.%s" % (
|
||||
str(major_version),
|
||||
str(minor_version),
|
||||
str(aux_reversion))
|
||||
|
||||
yield ("BMC", {'version': bmc_version})
|
||||
if bios_versions is not None:
|
||||
yield ("Bios", {'version': bios_versions[0:]})
|
||||
else:
|
||||
del data["Revision"]
|
||||
for key in data:
|
||||
yield (key, {'version': data[key]})
|
||||
if bios_versions is not None:
|
||||
yield ("Bios_bundle_ver",
|
||||
{'version': bios_versions['new_img_version']})
|
||||
yield ("Bios_current_ver",
|
||||
{'version': bios_versions['cur_img_version']})
|
||||
|
||||
|
||||
def parse_bios_number(raw):
|
||||
@@ -57,20 +107,11 @@ def get_categories():
|
||||
"firmware": {
|
||||
"idstr": "FW Version",
|
||||
"parser": parse_firmware_info,
|
||||
"command": {
|
||||
"netfn": 0x06,
|
||||
"command": 0x59,
|
||||
"data": (0x00, 0xc7, 0x00, 0x00)
|
||||
}
|
||||
"command": firmware_cmd
|
||||
},
|
||||
"bios_version": {
|
||||
"idstr": "Bios Version",
|
||||
"parser": parse_bios_number,
|
||||
"command": {
|
||||
"netfn": 0x32,
|
||||
"command": 0xE8,
|
||||
"data": (0x01, 0x01, 0x02)
|
||||
}
|
||||
|
||||
"command": bios_cmd
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +123,23 @@ led_status = {
|
||||
0x00: "Off",
|
||||
0xFF: "On"
|
||||
}
|
||||
|
||||
asrock_leds = {
|
||||
"SYSTEM_EVENT": 0x00,
|
||||
"BMC_UID": 0x01,
|
||||
"LED_FAN_FAULT_1": 0x02,
|
||||
"LED_FAN_FAULT_2": 0x03,
|
||||
"LED_FAN_FAULT_3": 0x04
|
||||
}
|
||||
|
||||
asrock_led_status = {
|
||||
0x00: "Off",
|
||||
0x01: "On"
|
||||
}
|
||||
|
||||
led_status_default = "Blink"
|
||||
mac_format = '{0:02x}:{1:02x}:{2:02x}:{3:02x}:{4:02x}:{5:02x}'
|
||||
categorie_items = ["cpu", "dimm", "firmware", "bios_version"]
|
||||
|
||||
|
||||
def _megarac_abbrev_image(name):
|
||||
@@ -289,7 +304,7 @@ class OEMHandler(generic.OEMHandler):
|
||||
return super(OEMHandler, self).reseat_bay(bay)
|
||||
|
||||
def get_ntp_enabled(self):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
ntpres = self.ipmicmd.xraw_command(netfn=0x32, command=0xa7)
|
||||
return ntpres['data'][0] == '\x01'
|
||||
elif self.is_fpc:
|
||||
@@ -299,7 +314,7 @@ class OEMHandler(generic.OEMHandler):
|
||||
return None
|
||||
|
||||
def get_ntp_servers(self):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
srvs = []
|
||||
ntpres = self.ipmicmd.xraw_command(netfn=0x32, command=0xa7)
|
||||
srvs.append(ntpres['data'][1:129].rstrip('\x00'))
|
||||
@@ -312,7 +327,7 @@ class OEMHandler(generic.OEMHandler):
|
||||
return None
|
||||
|
||||
def set_ntp_enabled(self, enabled):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
if enabled:
|
||||
self.ipmicmd.xraw_command(
|
||||
netfn=0x32, command=0xa8, data=(3, 1), timeout=15)
|
||||
@@ -328,7 +343,7 @@ class OEMHandler(generic.OEMHandler):
|
||||
return None
|
||||
|
||||
def set_ntp_server(self, server, index=0):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
if not (0 <= index <= 1):
|
||||
raise pygexc.InvalidParameterValue("Index must be 0 or 1")
|
||||
cmddata = bytearray((1 + index, ))
|
||||
@@ -405,8 +420,29 @@ class OEMHandler(generic.OEMHandler):
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def has_asrock(self):
|
||||
# True if this particular server have a ASROCKRACK
|
||||
# based service processor (RS160 or TS460)
|
||||
# RS160 (Riddler) product id is 1182 (049Eh)
|
||||
# TS460 (WildThing) product id is 1184 (04A0h)
|
||||
|
||||
if (self.oemid['manufacturer_id'] == 19046
|
||||
and (self.oemid['product_id'] == 1182
|
||||
or self.oemid['product_id'] == 1184)):
|
||||
try:
|
||||
self.ipmicmd.xraw_command(netfn=0x3a,
|
||||
command=0x50,
|
||||
data=(0x00, 0x00, 0x00))
|
||||
except pygexc.IpmiException as ie:
|
||||
if ie.ipmicode == 193:
|
||||
return False
|
||||
raise
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_oem_inventory_descriptions(self):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
# Thinkserver with TSM
|
||||
if not self.oem_inventory_info:
|
||||
self._collect_tsm_inventory()
|
||||
@@ -418,7 +454,7 @@ class OEMHandler(generic.OEMHandler):
|
||||
return ()
|
||||
|
||||
def get_oem_inventory(self):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
self._collect_tsm_inventory()
|
||||
for compname in self.oem_inventory_info:
|
||||
yield (compname, self.oem_inventory_info[compname])
|
||||
@@ -460,7 +496,7 @@ class OEMHandler(generic.OEMHandler):
|
||||
return ()
|
||||
|
||||
def get_inventory_of_component(self, component):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
self._collect_tsm_inventory()
|
||||
return self.oem_inventory_info.get(component, None)
|
||||
if self.has_imm:
|
||||
@@ -468,24 +504,46 @@ class OEMHandler(generic.OEMHandler):
|
||||
if self.is_fpc:
|
||||
return self.smmhandler.get_inventory_of_component(component)
|
||||
|
||||
def get_cmd_type(self, categorie_item, catspec):
|
||||
if self.has_asrock:
|
||||
cmd_type = catspec["command"]["asrock"]
|
||||
elif categorie_item in categorie_items:
|
||||
cmd_type = catspec["command"]["lenovo"]
|
||||
else:
|
||||
cmd_type = catspec["command"]
|
||||
|
||||
return cmd_type
|
||||
|
||||
def _collect_tsm_inventory(self):
|
||||
self.oem_inventory_info = {}
|
||||
asrock = False
|
||||
if self.has_asrock:
|
||||
asrock = True
|
||||
for catid, catspec in inventory.categories.items():
|
||||
if (catspec.get("workaround_bmc_bug", False)):
|
||||
# skip the inventory fields if the system is RS160
|
||||
if asrock and catid not in categorie_items:
|
||||
continue
|
||||
if (catspec.get("workaround_bmc_bug", False)
|
||||
and catspec["workaround_bmc_bug"](
|
||||
"ami" if self.has_ami else "lenovo")):
|
||||
rsp = None
|
||||
tmp_command = dict(catspec["command"])
|
||||
cmd = self.get_cmd_type(catid, catspec)
|
||||
tmp_command = dict(cmd)
|
||||
tmp_command["data"] = list(tmp_command["data"])
|
||||
count = 0
|
||||
for i in range(0x01, 0xff):
|
||||
tmp_command["data"][-1] = i
|
||||
try:
|
||||
partrsp = self.ipmicmd.xraw_command(**tmp_command)
|
||||
count += 1
|
||||
if asrock and partrsp["data"][1] == "\xff":
|
||||
continue
|
||||
|
||||
if rsp is None:
|
||||
rsp = partrsp
|
||||
rsp["data"] = list(rsp["data"])
|
||||
else:
|
||||
rsp["data"].extend(partrsp["data"][1:])
|
||||
count += 1
|
||||
except Exception:
|
||||
break
|
||||
# If we didn't get any response, assume we don't have
|
||||
@@ -496,13 +554,14 @@ class OEMHandler(generic.OEMHandler):
|
||||
rsp["data"] = buffer(bytearray(rsp["data"]))
|
||||
else:
|
||||
try:
|
||||
rsp = self.ipmicmd.xraw_command(**catspec["command"])
|
||||
cmd = self.get_cmd_type(catid, catspec)
|
||||
rsp = self.ipmicmd.xraw_command(**cmd)
|
||||
except pygexc.IpmiException:
|
||||
continue
|
||||
# Parse the response we got
|
||||
try:
|
||||
items = inventory.parse_inventory_category(
|
||||
catid, rsp,
|
||||
catid, rsp, asrock,
|
||||
countable=catspec.get("countable", True)
|
||||
)
|
||||
except Exception:
|
||||
@@ -512,7 +571,22 @@ class OEMHandler(generic.OEMHandler):
|
||||
|
||||
for item in items:
|
||||
try:
|
||||
key = catspec["idstr"].format(item["index"])
|
||||
# Originally on ThinkServer and SD350 (Kent),
|
||||
# the DIMM is distinguished by slot,
|
||||
# the key is the value of slot number (item["index"])
|
||||
# While on RS160/TS460 the DIMMs is distinguished
|
||||
# by slot number and channel number,
|
||||
# the key is the value of the sum of slot number
|
||||
# and channel number
|
||||
if asrock and catid == "dimm":
|
||||
if item["channel_number"] == 1:
|
||||
key = catspec["idstr"].format(item["index"])
|
||||
else:
|
||||
key = catspec["idstr"].format(
|
||||
item["index"] + item["channel_number"])
|
||||
else:
|
||||
key = catspec["idstr"].format(item["index"])
|
||||
|
||||
del item["index"]
|
||||
self.oem_inventory_info[key] = item
|
||||
except Exception:
|
||||
@@ -521,16 +595,34 @@ class OEMHandler(generic.OEMHandler):
|
||||
continue
|
||||
|
||||
def get_leds(self):
|
||||
if self.has_tsm:
|
||||
for (name, id_) in leds.items():
|
||||
try:
|
||||
rsp = self.ipmicmd.xraw_command(netfn=0x3A, command=0x02,
|
||||
cmd = 0x02
|
||||
led_set = leds
|
||||
led_set_status = led_status
|
||||
|
||||
asrock = self.has_asrock
|
||||
if asrock:
|
||||
cmd = 0x50
|
||||
led_set = asrock_leds
|
||||
led_set_status = asrock_led_status
|
||||
|
||||
for (name, id_) in led_set.items():
|
||||
try:
|
||||
if asrock:
|
||||
rsp = self.ipmicmd.xraw_command(netfn=0x3A, command=cmd,
|
||||
data=(0x03, id_, 0x00))
|
||||
rdata = bytearray(rsp['data'][:])
|
||||
status = rdata[1]
|
||||
else:
|
||||
rsp = self.ipmicmd.xraw_command(netfn=0x3A, command=cmd,
|
||||
data=(id_,))
|
||||
except pygexc.IpmiException:
|
||||
continue # Ignore LEDs we can't retrieve
|
||||
status = led_status.get(bytearray(rsp['data'][:])[0],
|
||||
rdata = bytearray(rsp['data'][:])
|
||||
status = rdata[0]
|
||||
|
||||
except pygexc.IpmiException:
|
||||
continue # Ignore LEDs we can't retrieve
|
||||
status = led_set_status.get(status,
|
||||
led_status_default)
|
||||
yield (name, {'status': status})
|
||||
yield (name, {'status': status})
|
||||
|
||||
def set_identify(self, on, duration):
|
||||
if on and not duration and self.is_sd350:
|
||||
@@ -608,6 +700,17 @@ class OEMHandler(generic.OEMHandler):
|
||||
elif self.is_fpc and self.is_fpc != 6: # SMM variant
|
||||
fru['oem_parser'] = 'lenovo'
|
||||
return self.smmhandler.process_fru(fru)
|
||||
elif self.has_asrock:
|
||||
fru['oem_parser'] = 'lenovo'
|
||||
# ASRock RS160 TS460 lays out specific interpretation of the
|
||||
# board extra fields
|
||||
try:
|
||||
mac1 = fru['board_extra']
|
||||
if mac1 not in ('00:00:00:00:00:00', ''):
|
||||
fru['MAC Address 1'] = mac1.encode('utf-8')
|
||||
except (AttributeError, KeyError):
|
||||
pass
|
||||
return fru
|
||||
else:
|
||||
fru['oem_parser'] = None
|
||||
return fru
|
||||
@@ -653,20 +756,27 @@ class OEMHandler(generic.OEMHandler):
|
||||
return self._hasimm
|
||||
|
||||
def get_oem_firmware(self, bmcver, components):
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
command = firmware.get_categories()["firmware"]
|
||||
rsp = self.ipmicmd.xraw_command(**command["command"])
|
||||
fw_cmd = self.get_cmd_type("firmware", command)
|
||||
rsp = self.ipmicmd.xraw_command(**fw_cmd)
|
||||
|
||||
# the newest Lenovo ThinkServer versions are returning Bios version
|
||||
# numbers through another command
|
||||
bios_versions = None
|
||||
if self.has_tsm:
|
||||
if self.has_tsm or self.has_asrock:
|
||||
bios_command = firmware.get_categories()["bios_version"]
|
||||
bios_rsp = self.ipmicmd.xraw_command(**bios_command["command"])
|
||||
bios_versions = bios_command["parser"](bios_rsp["data"])
|
||||
bios_cmd = self.get_cmd_type("bios_version", bios_command)
|
||||
bios_rsp = self.ipmicmd.xraw_command(**bios_cmd)
|
||||
if self.has_asrock:
|
||||
bios_versions = bios_rsp['data']
|
||||
else:
|
||||
bios_versions = bios_command["parser"](bios_rsp['data'])
|
||||
|
||||
# pass bios versions to firmware parser
|
||||
return command["parser"](rsp["data"], bios_versions)
|
||||
|
||||
return command["parser"](rsp["data"],
|
||||
bios_versions,
|
||||
self.has_asrock)
|
||||
elif self.has_imm:
|
||||
return self.immhandler.get_firmware_inventory(bmcver, components)
|
||||
elif self.is_fpc:
|
||||
@@ -1133,3 +1243,37 @@ class OEMHandler(generic.OEMHandler):
|
||||
uid, 0x03, 0x00, 0x00, 0x00))
|
||||
return True
|
||||
return False
|
||||
|
||||
def process_zero_fru(self, zerofru):
|
||||
if (self.oemid['manufacturer_id'] == 19046
|
||||
and self.oemid['product_id'] == 13616):
|
||||
# Currently SD350 FRU UUID is synchronized with the Device UUID.
|
||||
# Need to change to System UUID in future.
|
||||
# Since the IPMI get device uuid matches SMBIOS,
|
||||
# no need to decode it.
|
||||
guiddata = self.ipmicmd.raw_command(netfn=6, command=0x8)
|
||||
if 'error' not in guiddata:
|
||||
zerofru['UUID'] = util.decode_wireformat_uuid(
|
||||
guiddata['data'], True)
|
||||
else:
|
||||
# It is expected that a manufacturer matches SMBIOS to IPMI
|
||||
# get system uuid return data. If a manufacturer does not
|
||||
# do so, they should handle either deletion or fixup in the
|
||||
# OEM processing pass. Code optimistically assumes that if
|
||||
# data is returned, than the vendor is properly using it.
|
||||
|
||||
guiddata = self.ipmicmd.raw_command(netfn=6, command=0x37)
|
||||
if 'error' not in guiddata:
|
||||
if (self.oemid['manufacturer_id'] == 19046
|
||||
and (self.oemid['product_id'] == 1182
|
||||
or self.oemid['product_id'] == 1184)):
|
||||
# The manufacturer (Asrockrack) of RS160/TS460
|
||||
# matches SMBIOS
|
||||
# to IPMI get system uuid return data,
|
||||
# no need to decode it.
|
||||
zerofru['UUID'] = util.decode_wireformat_uuid(
|
||||
guiddata['data'], True)
|
||||
else:
|
||||
zerofru['UUID'] = util.decode_wireformat_uuid(
|
||||
guiddata['data'])
|
||||
return self.process_fru(zerofru)
|
||||
|
||||
@@ -52,7 +52,7 @@ class EntryField(object):
|
||||
|
||||
|
||||
# General parameter parsing functions
|
||||
def parse_inventory_category(name, info, countable=True):
|
||||
def parse_inventory_category(name, info, asrock=False, countable=True):
|
||||
"""Parses every entry in an inventory category
|
||||
|
||||
For example: CPU, memory, PCI, drives
|
||||
@@ -61,11 +61,15 @@ def parse_inventory_category(name, info, countable=True):
|
||||
|
||||
:param name: the name of the parameter (e.g.: "cpu")
|
||||
:param info: a list of integers with raw data read from an IPMI requests
|
||||
:param asrock: a boolean represents if RS160 with asrockrack or not
|
||||
:param countable: whether the data have an entries count field
|
||||
:returns: dict -- a list of entries in the category.
|
||||
"""
|
||||
raw = info["data"][1:]
|
||||
|
||||
if name == "cpu" and asrock:
|
||||
raw = info["data"]
|
||||
|
||||
cur = 0
|
||||
if countable:
|
||||
count = bytearray(raw)[cur]
|
||||
@@ -76,17 +80,17 @@ def parse_inventory_category(name, info, countable=True):
|
||||
|
||||
entries = []
|
||||
while cur < len(raw):
|
||||
read, cpu = categories[name]["parser"](raw[cur:])
|
||||
read, parser = categories[name]["parser"](raw[cur:])
|
||||
cur = cur + read
|
||||
# Account for discarded entries (because they are not present)
|
||||
if cpu is None:
|
||||
if parser is None:
|
||||
discarded += 1
|
||||
continue
|
||||
if not countable:
|
||||
# count by myself
|
||||
count += 1
|
||||
cpu["index"] = count
|
||||
entries.append(cpu)
|
||||
parser["index"] = count
|
||||
entries.append(parser)
|
||||
|
||||
# TODO(avidal): raise specific exception to point that there's data left in
|
||||
# the buffer
|
||||
@@ -94,7 +98,7 @@ def parse_inventory_category(name, info, countable=True):
|
||||
raise Exception
|
||||
# TODO(avidal): raise specific exception to point that the number of
|
||||
# entries is different than the expected
|
||||
if count - discarded != len(entries):
|
||||
if count - discarded != len(entries) and not asrock:
|
||||
raise Exception
|
||||
return entries
|
||||
|
||||
@@ -119,6 +123,9 @@ def parse_inventory_category_entry(raw, fields):
|
||||
value = struct.unpack_from(field.fmt, r)[0]
|
||||
read = struct.calcsize(field.fmt)
|
||||
bytes_read += read
|
||||
if bytes_read > len(raw):
|
||||
break
|
||||
|
||||
r = r[read:]
|
||||
# If this entry is not actually present, just parse and then discard it
|
||||
if field.presence and not bool(value):
|
||||
@@ -127,7 +134,7 @@ def parse_inventory_category_entry(raw, fields):
|
||||
continue
|
||||
|
||||
if (field.fmt[-1] == "s"):
|
||||
value = value.rstrip(b'\x00')
|
||||
value = value.rstrip(b'\x00\xff')
|
||||
if (field.mapper and value in field.mapper):
|
||||
value = field.mapper[value]
|
||||
if (field.valuefunc):
|
||||
|
||||
@@ -37,7 +37,7 @@ except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def decode_wireformat_uuid(rawguid):
|
||||
def decode_wireformat_uuid(rawguid, bigendian=False):
|
||||
"""Decode a wire format UUID
|
||||
|
||||
It handles the rather particular scheme where half is little endian
|
||||
@@ -45,7 +45,10 @@ def decode_wireformat_uuid(rawguid):
|
||||
"""
|
||||
if isinstance(rawguid, list):
|
||||
rawguid = bytearray(rawguid)
|
||||
lebytes = struct.unpack_from('<IHH', buffer(rawguid[:8]))
|
||||
endian = '<IHH' # little endian
|
||||
if bigendian:
|
||||
endian = '>IHH' # big endian
|
||||
lebytes = struct.unpack_from(endian, buffer(rawguid[:8]))
|
||||
bebytes = struct.unpack_from('>HHI', buffer(rawguid[8:]))
|
||||
return '{0:08X}-{1:04X}-{2:04X}-{3:04X}-{4:04X}{5:08X}'.format(
|
||||
lebytes[0], lebytes[1], lebytes[2], bebytes[0], bebytes[1], bebytes[2])
|
||||
|
||||
Reference in New Issue
Block a user