2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-09-21 16:39:32 +00:00

Finish the server side SOL and cleanup paths

The console awaits its output handler, but both sample BMCs supplied a plain
function, and both dropped the send_data coroutine. virshbmc additionally
receives its stream callback on a libvirt thread, so the send goes through
run_coroutine_threadsafe against the loop captured at activation, called
asyncloop because the class already has a loop method it uses as a thread
target.

ServerConsole asked the session layer to retry, which a ServerSession cannot
do: it never runs Session.__init__, so it has no timeout, and its _timedout
does nothing. IpmiServer.logout was synchronous and an argument short while
_cleanup awaits logout(False). The boot options handler answered, then read an
unbound name and answered again with 0xff.
This commit is contained in:
Markus Hilger
2026-08-10 04:39:28 +02:00
parent 8521c6ad4b
commit 42ae44d5bf
5 changed files with 19 additions and 8 deletions
+2 -2
View File
@@ -73,10 +73,10 @@ class FakeBmc(bmc.Bmc):
def is_active(self):
return self.powerstate == 'on'
def iohandler(self, data):
async def iohandler(self, data):
print(data)
if self.sol:
self.sol.send_data(data)
await self.sol.send_data(data)
def main():
+9 -3
View File
@@ -39,8 +39,11 @@ def stream_callback(stream, events, console):
data = console.stream.recv(1024)
except Exception:
return
if console.sol:
console.sol.send_data(data)
if console.sol and console.asyncloop:
# libvirt calls this from its own event thread, and asyncio objects
# are not thread safe, so hand the send to the loop that owns them.
asyncio.run_coroutine_threadsafe(console.sol.send_data(data),
console.asyncloop)
class LibvirtBmc(bmc.Bmc):
@@ -54,6 +57,7 @@ class LibvirtBmc(bmc.Bmc):
self.domain = self.conn.lookupByName(domain)
self.state = self.domain.state(0)
self.stream = None
self.asyncloop = None
self.run_console = False
self.conn.domainEventRegister(lifecycle_callback, self)
self.sol_thread = None
@@ -108,6 +112,8 @@ class LibvirtBmc(bmc.Bmc):
return self.run_console
async def activate_payload(self, request, session):
# captured for stream_callback, which runs on a libvirt thread
self.asyncloop = asyncio.get_running_loop()
await super(LibvirtBmc, self).activate_payload(request, session)
self.run_console = True
self.sol_thread = threading.Thread(target=self.loop)
@@ -118,7 +124,7 @@ class LibvirtBmc(bmc.Bmc):
self.sol_thread.join()
await super(LibvirtBmc, self).deactivate_payload(request, session)
def iohandler(self, data):
async def iohandler(self, data):
if self.stream:
self.stream.send(data)
+3 -1
View File
@@ -132,7 +132,9 @@ class Bmc(serversession.IpmiServer):
try:
bootdevice = self.get_boot_device()
except NotImplementedError:
await session.send_ipmi_response(data=[1, 5, 0, 0, 0, 0, 0])
# nothing more to say, and bootdevice below would be unbound
return await session.send_ipmi_response(
data=[1, 5, 0, 0, 0, 0, 0])
if (type(bootdevice) != int
and bootdevice in ipmicommand.boot_devices):
bootdevice = ipmicommand.boot_devices[bootdevice]
+4 -1
View File
@@ -541,9 +541,12 @@ class ServerConsole(Console):
needskeepalive=False):
while not (self.connected or self.broken):
await session.Session.wait_for_rsp(timeout=10)
# retry is not passed on: a ServerSession has no retry timer, it
# never runs Session.__init__ and its _timedout does nothing, so
# asking for one only reaches for a timeout attribute it lacks.
await self.ipmi_session.send_payload(payload,
payload_type=payload_type,
retry=retry,
retry=False,
needskeepalive=needskeepalive)
def close(self):
@@ -412,5 +412,5 @@ class IpmiServer(object):
# per table 5-2, completion code 0xc1 is 'unrecognized'
await session.send_ipmi_response(code=0xc1)
def logout(self):
async def logout(self, sessionok=True):
pass