From bd247bbaccc0b1e804608a06c75eda7ac3f2352a Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Mon, 8 Feb 2021 13:51:15 -0500 Subject: [PATCH] Add remote presence assertion to bmc config For XCC class systems, expose the presence assertion as a setting Change-Id: I2bae20c83647289fe5e08d9692875a9ce23906c6 --- pyghmi/ipmi/oem/lenovo/imm.py | 20 +++++++++ pyghmi/redfish/command.py | 5 +-- pyghmi/redfish/oem/generic.py | 7 ++++ pyghmi/redfish/oem/lenovo/xcc.py | 69 +++++++++++++++++++++++++++++++- 4 files changed, 97 insertions(+), 4 deletions(-) diff --git a/pyghmi/ipmi/oem/lenovo/imm.py b/pyghmi/ipmi/oem/lenovo/imm.py index 1071dfcb..66be7b89 100644 --- a/pyghmi/ipmi/oem/lenovo/imm.py +++ b/pyghmi/ipmi/oem/lenovo/imm.py @@ -895,6 +895,12 @@ class XCCClient(IMMClient): 'value': passrules.get('pass_min_length')} settings['password_lockout_period'] = { 'value': passrules.get('lockout_period')} + presassert = self.wc.grab_json_response('/api/dataset/imm_rpp') + asserted = presassert.get('items', [{}])[0].get('rpp_Assert', None) + if asserted is not None: + settings['presence_assert'] = { + 'value': 'Enable' if asserted else 'Disable' + } try: enclosureinfo = self.ipmicmd.xraw_command(0x3a, 0xf1, data=[0]) except pygexc.IpmiException: @@ -951,6 +957,20 @@ class XCCClient(IMMClient): if key.lower() == 'password_expiration': warntime = str(int(int(changeset[key]['value']) * 0.08)) ruleset['USER_GlobalPassExpWarningPeriod'] = warntime + elif 'presence_asserted'.startswith(key.lower()): + assertion = changeset[key]['value'] + if 'enabled'.startswith(assertion.lower()): + self.wc.grab_json_response('/api/dataset', + {'IMM_RPPAssert': '0'}) + self.wc.grab_json_response('/api/dataset', + {'IMM_RPPAssert': '1'}) + elif 'disabled'.startswith(assertion.lower()): + self.wc.grab_json_response('/api/dataset', + {'IMM_RPPAssert': '0'}) + else: + raise pygexc.InvalidParameterValue( + '"{0}" is not a recognized value for {1}'.format( + assertion, key)) else: raise pygexc.InvalidParameterValue( '{0} not a known setting'.format(key)) diff --git a/pyghmi/redfish/command.py b/pyghmi/redfish/command.py index 0dda15f4..8cb489a2 100644 --- a/pyghmi/redfish/command.py +++ b/pyghmi/redfish/command.py @@ -963,7 +963,7 @@ class Command(object): """ # For now, this is a stub, no implementation for redfish currently - return {} + return self.oem.get_bmc_configuration() def set_bmc_configuration(self, changeset): """Get miscellaneous BMC configuration @@ -975,8 +975,7 @@ class Command(object): """ # For now, this is a stub, no implementation for redfish currently - raise exc.UnsupportedFunctionality( - 'Set BMC configuration not supported in redfish yet') + return self.oem.set_bmc_configuration(changeset) def clear_bmc_configuration(self): """Reset BMC to factory default diff --git a/pyghmi/redfish/oem/generic.py b/pyghmi/redfish/oem/generic.py index 539ff8d0..62c75576 100644 --- a/pyghmi/redfish/oem/generic.py +++ b/pyghmi/redfish/oem/generic.py @@ -36,6 +36,13 @@ class OEMHandler(object): return cachent['contents'] return None + def get_bmc_configuration(self): + return {} + + def set_bmc_configuration(self, changeset): + raise exc.UnsupportedFunctionality( + 'Platform does not support setting bmc attributes') + def attach_remote_media(self, url, username, password, vmurls): return None diff --git a/pyghmi/redfish/oem/lenovo/xcc.py b/pyghmi/redfish/oem/lenovo/xcc.py index 3631b086..d43795d9 100644 --- a/pyghmi/redfish/oem/lenovo/xcc.py +++ b/pyghmi/redfish/oem/lenovo/xcc.py @@ -22,6 +22,8 @@ import re import socket import time +import six + import pyghmi.exceptions as pygexc import pyghmi.ipmi.private.util as util import pyghmi.media as media @@ -30,7 +32,6 @@ import pyghmi.storage as storage from pyghmi.util.parse import parse_time import pyghmi.util.webclient as webclient - numregex = re.compile('([0-9]+)') funtypes = { 0: 'RAID Controller', @@ -102,6 +103,72 @@ class OEMHandler(generic.OEMHandler): except KeyError: return None + def get_bmc_configuration(self): + settings = {} + passrules = self.wc.grab_json_response('/api/dataset/imm_users_global') + passrules = passrules.get('items', [{}])[0] + settings['password_reuse_count'] = { + 'value': passrules.get('pass_min_resuse')} + settings['password_change_interval'] = { + 'value': passrules.get('pass_change_interval')} + settings['password_expiration'] = { + 'value': passrules.get('pass_expire_days')} + settings['password_login_failures'] = { + 'value': passrules.get('max_login_failures')} + settings['password_complexity'] = { + 'value': passrules.get('pass_complex_required')} + settings['password_min_length'] = { + 'value': passrules.get('pass_min_length')} + settings['password_lockout_period'] = { + 'value': passrules.get('lockout_period')} + presassert = self.wc.grab_json_response('/api/dataset/imm_rpp') + asserted = presassert.get('items', [{}])[0].get('rpp_Assert', None) + if asserted is not None: + settings['presence_assert'] = { + 'value': 'Enable' if asserted else 'Disable' + } + return settings + + rulemap = { + 'password_change_interval': 'USER_GlobalMinPassChgInt', + 'password_reuse_count': 'USER_GlobalMinPassReuseCycle', + 'password_expiration': 'USER_GlobalPassExpPeriod', + 'password_login_failures': 'USER_GlobalMaxLoginFailures', + 'password_complexity': 'USER_GlobalPassComplexRequired', + 'password_min_length': 'USER_GlobalMinPassLen', + 'password_lockout_period': 'USER_GlobalLockoutPeriod', + } + + def set_bmc_configuration(self, changeset): + ruleset = {} + for key in changeset: + if isinstance(changeset[key], six.string_types): + changeset[key] = {'value': changeset[key]} + currval = changeset[key].get('value', None) + if key.lower() in self.rulemap: + ruleset[self.rulemap[key.lower()]] = currval + if key.lower() == 'password_expiration': + warntime = str(int(int(currval) * 0.08)) + ruleset['USER_GlobalPassExpWarningPeriod'] = warntime + elif 'presence_asserted'.startswith(key.lower()): + if 'enabled'.startswith(currval.lower()): + self.wc.grab_json_response('/api/dataset', + {'IMM_RPPAssert': '0'}) + self.wc.grab_json_response('/api/dataset', + {'IMM_RPPAssert': '1'}) + elif 'disabled'.startswith(currval.lower()): + self.wc.grab_json_response('/api/dataset', + {'IMM_RPPAssert': '0'}) + else: + raise pygexc.InvalidParameterValue( + '"{0}" is not a recognized value for {1}'.format( + currval, key)) + else: + raise pygexc.InvalidParameterValue( + '{0} not a known setting'.format(key)) + if ruleset: + self.wc.grab_json_response('/api/dataset', ruleset) + def get_description(self): description = self._do_web_request('/DeviceDescription.json') if description: