mirror of
https://opendev.org/x/pyghmi
synced 2026-01-11 10:42:32 +00:00
Refactor redfish settings and leverage in XCC3
XCC3 has some OEM settings managed in a redfish settings registry sort of way. Refactor to pull out generic registry handling and use it with XCC3 settings as well as UEFI. Manifest 'XCC' settings with 'XCC.' prefix, imitating the 'IMM.' of the past. Since OData forbids '.', this means XCC. cannot conflict with hypothetical BIOS names that may conflict. Change-Id: Idb9e5ecffdc0d27f20ae070acdc3cd78658a0955
This commit is contained in:
@@ -81,20 +81,6 @@ def _mask_to_cidr(mask):
|
||||
return cidr
|
||||
|
||||
|
||||
def _to_boolean(attrval):
|
||||
attrval = attrval.lower()
|
||||
if not attrval:
|
||||
return False
|
||||
if ('true'.startswith(attrval) or 'yes'.startswith(attrval)
|
||||
or 'enabled'.startswith(attrval) or attrval == '1'):
|
||||
return True
|
||||
if ('false'.startswith(attrval) or 'no'.startswith(attrval)
|
||||
or 'disabled'.startswith(attrval) or attrval == '0'):
|
||||
return False
|
||||
raise Exception(
|
||||
'Unrecognized candidate for boolean: {0}'.format(attrval))
|
||||
|
||||
|
||||
def _cidr_to_mask(cidr):
|
||||
return socket.inet_ntop(
|
||||
socket.AF_INET, struct.pack(
|
||||
|
||||
@@ -44,11 +44,29 @@ class SensorReading(object):
|
||||
self.units = units
|
||||
self.unavailable = unavailable
|
||||
|
||||
|
||||
def _to_boolean(attrval):
|
||||
attrval = attrval.lower()
|
||||
if not attrval:
|
||||
return False
|
||||
if ('true'.startswith(attrval) or 'yes'.startswith(attrval)
|
||||
or 'enabled'.startswith(attrval) or attrval == '1'):
|
||||
return True
|
||||
if ('false'.startswith(attrval) or 'no'.startswith(attrval)
|
||||
or 'disabled'.startswith(attrval) or attrval == '0'):
|
||||
return False
|
||||
raise Exception(
|
||||
'Unrecognized candidate for boolean: {0}'.format(attrval))
|
||||
|
||||
|
||||
def _normalize_mac(mac):
|
||||
if ':' not in mac:
|
||||
mac = ':'.join((mac[:2], mac[2:4], mac[4:6], mac[6:8], mac[8:10], mac[10:12]))
|
||||
mac = ':'.join((
|
||||
mac[:2], mac[2:4], mac[4:6],
|
||||
mac[6:8], mac[8:10], mac[10:12]))
|
||||
return mac.lower()
|
||||
|
||||
|
||||
_healthmap = {
|
||||
'Critical': const.Health.Critical,
|
||||
'Unknown': const.Health.Warning,
|
||||
@@ -345,6 +363,38 @@ class OEMHandler(object):
|
||||
def get_system_configuration(self, hideadvanced=True, fishclient=None):
|
||||
return self._getsyscfg(fishclient)[0]
|
||||
|
||||
def _get_attrib_registry(self, fishclient, attribreg):
|
||||
overview = fishclient._do_web_request('/redfish/v1/')
|
||||
reglist = overview['Registries']['@odata.id']
|
||||
reglist = fishclient._do_web_request(reglist)
|
||||
regurl = None
|
||||
for cand in reglist.get('Members', []):
|
||||
cand = cand.get('@odata.id', '')
|
||||
candname = cand.split('/')[-1]
|
||||
if candname == '': # implementation uses trailing slash
|
||||
candname = cand.split('/')[-2]
|
||||
if candname == attribreg:
|
||||
regurl = cand
|
||||
break
|
||||
if not regurl:
|
||||
# Workaround a vendor bug where they link to a
|
||||
# non-existant name
|
||||
for cand in reglist.get('Members', []):
|
||||
cand = cand.get('@odata.id', '')
|
||||
candname = cand.split('/')[-1]
|
||||
candname = candname.split('.')[0]
|
||||
if candname == attribreg.split('.')[0]:
|
||||
regurl = cand
|
||||
break
|
||||
if regurl:
|
||||
reginfo = fishclient._do_web_request(regurl)
|
||||
for reg in reginfo.get('Location', []):
|
||||
if reg.get('Language', 'en').startswith('en'):
|
||||
reguri = reg['Uri']
|
||||
reginfo = self._get_biosreg(reguri, fishclient)
|
||||
return reginfo
|
||||
extrainfo, valtodisplay, _, self.attrdeps = reginfo
|
||||
|
||||
def _getsyscfg(self, fishclient):
|
||||
biosinfo = self._do_web_request(fishclient._biosurl, cache=False)
|
||||
reginfo = ({}, {}, {}, {})
|
||||
@@ -352,36 +402,9 @@ class OEMHandler(object):
|
||||
valtodisplay = {}
|
||||
self.attrdeps = {'Dependencies': [], 'Attributes': []}
|
||||
if 'AttributeRegistry' in biosinfo:
|
||||
overview = fishclient._do_web_request('/redfish/v1/')
|
||||
reglist = overview['Registries']['@odata.id']
|
||||
reglist = fishclient._do_web_request(reglist)
|
||||
regurl = None
|
||||
for cand in reglist.get('Members', []):
|
||||
cand = cand.get('@odata.id', '')
|
||||
candname = cand.split('/')[-1]
|
||||
if candname == '': # implementation uses trailing slash
|
||||
candname = cand.split('/')[-2]
|
||||
if candname == biosinfo['AttributeRegistry']:
|
||||
regurl = cand
|
||||
break
|
||||
if not regurl:
|
||||
# Workaround a vendor bug where they link to a
|
||||
# non-existant name
|
||||
for cand in reglist.get('Members', []):
|
||||
cand = cand.get('@odata.id', '')
|
||||
candname = cand.split('/')[-1]
|
||||
candname = candname.split('.')[0]
|
||||
if candname == biosinfo[
|
||||
'AttributeRegistry'].split('.')[0]:
|
||||
regurl = cand
|
||||
break
|
||||
if regurl:
|
||||
reginfo = fishclient._do_web_request(regurl)
|
||||
for reg in reginfo.get('Location', []):
|
||||
if reg.get('Language', 'en').startswith('en'):
|
||||
reguri = reg['Uri']
|
||||
reginfo = self._get_biosreg(reguri, fishclient)
|
||||
extrainfo, valtodisplay, _, self.attrdeps = reginfo
|
||||
reginfo = self._get_attrib_registry(fishclient, biosinfo['AttributeRegistry'])
|
||||
if reginfo:
|
||||
extrainfo, valtodisplay, _, self.attrdeps = reginfo
|
||||
currsettings = {}
|
||||
try:
|
||||
pendingsettings = fishclient._do_web_request(
|
||||
@@ -418,10 +441,19 @@ class OEMHandler(object):
|
||||
rawsettings = fishclient._do_web_request(fishclient._biosurl,
|
||||
cache=False)
|
||||
rawsettings = rawsettings.get('Attributes', {})
|
||||
pendingsettings = fishclient._do_web_request(fishclient._setbiosurl)
|
||||
pendingsettings = fishclient._do_web_request(
|
||||
fishclient._setbiosurl)
|
||||
return self._set_redfish_settings(
|
||||
changeset, fishclient, currsettings, rawsettings,
|
||||
pendingsettings, self.attrdeps, reginfo,
|
||||
fishclient._setbiosurl)
|
||||
|
||||
def _set_redfish_settings(self, changeset, fishclient, currsettings,
|
||||
rawsettings, pendingsettings, attrdeps, reginfo,
|
||||
seturl):
|
||||
etag = pendingsettings.get('@odata.etag', None)
|
||||
pendingsettings = pendingsettings.get('Attributes', {})
|
||||
dephandler = AttrDependencyHandler(self.attrdeps, rawsettings,
|
||||
dephandler = AttrDependencyHandler(attrdeps, rawsettings,
|
||||
pendingsettings)
|
||||
for change in list(changeset):
|
||||
if change not in currsettings:
|
||||
@@ -440,7 +472,7 @@ class OEMHandler(object):
|
||||
changeval = changeset[change]
|
||||
overrides, blameattrs = dephandler.get_overrides(change)
|
||||
meta = {}
|
||||
for attr in self.attrdeps['Attributes']:
|
||||
for attr in attrdeps['Attributes']:
|
||||
if attr['AttributeName'] == change:
|
||||
meta = dict(attr)
|
||||
break
|
||||
@@ -479,7 +511,7 @@ class OEMHandler(object):
|
||||
changeset[change] = _to_boolean(changeset[change])
|
||||
redfishsettings = {'Attributes': changeset}
|
||||
fishclient._do_web_request(
|
||||
fishclient._setbiosurl, redfishsettings, 'PATCH', etag=etag)
|
||||
seturl, redfishsettings, 'PATCH', etag=etag)
|
||||
|
||||
def attach_remote_media(self, url, username, password, vmurls):
|
||||
return None
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
import pyghmi.redfish.oem.generic as generic
|
||||
from pyghmi.redfish.oem.lenovo import tsma
|
||||
from pyghmi.redfish.oem.lenovo import xcc
|
||||
from pyghmi.redfish.oem.lenovo import xcc3
|
||||
|
||||
|
||||
def get_handler(sysinfo, sysurl, webclient, cache, cmd):
|
||||
@@ -26,6 +27,9 @@ def get_handler(sysinfo, sysurl, webclient, cache, cmd):
|
||||
if 'FrontPanelUSB' in leninf or 'USBManagementPortAssignment' in leninf or sysinfo.get('SKU', '').startswith('7X58'):
|
||||
return xcc.OEMHandler(sysinfo, sysurl, webclient, cache,
|
||||
gpool=cmd._gpool)
|
||||
elif 'NextOneTimeBootDevice' in leninf:
|
||||
return xcc3.OEMHandler(sysinfo, sysurl, webclient, cache,
|
||||
gpool=cmd._gpool)
|
||||
else:
|
||||
leninv = sysinfo.get('Links', {}).get('OEM', {}).get(
|
||||
'Lenovo', {}).get('Inventory', {})
|
||||
|
||||
94
pyghmi/redfish/oem/lenovo/xcc3.py
Normal file
94
pyghmi/redfish/oem/lenovo/xcc3.py
Normal file
@@ -0,0 +1,94 @@
|
||||
import pyghmi.redfish.oem.generic as generic
|
||||
|
||||
class OEMHandler(generic.OEMHandler):
|
||||
|
||||
def get_system_configuration(self, hideadvanced=True, fishclient=None):
|
||||
stgs = self._getsyscfg(fishclient)[0]
|
||||
outstgs = {}
|
||||
for stg in stgs:
|
||||
outstgs[f'UEFI.{stg}'] = stgs[stg]
|
||||
return outstgs
|
||||
|
||||
def set_system_configuration(self, changeset, fishclient):
|
||||
bmchangeset = {}
|
||||
vpdchangeset = {}
|
||||
for stg in list(changeset):
|
||||
if stg.startswith('BMC.'):
|
||||
bmchangeset[stg.replace('BMC.', '')] = changeset[stg]
|
||||
del changeset[stg]
|
||||
if stg.startswith('UEFI.'):
|
||||
changeset[stg.replace('UEFI.' '')] = changeset[stg]
|
||||
del changeset[stg]
|
||||
if stg.startswith('VPD.'):
|
||||
vpdchangeset[stg.replace('VPD.', '')] = changeset[stg]
|
||||
del changeset[stg]
|
||||
if changeset:
|
||||
super().set_system_configuration(changeset, fishclient)
|
||||
if bmchangeset:
|
||||
self._set_xcc3_settings(bmchangeset, fishclient)
|
||||
if vpdchangeset:
|
||||
self._set_xcc3_vpd(vpdchangeset, fishclient)
|
||||
|
||||
def _set_xcc3_vpd(self, changeset, fishclient):
|
||||
newvpd = {'Attributes': changeset}
|
||||
fishclient._do_web_request(
|
||||
'/redfish/v1/Chassis/1/Oem/Lenovo/SysvpdSettings/Actions/LenovoSysVpdSettings.SetVpdSettings',
|
||||
newvpd)
|
||||
|
||||
|
||||
def _set_xcc3_settings(self, changeset, fishclient):
|
||||
currsettings, reginfo = self._get_lnv_bmcstgs(fishclient)
|
||||
rawsettings = fishclient._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings',
|
||||
cache=False)
|
||||
rawsettings = rawsettings.get('Attributes', {})
|
||||
pendingsettings = {}
|
||||
ret = self._set_redfish_settings(
|
||||
changeset, fishclient, currsettings, rawsettings,
|
||||
pendingsettings, self.lenovobmcattrdeps, reginfo,
|
||||
'/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
|
||||
fishclient._do_web_request('/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings', cache=False)
|
||||
return ret
|
||||
|
||||
def get_extended_bmc_configuration(self, fishclient, hideadvanced=True):
|
||||
cfgin = self._get_lnv_bmcstgs(fishclient)[0]
|
||||
cfgout = {}
|
||||
for stgname in cfgin:
|
||||
cfgout[f'BMC.{stgname}'] = cfgin[stgname]
|
||||
vpdin = self._get_lnv_vpd(fishclient)[0]
|
||||
for stgname in vpdin:
|
||||
cfgout[f'VPD.{stgname}'] = vpdin[stgname]
|
||||
return cfgout
|
||||
|
||||
def _get_lnv_vpd(self, fishclient):
|
||||
currsettings, reginfo = self._get_lnv_stgs(
|
||||
fishclient, '/redfish/v1/Chassis/1/Oem/Lenovo/SysvpdSettings')
|
||||
self.lenovobmcattrdeps = reginfo[3]
|
||||
return currsettings, reginfo
|
||||
|
||||
def _get_lnv_bmcstgs(self, fishclient):
|
||||
currsettings, reginfo = self._get_lnv_stgs(
|
||||
fishclient, '/redfish/v1/Managers/1/Oem/Lenovo/BMCSettings')
|
||||
self.lenovobmcattrdeps = reginfo[3]
|
||||
return currsettings, reginfo
|
||||
|
||||
def _get_lnv_stgs(self, fishclient, url):
|
||||
bmcstgs = fishclient._do_web_request(url)
|
||||
bmcreg = bmcstgs.get('AttributeRegistry', None)
|
||||
extrainfo = {}
|
||||
valtodisplay = {}
|
||||
currsettings = {}
|
||||
reginfo = {}, {}, {}, {}
|
||||
if bmcreg:
|
||||
reginfo = self._get_attrib_registry(fishclient, bmcreg)
|
||||
if reginfo:
|
||||
extrainfo, valtodisplay, _, _ = reginfo
|
||||
for setting in bmcstgs.get('Attributes', {}):
|
||||
val = bmcstgs['Attributes'][setting]
|
||||
currval = val
|
||||
val = valtodisplay.get(setting, {}).get(val, val)
|
||||
val = {'value': val}
|
||||
val.update(**extrainfo.get(setting, {}))
|
||||
currsettings[setting] = val
|
||||
return currsettings, reginfo
|
||||
|
||||
|
||||
Reference in New Issue
Block a user