From a69d828e6938c0423b2cd6f73833676be9c13464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20Ferr=C3=A3o?= <2031761+viniciusferrao@users.noreply.github.com> Date: Sat, 2 May 2026 22:56:39 -0300 Subject: [PATCH] Remove eventlet dependency, migrate to asyncio/concurrent.futures Replace eventlet.greenpool with concurrent.futures.ThreadPoolExecutor in the BMC discovery script, using as_completed() for proper exception propagation and main-thread result aggregation to avoid race conditions. Remove dead eventlet socket compatibility code (.fd attribute checks) from the IPMI session layer, and clean up stale eventlet references in comments across the codebase. Closes: xcat2/confluent#197 --- .../aiohmi/ipmi/private/session.py | 21 ++--------- confluent_server/confluent/debugger.py | 2 - confluent_server/confluent/syncfiles.py | 5 +-- misc/cfg-dhcp-redfish-bmcs-by-switch.py | 37 ++++++++++++------- 4 files changed, 29 insertions(+), 36 deletions(-) diff --git a/confluent_server/aiohmi/ipmi/private/session.py b/confluent_server/aiohmi/ipmi/private/session.py index 23e15db6..ce66361d 100644 --- a/confluent_server/aiohmi/ipmi/private/session.py +++ b/confluent_server/aiohmi/ipmi/private/session.py @@ -57,12 +57,8 @@ except AttributeError: # in case of congestion initialtimeout = 0.5 # the thread in which all IO will be performed -# While the model as-is works fine for it's own coroutine -# structure, when combined with threading or something like -# eventlet, it becomes difficult for the calling code to cope -# This thread will tuck away the threading situation such that -# calling code doesn't have to do any gymnastics to cope with -# the nature of things. +# This thread tucks away the threading situation such that +# calling code doesn't have to do any gymnastics. iothread = None # whether io thread is yet ready to work iothreadready = False @@ -186,24 +182,13 @@ async def _io_wait(timeout, myaddr=None, evq=None): evq.append(evt) deadline = timeout + _monotonic_time() ioqueue.append((deadline, evt, myaddr)) - # Unfortunately, at least with eventlet patched threading, the wait() - # is a somewhat busy wait if given a deadline. Workaround by having - # it piggy back on the select() in the io thread, which is a truly - # lazy wait even with eventlet involvement if deadline < selectdeadline: - intsock = iosockets[0] - if hasattr(intsock, 'fd'): - # if in eventlet, go for the true sendto, which is less glitchy - intsock = intsock.fd - intsock.sendto(b'\x01', (myself, iosockets[0].getsockname()[1])) + iosockets[0].sendto(b'\x01', (myself, iosockets[0].getsockname()[1])) await evt.wait() def _io_sendto(mysocket, packet, sockaddr): - # Want sendto to act reasonably sane.. mysocket.setblocking(1) - if hasattr(mysocket, 'fd'): - mysocket = mysocket.fd try: mysocket.sendto(packet, sockaddr) except Exception: diff --git a/confluent_server/confluent/debugger.py b/confluent_server/confluent/debugger.py index 85ec283b..557835a2 100644 --- a/confluent_server/confluent/debugger.py +++ b/confluent_server/confluent/debugger.py @@ -5,8 +5,6 @@ import socket import sys import confluent.tasks as tasks -#this will ultimately fill the role of the 'backdoor' of eventlet - # since we have to asyncio up the input and output, we use InteractiveInterpreter and handle the # input ourselves, since code is not asyncio friendly in and of itself #code.InteractiveConsole().interact() diff --git a/confluent_server/confluent/syncfiles.py b/confluent_server/confluent/syncfiles.py index 2c7edf96..426c0021 100644 --- a/confluent_server/confluent/syncfiles.py +++ b/confluent_server/confluent/syncfiles.py @@ -199,9 +199,8 @@ async def sync_list_to_node(sl, node, suffixes, peerip=None): 'rsync', '-rvLD', targdir + '/', 'root@[{}]:/'.format(targip)) except Exception as e: if 'CalledProcessError' not in repr(e): - # https://github.com/eventlet/eventlet/issues/413 - # for some reason, can't catch the calledprocesserror normally - # for this exception, implement a hack workaround + # CalledProcessError can't be caught normally in some contexts, + # so check via repr as a workaround raise unreadablefiles = [] for root, dirnames, filenames in os.walk(targdir): diff --git a/misc/cfg-dhcp-redfish-bmcs-by-switch.py b/misc/cfg-dhcp-redfish-bmcs-by-switch.py index fe304ae3..a0249641 100755 --- a/misc/cfg-dhcp-redfish-bmcs-by-switch.py +++ b/misc/cfg-dhcp-redfish-bmcs-by-switch.py @@ -32,18 +32,17 @@ import sys sys.path.append('/opt/confluent/lib/python') +import concurrent.futures import confluent.client as cli -import eventlet.greenpool import gzip import io import json import os import struct import subprocess +import pyghmi.util.webclient as webclient import time -webclient = eventlet.import_patched('pyghmi.util.webclient') - bmcsbyuuid = {} def checkfish(addr, mac): @@ -57,10 +56,10 @@ def checkfish(addr, mac): try: body = json.loads(body) except json.decoder.JSONDecodeError: - return + return None uuid = body.get('UUID', None) if not uuid: - return + return None #This part is needed if a bmc sticks 'wire format' uuid in the json body #Should be skipped for bmcs that present it sanely uuidparts = uuid.split('-') @@ -68,14 +67,10 @@ def checkfish(addr, mac): uuidparts[1] = '{:04x}'.format(struct.unpack('!H', struct.pack('