2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-10-22 07:38:11 +00:00

Tell a bmc without DCMI apart from a failed request

There is no ipmi command for a bmc hostname, so get_hostname falls back to the
DCMI management controller identifier. A bmc that does not implement the DCMI
group at all rejects that with "invalid command", which was handed to the caller
as if the request had been bad: nodeconfig <node> bmc read seven fields
correctly and then reported "Error: Invalid command", and the api answered 500
Unexpected error.

Route every DCMI request through one helper that turns "invalid command" and
"command disabled or unavailable" into UnsupportedFunctionality, so the
identifier, the asset tag and the hostname all report a platform that cannot do
this rather than a fault. Where the caller asked about a hostname, say that
rather than naming DCMI.

The whole group read still ends in one error line, because an operation a
platform cannot perform and one that failed are the same message to the client.
That is worth separating, but not here.
This commit is contained in:
Markus Hilger
2026-08-13 23:50:55 +02:00
parent d9d9fa3df7
commit 58d56426ed
+34 -7
View File
@@ -1388,7 +1388,13 @@ class Command(object):
except exc.UnsupportedFunctionality:
# Use the DCMI MCI field as a fallback, since it's the closest
# thing in the IPMI Spec for this
return await self.get_mci()
try:
return await self.get_mci()
except exc.UnsupportedFunctionality:
# With neither an oem command nor DCMI there is nowhere left to
# look, and the caller asked about a hostname rather than DCMI
raise exc.UnsupportedFunctionality(
'The bmc hostname is not reported by this platform')
async def get_mci(self):
"""Set the management controller identifier.
@@ -1415,7 +1421,11 @@ class Command(object):
try:
return await self._oem.set_hostname(hostname)
except exc.UnsupportedFunctionality:
return await self.set_mci(hostname)
try:
return await self.set_mci(hostname)
except exc.UnsupportedFunctionality:
raise exc.UnsupportedFunctionality(
'The bmc hostname cannot be set on this platform')
async def set_mci(self, mci):
"""Set the management controller identifier.
@@ -1449,9 +1459,26 @@ class Command(object):
return await self._oem.set_asset_tag(tag)
return await self._chunkwise_dcmi_set(8, tag)
async def _dcmi_command(self, command, data):
"""Issue a DCMI command, telling a bmc without DCMI apart from a fault.
A bmc that does not implement the DCMI group at all rejects the command
outright, which is not the same thing as the request having been bad, and
the caller can offer something else or say plainly that the platform
cannot do it.
"""
try:
return await self.raw_command(netfn=0x2c, command=command,
data=data)
except exc.IpmiException as ie:
# invalid command, and command disabled or unavailable
if ie.ipmicode in (0xc1, 0xd6):
raise exc.UnsupportedFunctionality(
'This platform does not support the DCMI commands')
raise
async def _chunkwise_dcmi_fetch(self, command):
szdata = await self.raw_command(
netfn=0x2c, command=command, data=(0xdc, 0, 0))
szdata = await self._dcmi_command(command, (0xdc, 0, 0))
totalsize = bytearray(szdata['data'])[1]
chksize = 0xf
offset = 0
@@ -1459,8 +1486,8 @@ class Command(object):
while offset < totalsize:
if (offset + chksize) > totalsize:
chksize = totalsize - offset
chk = await self.raw_command(
netfn=0x2c, command=command, data=(0xdc, offset, chksize))
chk = await self._dcmi_command(command,
(0xdc, offset, chksize))
retstr += chk['data'][2:]
offset += chksize
if not isinstance(retstr, str):
@@ -1477,7 +1504,7 @@ class Command(object):
# set offset, otherwise the last setting will override
# the previous setting
offset += len(chunk)
await self.raw_command(netfn=0x2c, command=command, data=cmddata)
await self._dcmi_command(command, cmddata)
async def set_channel_access(self, channel=None,
access_update_mode='non_volatile',