2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-02 15:36:05 +00:00

Implement the redfish resources that called missing methods

Five resources called methods that do not exist on the redfish client, so
each answered with an internal error naming the missing attribute: the leds,
the management controller identifier, the domain name, the remote kvm licence
and the alert destinations. Implement the first four from the manager network
protocol, the graphical console and the chassis indicator.

Alert destinations stay unimplemented on purpose. Redfish describes where to
send events with EventService subscriptions, which is a different model from
the numbered PET destinations this resource was built around, so say so and
drop the code that could never run.

The location resource fetched its data and discarded it, so a read produced
no output whatsoever.
This commit is contained in:
Markus Hilger
2026-08-13 18:10:05 +02:00
parent c1545cdf3f
commit b30ee29ff6
2 changed files with 123 additions and 38 deletions
+101
View File
@@ -1157,6 +1157,107 @@ class Command(object):
await self._do_web_request(await self.get_bmcnicurl(),
{'HostName': hostname}, 'PATCH', etag='*')
async def _netprotocolurl(self):
bmcinfo = await self._do_web_request(await self.get_bmcurl())
netprotocols = bmcinfo.get('NetworkProtocol', {}).get('@odata.id', None)
if not netprotocols:
raise exc.UnsupportedFunctionality(
'This platform does not describe its manager network protocols')
return netprotocols
async def get_mci(self):
"""Get the management controller identifier
Redfish has no separate identifier for a management controller the way
ipmi does, and the platforms that offer both report the same string for
each, so use the name the manager answers to.
"""
netcfg = await self._do_web_request(await self._netprotocolurl())
name = netcfg.get('HostName', None)
if name is None:
raise exc.UnsupportedFunctionality(
'This platform does not report a manager identifier')
return name
async def set_mci(self, mci):
await self._do_web_request(await self._netprotocolurl(),
{'HostName': mci}, method='PATCH', etag='*')
async def get_domain_name(self):
netcfg = await self._do_web_request(await self._netprotocolurl())
fqdn = netcfg.get('FQDN', None)
if not fqdn:
return ''
# The fqdn is the manager name with the domain appended, and only the
# domain part is wanted here
hostname = netcfg.get('HostName', None)
if hostname and fqdn.startswith(hostname + '.'):
return fqdn[len(hostname) + 1:]
return fqdn.partition('.')[2]
async def set_domain_name(self, domain):
netprotocols = await self._netprotocolurl()
netcfg = await self._do_web_request(netprotocols)
hostname = netcfg.get('HostName', '')
fqdn = '{0}.{1}'.format(hostname, domain) if domain else hostname
await self._do_web_request(netprotocols, {'FQDN': fqdn},
method='PATCH', etag='*')
async def get_remote_kvm_available(self):
bmcinfo = await self._do_web_request(await self.get_bmcurl())
gconsole = bmcinfo.get('GraphicalConsole', {})
return bool(gconsole.get('ServiceEnabled', False))
_ledstatusmap = {
'Lit': 'On',
'Blinking': 'Blink',
'Off': 'Off',
}
async def get_leds(self):
"""Get LED status information
Standard redfish only describes the identify indicator, so that is all a
platform without an oem specific view of its leds can report.
"""
sysinfo = await self.sysinfo()
seen = False
for chassis in sysinfo.get('Links', {}).get('Chassis', []):
chassisinfo = await self._do_web_request(chassis['@odata.id'])
state = chassisinfo.get('IndicatorLED', None)
if state is None:
continue
seen = True
yield ('identify', {'status': self._ledstatusmap.get(state, state)})
break
if not seen and sysinfo.get('IndicatorLED', None) is not None:
state = sysinfo['IndicatorLED']
yield ('identify', {'status': self._ledstatusmap.get(state, state)})
# A firmware inventory entry says what it belongs to with RelatedItem, so
# map the collections that turn up there onto the categories confluent asks
# for
_fwcategorybyurl = (
('/Drives/', 'disks'),
('/Storage/', 'disks'),
('/PCIeDevices/', 'adapters'),
('/NetworkAdapters/', 'adapters'),
('/NetworkInterfaces/', 'adapters'),
)
def _fwcategory(self, fwi):
"""Which category a firmware inventory entry belongs to.
Returns None when the entry gives nothing to judge by.
"""
related = fwi.get('RelatedItem', [])
for item in related:
url = item.get('@odata.id', '')
for frag, category in self._fwcategorybyurl:
if frag in url:
return category
return 'core' if related else None
async def get_firmware(self, components=(), category=None):
self._fwnamemap = {}
oem = await self.oem()
@@ -655,43 +655,13 @@ class IpmiHandler:
await self.ipmicmd.install_bmc_certificate(cert)
async def handle_alerts(self):
if self.element[3] == 'destinations':
if len(self.element) == 4:
# A list of destinations
maxdest = await self.ipmicmd.get_alert_destination_count()
for alertidx in range(0, maxdest + 1):
await self.output.put(msg.ChildCollection(alertidx))
return
elif len(self.element) == 5:
alertidx = int(self.element[-1])
if self.op == 'read':
destdata = await self.ipmicmd.get_alert_destination(alertidx)
await self.output.put(msg.AlertDestination(
ip=destdata['address'],
acknowledge=destdata['acknowledge_required'],
acknowledge_timeout=destdata.get('acknowledge_timeout', None),
retries=destdata['retries'],
name=self.node))
return
elif self.op == 'update':
alertparms = self.inputdata.alert_params_by_node(
self.node)
alertargs = {}
if 'acknowledge' in alertparms:
alertargs['acknowledge_required'] = alertparms['acknowledge']
if 'acknowledge_timeout' in alertparms:
alertargs['acknowledge_timeout'] = alertparms['acknowledge_timeout']
if 'ip' in alertparms:
alertargs['ip'] = alertparms['ip']
if 'retries' in alertparms:
alertargs['retries'] = alertparms['retries']
await self.ipmicmd.set_alert_destination(destination=alertidx,
**alertargs)
return
elif self.op == 'delete':
await self.ipmicmd.clear_alert_destination(alertidx)
return
raise Exception('Not implemented')
# Redfish describes where to send events with the EventService
# subscription collection, which is a different model from the numbered
# ipmi PET destinations this resource was built around, so say so rather
# than calling methods the redfish client does not have
raise pygexc.UnsupportedFunctionality(
'Alert destinations are not implemented for redfish, use the '
'EventService subscriptions on the bmc directly')
async def handle_nets(self):
if len(self.element) == 3:
@@ -1437,9 +1407,23 @@ class IpmiHandler:
await self.ipmicmd.set_domain_name(dn)
return
_locationfields = ('room', 'location', 'building', 'rack', 'contactnames')
async def handle_location_config(self):
if 'read' == self.op:
lc = await self.ipmicmd.get_location_information()
await self.output.put(msg.KeyValueData(
await self.ipmicmd.get_location_information(), self.node))
return
elif 'update' == self.op:
attribs = self.inputdata.get_attributes(self.node)
locargs = {x: attribs[x] for x in self._locationfields
if x in attribs}
if not locargs:
raise exc.InvalidArgumentException(
'Location accepts only: {0}'.format(
', '.join(self._locationfields)))
await self.ipmicmd.set_location_information(**locargs)
return
async def handle_bmcconfig(self, advanced=False, extended=False):
if 'read' == self.op: