From 6909d1b5df3025ee063e8fae474eb21099d12f59 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Tue, 1 Sep 2026 23:52:25 +0200 Subject: [PATCH 1/2] 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: From 1d8dcae6b0e08a44b150f453ce09351957792bd2 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Tue, 1 Sep 2026 23:52:25 +0200 Subject: [PATCH 2/2] Refuse plainly when a BMC lists no interfaces at all Same function, one line above. EthernetInterfaces is optional, and when it is absent the None went into a request and raised TypeError from the url library rather than saying what was missing. Kept beside the ambiguous case because the two are one question asked twice. --- confluent_server/aiohmi/redfish/command.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/confluent_server/aiohmi/redfish/command.py b/confluent_server/aiohmi/redfish/command.py index 6f845911..644822e5 100644 --- a/confluent_server/aiohmi/redfish/command.py +++ b/confluent_server/aiohmi/redfish/command.py @@ -820,6 +820,11 @@ class Command(object): async def _get_bmc_nic_url(self, name=None): bmcinfo = await self._do_web_request(await self.get_bmcurl()) nicurl = bmcinfo.get('EthernetInterfaces', {}).get('@odata.id', None) + if not nicurl: + # Also optional. The None went straight into a request and + # raised TypeError out of the url library. + raise exc.UnsupportedFunctionality( + 'BMC publishes no network interface collection of its own') niclist = await self._do_web_request(nicurl) candidates = [] oem = await self.oem()