From 91654ea0d19c6f624c9a64cb56037dd7dfe2e694 Mon Sep 17 00:00:00 2001 From: Markus Hilger Date: Sun, 12 Jul 2026 23:53:39 +0200 Subject: [PATCH] Fix aiohmi async call contracts --- confluent_server/aiohmi/ipmi/command.py | 9 ++-- .../aiohmi/ipmi/oem/lenovo/handler.py | 42 +++++++++---------- .../aiohmi/ipmi/oem/lenovo/nextscale.py | 8 ++-- .../aiohmi/ipmi/private/localsession.py | 1 + confluent_server/aiohmi/ipmi/sdr.py | 16 +++---- .../aiohmi/redfish/oem/generic.py | 13 +++--- .../aiohmi/redfish/oem/lenovo/smm3.py | 3 +- .../aiohmi/redfish/oem/lenovo/xcc.py | 16 +++---- 8 files changed, 55 insertions(+), 53 deletions(-) diff --git a/confluent_server/aiohmi/ipmi/command.py b/confluent_server/aiohmi/ipmi/command.py index d4f0cfaf..a7f4723b 100644 --- a/confluent_server/aiohmi/ipmi/command.py +++ b/confluent_server/aiohmi/ipmi/command.py @@ -738,7 +738,8 @@ class Command(object): This provides a detailed view of the LEDs of the managed system. """ await self.oem_init() - return await self._oem.get_leds() + async for led in self._oem.get_leds(): + yield led async def get_ntp_enabled(self): await self.oem_init() @@ -806,7 +807,7 @@ class Command(object): rsp = await self.raw_command(command=0x2d, netfn=4, rslun=currsensor.sensor_lun, data=(currsensor.sensor_number,)) - return self._sdr.sensors[sensor].decode_sensor_reading( + return await self._sdr.sensors[sensor].decode_sensor_reading( self, rsp['data']) await self.oem_init() return await self._oem.get_sensor_reading(sensorname) @@ -1091,7 +1092,7 @@ class Command(object): if rsp['code'] == 203: # Sensor does not exist, optional dev continue raise exc.IpmiException(rsp['error'], code=rsp['code']) - yield self._sdr.sensors[sensor].\ + yield await self._sdr.sensors[sensor].\ decode_sensor_reading(self, rsp['data']) await self.oem_init() async for reading in self._oem.get_sensor_data(): @@ -2311,4 +2312,4 @@ class Command(object): """ await self.oem_init() - return await self._oem.set_oem_extended_privilleges(uid) \ No newline at end of file + return await self._oem.set_oem_extended_privilleges(uid) diff --git a/confluent_server/aiohmi/ipmi/oem/lenovo/handler.py b/confluent_server/aiohmi/ipmi/oem/lenovo/handler.py index eaff7789..65186e69 100755 --- a/confluent_server/aiohmi/ipmi/oem/lenovo/handler.py +++ b/confluent_server/aiohmi/ipmi/oem/lenovo/handler.py @@ -336,9 +336,9 @@ class OEMHandler(generic.OEMHandler): event['component'] += ' {0}'.format(evdata[1] & 0b11111) async def reseat_bay(self, bay): - if self.is_fpc: + if await self.is_fpc(): return await self.smmhandler.reseat_bay(bay) - elif self.has_xcc and bay == -1: + elif await self.has_xcc() and bay == -1: return await self.immhandler.reseat() return await super(OEMHandler, self).reseat_bay(bay) @@ -347,7 +347,7 @@ class OEMHandler(generic.OEMHandler): ntpres = await self.ipmicmd.raw_command(netfn=0x32, command=0xa7) return ntpres['data'][0] == '\x01' elif await self.is_fpc(): - return await self.smmhandler.get_ntp_enabled(self._fpc_variant) + return self.smmhandler.get_ntp_enabled(self._fpc_variant) elif self.has_tsma: return await self.tsmahandler.get_ntp_enabled() return None @@ -360,7 +360,7 @@ class OEMHandler(generic.OEMHandler): srvs.append(ntpres['data'][129:257].rstrip('\x00')) return srvs if await self.is_fpc(): - return await self.smmhandler.get_ntp_servers() + return self.smmhandler.get_ntp_servers() if self.has_tsma: return await self.tsmahandler.get_ntp_servers() return () @@ -375,7 +375,7 @@ class OEMHandler(generic.OEMHandler): netfn=0x32, command=0xa8, data=(3, 0), timeout=15) return True if await self.is_fpc(): - await self.smmhandler.set_ntp_enabled(enabled) + self.smmhandler.set_ntp_enabled(enabled) return True if self.has_tsma: await self.tsmahandler.set_ntp_enabled(enabled) @@ -393,7 +393,7 @@ class OEMHandler(generic.OEMHandler): if not 0 <= index <= 2: raise pygexc.InvalidParameterValue( 'SMM supports indexes 0 through 2') - await self.smmhandler.set_ntp_server(server, index) + self.smmhandler.set_ntp_server(server, index) return True elif self.has_tsma: if not (0 <= index <= 1): @@ -516,7 +516,7 @@ class OEMHandler(generic.OEMHandler): elif await self.is_fpc(): async for compname in self.smmhandler.get_inventory_descriptions( self.ipmicmd, await self.is_fpc()): - yield (compname, self.smmhandler.get_inventory_of_component( + yield (compname, await self.smmhandler.get_inventory_of_component( self.ipmicmd, compname)) async def get_sensor_data(self): @@ -561,14 +561,14 @@ class OEMHandler(generic.OEMHandler): async def get_inventory_of_component(self, component): if await self.has_tsm() or await self.has_ami() or await self.has_asrock(): await self._collect_tsm_inventory() - return await self.oem_inventory_info.get(component, None) + return self.oem_inventory_info.get(component, None) if await self.has_imm(): return await self.immhandler.get_component_inventory(component) if await self.is_fpc(): - return await self.smmhandler.get_inventory_of_component(component) + return await self.smmhandler.get_inventory_of_component(self.ipmicmd, component) - def get_cmd_type(self, categorie_item, catspec): - if self.has_asrock: + async def get_cmd_type(self, categorie_item, catspec): + if await self.has_asrock(): cmd_type = catspec["command"]["asrock"] elif categorie_item in categorie_items: cmd_type = catspec["command"]["lenovo"] @@ -579,9 +579,7 @@ class OEMHandler(generic.OEMHandler): async def _collect_tsm_inventory(self): self.oem_inventory_info = {} - asrock = False - if self.has_asrock: - asrock = True + asrock = await self.has_asrock() for catid, catspec in inventory.categories.items(): # skip the inventory fields if the system is RS160 if asrock and catid not in categorie_items: @@ -590,7 +588,7 @@ class OEMHandler(generic.OEMHandler): and catspec["workaround_bmc_bug"]( "ami" if await self.has_ami() else "lenovo")): rsp = None - cmd = self.get_cmd_type(catid, catspec) + cmd = await self.get_cmd_type(catid, catspec) tmp_command = dict(cmd) tmp_command["data"] = list(tmp_command["data"]) count = 0 @@ -617,7 +615,7 @@ class OEMHandler(generic.OEMHandler): rsp["data"] = buffer(bytearray(rsp["data"])) else: try: - cmd = self.get_cmd_type(catid, catspec) + cmd = await self.get_cmd_type(catid, catspec) rsp = await self.ipmicmd.raw_command(**cmd) except pygexc.IpmiException: continue @@ -852,7 +850,7 @@ class OEMHandler(generic.OEMHandler): async def get_oem_firmware(self, bmcver, components, category): if await self.has_tsm() or await self.has_ami() or await self.has_asrock(): command = firmware.get_categories()["firmware"] - fw_cmd = self.get_cmd_type("firmware", command) + fw_cmd = await self.get_cmd_type("firmware", command) rsp = await self.ipmicmd.raw_command(**fw_cmd) # the newest Lenovo ThinkServer versions are returning Bios version @@ -860,7 +858,7 @@ class OEMHandler(generic.OEMHandler): bios_versions = None if await self.has_tsm() or await self.has_asrock(): bios_command = firmware.get_categories()["bios_version"] - bios_cmd = self.get_cmd_type("bios_version", bios_command) + bios_cmd = await self.get_cmd_type("bios_version", bios_command) bios_rsp = await self.ipmicmd.raw_command(**bios_cmd) if await self.has_asrock(): bios_versions = bios_rsp['data'] @@ -943,7 +941,7 @@ class OEMHandler(generic.OEMHandler): name += rsp['data'][:] return name.rstrip('\x00') elif await self.is_fpc(): - return await self.smmhandler.get_domain() + return self.smmhandler.get_domain() async def set_oem_domain_name(self, name): if await self.has_tsm(): @@ -962,20 +960,20 @@ class OEMHandler(generic.OEMHandler): await self._restart_dns() return elif await self.is_fpc(): - await self.smmhandler.set_domain(name) + self.smmhandler.set_domain(name) async def set_hostname(self, hostname): if await self.has_xcc(): return await self.immhandler.set_hostname(hostname) elif await self.is_fpc(): - return await self.smmhandler.set_hostname(hostname) + return self.smmhandler.set_hostname(hostname) return await super(OEMHandler, self).set_hostname(hostname) async def get_hostname(self): if await self.has_xcc(): return await self.immhandler.get_hostname() elif await self.is_fpc(): - return await self.smmhandler.get_hostname() + return self.smmhandler.get_hostname() return await super(OEMHandler, self).get_hostname() """ Gets a remote console launcher for a Lenovo ThinkServer. diff --git a/confluent_server/aiohmi/ipmi/oem/lenovo/nextscale.py b/confluent_server/aiohmi/ipmi/oem/lenovo/nextscale.py index 56adf001..1c15d507 100644 --- a/confluent_server/aiohmi/ipmi/oem/lenovo/nextscale.py +++ b/confluent_server/aiohmi/ipmi/oem/lenovo/nextscale.py @@ -1061,16 +1061,16 @@ class SMMClient(object): complete = percent >= 100.0 return 'complete' - def get_inventory_descriptions(self, ipmicmd, variant): + async def get_inventory_descriptions(self, ipmicmd, variant): if variant >> 5 == 0: return - psucount = get_psu_count(ipmicmd, variant) + psucount = await get_psu_count(ipmicmd, variant) for idx in range(psucount): yield 'PSU {}'.format(idx + 1) - def get_inventory_of_component(self, ipmicmd, component): + async def get_inventory_of_component(self, ipmicmd, component): psuidx = int(component.replace('PSU ', '')) - return self.get_psu_info(ipmicmd, psuidx) + return await self.get_psu_info(ipmicmd, psuidx) async def get_psu_info(self, ipmicmd, psunum): psuinfo = await ipmicmd.raw_command(0x34, 0x6, data=(psunum,)) diff --git a/confluent_server/aiohmi/ipmi/private/localsession.py b/confluent_server/aiohmi/ipmi/private/localsession.py index 2489d272..82b0a7b5 100644 --- a/confluent_server/aiohmi/ipmi/private/localsession.py +++ b/confluent_server/aiohmi/ipmi/private/localsession.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio import ctypes import fcntl from select import select diff --git a/confluent_server/aiohmi/ipmi/sdr.py b/confluent_server/aiohmi/ipmi/sdr.py index d2855525..fcf05d3c 100644 --- a/confluent_server/aiohmi/ipmi/sdr.py +++ b/confluent_server/aiohmi/ipmi/sdr.py @@ -475,7 +475,7 @@ class SDREntry(object): health = const.Health.Ok return desc, health - def decode_sensor_reading(self, ipmicmd, reading): + async def decode_sensor_reading(self, ipmicmd, reading): numeric = None output = { 'name': self.sensor_name, @@ -495,8 +495,8 @@ class SDREntry(object): if numeric is not None: lowerbound = numeric - (0.5 + (self.tolerance / 2.0)) upperbound = numeric + (0.5 + (self.tolerance / 2.0)) - lowerbound = self.decode_value(ipmicmd, lowerbound) - upperbound = self.decode_value(ipmicmd, upperbound) + lowerbound = await self.decode_value(ipmicmd, lowerbound) + upperbound = await self.decode_value(ipmicmd, upperbound) output['value'] = (lowerbound + upperbound) / 2.0 output['imprecision'] = output['value'] - lowerbound discrete = False @@ -552,13 +552,13 @@ class SDREntry(object): output['state_ids'].append(self.assert_trap_value(6)) return SensorReading(output, self.unit_suffix) - def _set_tmp_formula(self, ipmicmd, value): - rsp = ipmicmd.raw_command(netfn=4, command=0x23, - data=(self.sensor_number, value)) + async def _set_tmp_formula(self, ipmicmd, value): + rsp = await ipmicmd.raw_command(netfn=4, command=0x23, + data=(self.sensor_number, value)) # skip next reading field, not used in on-demand situation self.decode_formula(rsp['data'][1:]) - def decode_value(self, ipmicmd, value): + async def decode_value(self, ipmicmd, value): # Take the input value and return meaningful value linearization = self.linearization if linearization > 11: # direct calling code to get factors @@ -568,7 +568,7 @@ class SDREntry(object): # fashion. However for now opt for retrieving rows as needed # rather than tracking all that information for a relatively # rare behavior - self._set_tmp_formula(ipmicmd, value) + await self._set_tmp_formula(ipmicmd, value) linearization = 0 # time to compute the pre-linearization value. decoded = float((value * self.m + self.b) diff --git a/confluent_server/aiohmi/redfish/oem/generic.py b/confluent_server/aiohmi/redfish/oem/generic.py index 87c052a2..df053980 100644 --- a/confluent_server/aiohmi/redfish/oem/generic.py +++ b/confluent_server/aiohmi/redfish/oem/generic.py @@ -660,8 +660,8 @@ class OEMHandler(object): procurl = sysinfo.get('Processors', {}).get('@odata.id', None) if procurl: - for cpu in await fishclient._do_web_request(procurl).get( - 'Members', []): + procinfo = await fishclient._do_web_request(procurl) + for cpu in procinfo.get('Members', []): cinfo = await fishclient._do_web_request(cpu['@odata.id']) if cinfo.get('Status', {}).get( 'State', None) == 'Absent': @@ -1004,8 +1004,9 @@ class OEMHandler(object): def _extract_fwinfo(self, inf): return {} - def get_firmware_inventory(self, components, fishclient, category=None): - return [] + async def get_firmware_inventory(self, components, fishclient, category=None): + return + yield def set_credentials(self, username, password): try: @@ -1240,7 +1241,7 @@ class OEMHandler(object): if not foundmacs: # No PCIe device inventory, but *maybe* ethernet inventory... idxsbyname = {} - for nicinfo in self._get_eth_urls(): + for nicinfo in await self._get_eth_urls(): nicinfo = await self._do_web_request(nicinfo) nicname = nicinfo.get('Name', None) nicinfo = nicinfo.get('MACAddress', nicinfo.get('PermanentAddress', None)) @@ -1675,7 +1676,7 @@ class OEMHandler(object): await fishclient._do_web_request(licenses, licinfo) - def get_user_expiration(self, uid): + async def get_user_expiration(self, uid): return None async def reseat_bay(self, bay): diff --git a/confluent_server/aiohmi/redfish/oem/lenovo/smm3.py b/confluent_server/aiohmi/redfish/oem/lenovo/smm3.py index 959c967d..1da4165e 100644 --- a/confluent_server/aiohmi/redfish/oem/lenovo/smm3.py +++ b/confluent_server/aiohmi/redfish/oem/lenovo/smm3.py @@ -286,7 +286,8 @@ class OEMHandler(generic.OEMHandler): rsp = await self._do_web_request(url, method='POST') async def get_event_log(self, clear=False, fishclient=None): - return await super().get_event_log(clear, fishclient, extraurls=[{'@odata.id':'/redfish/v1/Chassis/chassis1/LogServices/EventLog'}]) + async for event in super().get_event_log(clear, fishclient, extraurls=[{'@odata.id':'/redfish/v1/Chassis/chassis1/LogServices/EventLog'}]): + yield event async def get_description(self, fishclient): return {'height': 13, 'slot': 0, 'slots': [8, 2]} diff --git a/confluent_server/aiohmi/redfish/oem/lenovo/xcc.py b/confluent_server/aiohmi/redfish/oem/lenovo/xcc.py index 575b3726..09fd1a11 100644 --- a/confluent_server/aiohmi/redfish/oem/lenovo/xcc.py +++ b/confluent_server/aiohmi/redfish/oem/lenovo/xcc.py @@ -1757,18 +1757,18 @@ class OEMHandler(generic.OEMHandler): else: return days - def get_inventory_descriptions(self, withids=False): - hwmap = self.hardware_inventory_map() + async def get_inventory_descriptions(self, withids=False): + hwmap = await self.hardware_inventory_map() yield "System" for key in natural_sort(hwmap): yield key - for cpuinv in self._get_cpu_inventory(): + async for cpuinv in self._get_cpu_inventory(): yield cpuinv[0] - for meminv in self._get_mem_inventory(): + async for meminv in self._get_mem_inventory(): yield meminv[0] - def get_inventory_of_component(self, compname): + async def get_inventory_of_component(self, compname): if compname.lower() == 'system': sysinfo = { 'UUID': self._varsysinfo.get('UUID', ''), @@ -1779,14 +1779,14 @@ class OEMHandler(generic.OEMHandler): 'SKU', self._varsysinfo.get('PartNumber', '')), } return sysinfo - hwmap = self.hardware_inventory_map() + hwmap = await self.hardware_inventory_map() try: return hwmap[compname] except KeyError: - for cpuinv in self._get_cpu_inventory(): + async for cpuinv in self._get_cpu_inventory(): if cpuinv[0] == compname: return cpuinv[1] - for meminv in self._get_mem_inventory(): + async for meminv in self._get_mem_inventory(): if meminv[0] == compname: return meminv[1]