diff --git a/confluent_server/aiohmi/cmd/fakebmc.py b/confluent_server/aiohmi/cmd/fakebmc.py index 5a222241..3ccbabf8 100755 --- a/confluent_server/aiohmi/cmd/fakebmc.py +++ b/confluent_server/aiohmi/cmd/fakebmc.py @@ -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(): diff --git a/confluent_server/aiohmi/cmd/virshbmc.py b/confluent_server/aiohmi/cmd/virshbmc.py index d5e614e1..359ff97a 100755 --- a/confluent_server/aiohmi/cmd/virshbmc.py +++ b/confluent_server/aiohmi/cmd/virshbmc.py @@ -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) diff --git a/confluent_server/aiohmi/ipmi/bmc.py b/confluent_server/aiohmi/ipmi/bmc.py index 1a35bfa3..7ef57226 100644 --- a/confluent_server/aiohmi/ipmi/bmc.py +++ b/confluent_server/aiohmi/ipmi/bmc.py @@ -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] diff --git a/confluent_server/aiohmi/ipmi/console.py b/confluent_server/aiohmi/ipmi/console.py index d204e126..c68ca774 100644 --- a/confluent_server/aiohmi/ipmi/console.py +++ b/confluent_server/aiohmi/ipmi/console.py @@ -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): diff --git a/confluent_server/aiohmi/ipmi/private/serversession.py b/confluent_server/aiohmi/ipmi/private/serversession.py index a3288ec2..934ec0ca 100644 --- a/confluent_server/aiohmi/ipmi/private/serversession.py +++ b/confluent_server/aiohmi/ipmi/private/serversession.py @@ -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