From 6909d1b5df3025ee063e8fae474eb21099d12f59 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Tue, 1 Sep 2026 23:52:25 +0200 Subject: [PATCH] Say which interfaces a multi-homed BMC has, rather than crash Dedicated plus shared is how BMCs are built, so several NICs is ordinary. _get_bmc_nic_url only reaches the count when the address the session came in on matches none of them, which is what a tunnel or a NAT does, and it then raised the bare PyghmiException base class. Confluent has no handler for the base class, so it fell through to the generic one and showed "Unexpected Error" plus a traceback, for a machine doing nothing wrong. UnsupportedFunctionality now, which the redfish plugin already reports plainly and which stays inside PyghmiException. The message said "does not have exactly one interface" without saying how many, which ones, or what to do. Every caller takes a name, so it lists the candidates, and the empty case reads differently from the ambiguous one. --- confluent_server/aiohmi/redfish/command.py | 30 +++++++++++++++------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/confluent_server/aiohmi/redfish/command.py b/confluent_server/aiohmi/redfish/command.py index 9fb4fdd3..6f845911 100644 --- a/confluent_server/aiohmi/redfish/command.py +++ b/confluent_server/aiohmi/redfish/command.py @@ -821,8 +821,7 @@ class Command(object): bmcinfo = await self._do_web_request(await self.get_bmcurl()) nicurl = bmcinfo.get('EthernetInterfaces', {}).get('@odata.id', None) niclist = await self._do_web_request(nicurl) - foundnics = 0 - lastnicurl = None + candidates = [] oem = await self.oem() for nic in niclist.get('Members', []): curl = nic.get('@odata.id', None) @@ -852,13 +851,26 @@ class Command(object): socket.AF_INET6, addrs.get('Address', '::')) if self._bmcv6ip == v6addr: return curl - foundnics += 1 - lastnicurl = curl - if name is None and foundnics != 1: - raise exc.PyghmiException( - 'BMC does not have exactly one interface') - if name is None: - return lastnicurl + candidates.append(curl) + if name is not None: + return None + if len(candidates) == 1: + return candidates[0] + # UnsupportedFunctionality, not the bare base class, which confluent + # maps through its generic handler and shows as "Unexpected Error". + if not candidates: + raise exc.UnsupportedFunctionality( + 'BMC published no enabled network interface of its own') + # Several NICs is ordinary. Reaching here means the address this + # session came in on matched none of them, which a tunnel or a NAT + # does, and picking one to reconfigure would be a guess. Every caller + # takes a name. + raise exc.UnsupportedFunctionality( + 'BMC has {0} enabled interfaces and none of them carries the ' + 'address this session connected to, so which one is meant cannot ' + 'be determined. Name one of: {1}'.format( + len(candidates), + ', '.join(url.rsplit('/', 1)[-1] for url in candidates))) async def _bmcresetinfo(self): if not self._varresetbmcurl: