From 40cb397ae77981cce07b81017920a729e0b415aa Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 26 Aug 2019 14:56:45 -0400 Subject: [PATCH] Implement extensible BMC configuration In much the same way system_configuration permits a system to extensibly describe UEFI/BIOS type configuration, offer OEM modules a mechanism to do the same for BMC specific settings. Change-Id: Ic6be1b90247afe9b43af498e90e4d139343a5124 --- pyghmi/ipmi/command.py | 12 ++++++++++ pyghmi/ipmi/oem/generic.py | 10 ++++++++ pyghmi/ipmi/oem/lenovo/handler.py | 17 +++++++++++++ pyghmi/ipmi/oem/lenovo/imm.py | 37 +++++++++++++++++++++++++++++ pyghmi/ipmi/oem/lenovo/nextscale.py | 3 +++ pyghmi/redfish/command.py | 35 +++++++++++++++++++++++++++ 6 files changed, 114 insertions(+) diff --git a/pyghmi/ipmi/command.py b/pyghmi/ipmi/command.py index 30a2da6f..2d12ff6a 100644 --- a/pyghmi/ipmi/command.py +++ b/pyghmi/ipmi/command.py @@ -774,6 +774,18 @@ class Command(object): else: raise Exception("Unrecognized data format " + repr(fetchdata)) + def get_bmc_configuration(self): + self.oem_init() + return self._oem.get_bmc_configuration() + + def set_bmc_configuration(self, changeset): + self.oem_init() + return self._oem.set_bmc_configuration(changeset) + + def clear_bmc_configuration(self): + self.oem_init() + return self._oem.clear_bmc_configuration() + def get_system_configuration(self, hideadvanced=True): self.oem_init() return self._oem.get_system_configuration(hideadvanced) diff --git a/pyghmi/ipmi/oem/generic.py b/pyghmi/ipmi/oem/generic.py index 8fae6b20..3e82073a 100644 --- a/pyghmi/ipmi/oem/generic.py +++ b/pyghmi/ipmi/oem/generic.py @@ -60,6 +60,10 @@ class OEMHandler(object): raise exc.UnsupportedFunctionality( 'Clearing system configuration not implemented for this platform') + def clear_bmc_configuration(self): + raise exc.UnsupportedFunctionality( + 'Clearing BMC configuration not implemented for this platform') + def get_oem_inventory_descriptions(self): """Get descriptions of available additional inventory items @@ -335,6 +339,12 @@ class OEMHandler(object): """ return False + def get_bmc_configuration(self): + return {} + + def set_bmc_configuration(self, changeset): + raise exc.UnsupportedFunctionality('Platform does not support setting bmc attributes') + def get_system_configuration(self, hideadvanced): """Retrieve system configuration diff --git a/pyghmi/ipmi/oem/lenovo/handler.py b/pyghmi/ipmi/oem/lenovo/handler.py index 0d616319..63491e90 100755 --- a/pyghmi/ipmi/oem/lenovo/handler.py +++ b/pyghmi/ipmi/oem/lenovo/handler.py @@ -938,6 +938,16 @@ class OEMHandler(generic.OEMHandler): return {'height': self._fpc_variant, 'slot': 0} return super(OEMHandler, self).get_description() + def get_bmc_configuration(self): + if self.has_xcc: + return self.immhandler.get_bmc_configuration() + return super(OEMHandler, self).get_bmc_configuration() + + def set_bmc_configuration(self, changeset): + if self.has_xcc: + return self.immhandler.set_bmc_configuration(changeset) + return super(OEMHandler, self).set_bmc_configuration(changeset) + def get_system_configuration(self, hideadvanced): if self.has_imm or self.has_xcc: return self.immhandler.get_system_configuration(hideadvanced) @@ -948,6 +958,13 @@ class OEMHandler(generic.OEMHandler): return self.immhandler.set_system_configuration(changeset) return super(OEMHandler, self).set_system_configuration(changeset) + def clear_bmc_configuration(self): + if self.has_xcc: + return self.immhandler.clear_bmc_configuration() + elif self.is_fpc: + return self.smmhandler.clear_bmc_configuration() + return super(OEMHandler, self).clear_system_configuration() + def clear_system_configuration(self): if self.has_xcc: return self.immhandler.clear_system_configuration() diff --git a/pyghmi/ipmi/oem/lenovo/imm.py b/pyghmi/ipmi/oem/lenovo/imm.py index 1fa48281..97b6b2ec 100644 --- a/pyghmi/ipmi/oem/lenovo/imm.py +++ b/pyghmi/ipmi/oem/lenovo/imm.py @@ -265,6 +265,9 @@ class IMMClient(object): self.fwo = None raise + def clear_bmc_configuration(self): + self.ipmicmd.xraw_command(0x2e, 0xcc, data=(0x5e, 0x2b, 0, 0xa, 1, 0xff, 0, 0, 0)) + def set_property(self, propname, value): if not isinstance(value, int) or value > 255: raise Exception('Unsupported property value') @@ -806,6 +809,40 @@ class XCCClient(IMMClient): return {} return {'height': int(dsc['u-height']), 'slot': int(dsc['slot'])} + def get_bmc_configuration(self): + try: + enclosureinfo = self.ipmicmd.xraw_command(0x3a, 0xf1, data=[0]) + except pygexc.IpmiException: + return {} + settings = { + 'smm': { + 'default': 'Disable', + 'possible': ['Enable', 'Disable'], + } + } + if enclosureinfo['data'][0] == '\x02': + settings['smm']['value'] = 'Disable' + elif enclosureinfo['data'][0] == '\x01': + settings['smm']['value'] = 'Enable' + else: + settings['smm']['value'] = None + return settings + + def set_bmc_configuration(self, changeset): + for key in changeset: + if (isinstance(changeset[key], str) or + isinstance(changeset[key], unicode)): + changeset[key] = {'value': changeset[key]} + currval = changeset[key].get('value', None) + if 'smm'.startswith(key.lower()): + if currval == 'Enable': + self.ipmicmd.xraw_command(0x3a, 0xf1, data=[1]) + elif currval == 'Disable': + self.ipmicmd.xraw_command(0x3a, 0xf1, data=[2]) + else: + raise pygexc.InvalidParameterValue( + '{0} not a known setting'.format(key)) + def clear_system_configuration(self): res = self.wc.grab_json_response_with_status( '/redfish/v1/Systems/1/Bios/Actions/Bios.ResetBios', diff --git a/pyghmi/ipmi/oem/lenovo/nextscale.py b/pyghmi/ipmi/oem/lenovo/nextscale.py index 5104c661..50e55d5b 100644 --- a/pyghmi/ipmi/oem/lenovo/nextscale.py +++ b/pyghmi/ipmi/oem/lenovo/nextscale.py @@ -251,6 +251,9 @@ class SMMClient(object): self.password = ipmicmd.ipmi_session.password self._wc = None + def clear_bmc_configuration(self): + self.ipmicmd.xraw_command(0x32, 0xad) + def set_user_priv(self, uid, priv): if priv.lower() == 'administrator': rsp = self.ipmicmd.xraw_command(netfn=6, command=0x46, data=(uid,)) diff --git a/pyghmi/redfish/command.py b/pyghmi/redfish/command.py index bc745dd7..94193866 100644 --- a/pyghmi/redfish/command.py +++ b/pyghmi/redfish/command.py @@ -847,6 +847,41 @@ class Command(object): } return addon, valtodisplay, displaytoval, reg + def get_bmc_configuration(self): + """Get miscellaneous BMC configuration + + In much the same way a bmc can present arbitrary key-value + structure for BIOS/UEFI configuration, provide a mechanism + for a BMC to provide arbitrary key-value for BMC specific + settings. + """ + + # For now, this is a stub, no implementation for redfish currently + return {} + + def set_bmc_configuration(self, changeset): + """Get miscellaneous BMC configuration + + In much the same way a bmc can present arbitrary key-value + structure for BIOS/UEFI configuration, provide a mechanism + for a BMC to provide arbitrary key-value for BMC specific + settings. + """ + + # For now, this is a stub, no implementation for redfish currently + raise exc.UnsupportedFunctionality( + 'Set BMC configuration not supported in redfish yet') + + def clear_bmc_configuration(self): + """Reset BMC to factory default + + Call appropriate function to clear BMC to factory default settings. + In many cases, this may render remote network access impracticle or + impossible." + """ + raise exc.UnsupportedFunctionality( + 'Clear BMC configuration not supported in redfish yet') + def get_system_configuration(self, hideadvanced=True): return self._getsyscfg()[0]