Python: synchronize python-qemu-qmp

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAmR3sUwACgkQfe+BBqr8
 OQ75GA/+NkO60LR6G7M68Wk2eaLlArlpWKa66lVTUPzIV+ERTzccjzFmEFhYM42z
 lJkkVieysuW/cFpjQqILSokfjiMOEH0XqC2R545vx0shZlExG6j6ky74jpFXxLCY
 1tnZ/wOB97D1nO273T6taGfS6ZPBULaL+J2iCBuruEQiM9OKDQTjojLQYn+hRokL
 BZHF5fkMDts92GHBJdUo8ftYDyblDQ2SUQqdq0pgBgkt+kHlQ4wFB7O39HUwKwT7
 rnAYz7EGbumYGwDkuNSIbpJ2pPiX7SxSPmmrebVPlQ79town3XATLraVbllls5eO
 8BvvkDakO7GvTkzcRvqcFnsnytWJvbEr0jPs1m8lQ2dMTv+NdZmsoItqGDP3LzVZ
 RU/Dr/8biKAbMXpSRH0Waddvmpb18I9I4U2NrVWDZ/vp6DqOFMgx/wUAVz0y0+3O
 M9o9Bj93YZhqBXhpShc75xjvaqJ10IzqG0roR0JbbskdbPmtIEvFlparxGDyH3cX
 UaQPKk8WdRCVOjtodqM28C441zMSUdL5ZCHB1LnMEhbTeV/MkR8W5KAXcYIzy2ay
 gh0FBYoiI8QNBGMR5AEpxdc3XKSSYFXlPGMz74yhlO1hWP1KZM1rE8OWHVfAPcwl
 T4xkw+Hoio9T6SlOWH4qwANaiaX9BII5Dv+L+UqqYt4+neeN8yk=
 =FvG2
 -----END PGP SIGNATURE-----

Merge tag 'python-pull-request' of https://gitlab.com/jsnow/qemu into staging

Python: synchronize python-qemu-qmp

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAmR3sUwACgkQfe+BBqr8
# OQ75GA/+NkO60LR6G7M68Wk2eaLlArlpWKa66lVTUPzIV+ERTzccjzFmEFhYM42z
# lJkkVieysuW/cFpjQqILSokfjiMOEH0XqC2R545vx0shZlExG6j6ky74jpFXxLCY
# 1tnZ/wOB97D1nO273T6taGfS6ZPBULaL+J2iCBuruEQiM9OKDQTjojLQYn+hRokL
# BZHF5fkMDts92GHBJdUo8ftYDyblDQ2SUQqdq0pgBgkt+kHlQ4wFB7O39HUwKwT7
# rnAYz7EGbumYGwDkuNSIbpJ2pPiX7SxSPmmrebVPlQ79town3XATLraVbllls5eO
# 8BvvkDakO7GvTkzcRvqcFnsnytWJvbEr0jPs1m8lQ2dMTv+NdZmsoItqGDP3LzVZ
# RU/Dr/8biKAbMXpSRH0Waddvmpb18I9I4U2NrVWDZ/vp6DqOFMgx/wUAVz0y0+3O
# M9o9Bj93YZhqBXhpShc75xjvaqJ10IzqG0roR0JbbskdbPmtIEvFlparxGDyH3cX
# UaQPKk8WdRCVOjtodqM28C441zMSUdL5ZCHB1LnMEhbTeV/MkR8W5KAXcYIzy2ay
# gh0FBYoiI8QNBGMR5AEpxdc3XKSSYFXlPGMz74yhlO1hWP1KZM1rE8OWHVfAPcwl
# T4xkw+Hoio9T6SlOWH4qwANaiaX9BII5Dv+L+UqqYt4+neeN8yk=
# =FvG2
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed 31 May 2023 01:42:52 PM PDT
# gpg:                using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E
# gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg:          There is no indication that the signature belongs to the owner.
# Primary key fingerprint: FAEB 9711 A12C F475 812F  18F2 88A9 064D 1835 61EB
#      Subkey fingerprint: F9B7 ABDB BCAC DF95 BE76  CBD0 7DEF 8106 AAFC 390E

* tag 'python-pull-request' of https://gitlab.com/jsnow/qemu:
  Revert "python/qmp/protocol: add open_with_socket()"
  python/qmp/legacy: remove open_with_socket() calls
  python/machine: use connect-based interface for existing sockets
  python/qmp/legacy: allow using sockets for connect()
  python/qmp: allow sockets to be passed to connect()

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-05-31 14:32:23 -07:00
commit 9824490ded
3 changed files with 41 additions and 47 deletions

View File

@ -337,18 +337,18 @@ class QEMUMachine:
self._remove_files.append(self._console_address) self._remove_files.append(self._console_address)
if self._qmp_set: if self._qmp_set:
monitor_address = None
sock = None
if self._monitor_address is None: if self._monitor_address is None:
self._sock_pair = socket.socketpair() self._sock_pair = socket.socketpair()
sock = self._sock_pair[1] sock = self._sock_pair[1]
if isinstance(self._monitor_address, str): if isinstance(self._monitor_address, str):
self._remove_files.append(self._monitor_address) self._remove_files.append(self._monitor_address)
monitor_address = self._monitor_address
sock_or_addr = self._monitor_address or sock
assert sock_or_addr is not None
self._qmp_connection = QEMUMonitorProtocol( self._qmp_connection = QEMUMonitorProtocol(
address=monitor_address, sock_or_addr,
sock=sock, server=bool(self._monitor_address),
server=True,
nickname=self._name nickname=self._name
) )
@ -370,7 +370,10 @@ class QEMUMachine:
if self._sock_pair: if self._sock_pair:
self._sock_pair[0].close() self._sock_pair[0].close()
if self._qmp_connection: if self._qmp_connection:
self._qmp.accept(self._qmp_timer) if self._sock_pair:
self._qmp.connect()
else:
self._qmp.accept(self._qmp_timer)
def _close_qemu_log_file(self) -> None: def _close_qemu_log_file(self) -> None:
if self._qemu_log_file is not None: if self._qemu_log_file is not None:

View File

@ -68,34 +68,31 @@ class QEMUMonitorProtocol:
Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP) Provide an API to connect to QEMU via QEMU Monitor Protocol (QMP)
and then allow to handle commands and events. and then allow to handle commands and events.
:param address: QEMU address, can be either a unix socket path (string) :param address: QEMU address, can be a unix socket path (string), a tuple
or a tuple in the form ( address, port ) for a TCP in the form ( address, port ) for a TCP connection, or an
connection or None existing `socket.socket` object.
:param sock: a socket or None
:param server: Act as the socket server. (See 'accept') :param server: Act as the socket server. (See 'accept')
Not applicable when passing a socket directly.
:param nickname: Optional nickname used for logging. :param nickname: Optional nickname used for logging.
""" """
def __init__(self, def __init__(self,
address: Optional[SocketAddrT] = None, address: Union[SocketAddrT, socket.socket],
sock: Optional[socket.socket] = None,
server: bool = False, server: bool = False,
nickname: Optional[str] = None): nickname: Optional[str] = None):
assert address or sock if server and isinstance(address, socket.socket):
raise ValueError(
"server argument should be False when passing a socket")
self._qmp = QMPClient(nickname) self._qmp = QMPClient(nickname)
self._aloop = asyncio.get_event_loop() self._aloop = asyncio.get_event_loop()
self._address = address self._address = address
self._sock = sock
self._timeout: Optional[float] = None self._timeout: Optional[float] = None
if server: if server:
if sock: assert not isinstance(self._address, socket.socket)
assert self._sock is not None self._sync(self._qmp.start_server(self._address))
self._sync(self._qmp.open_with_socket(self._sock))
else:
assert self._address is not None
self._sync(self._qmp.start_server(self._address))
_T = TypeVar('_T') _T = TypeVar('_T')
@ -150,7 +147,6 @@ class QEMUMonitorProtocol:
:return: QMP greeting dict, or None if negotiate is false :return: QMP greeting dict, or None if negotiate is false
:raise ConnectError: on connection errors :raise ConnectError: on connection errors
""" """
assert self._address is not None
self._qmp.await_greeting = negotiate self._qmp.await_greeting = negotiate
self._qmp.negotiate = negotiate self._qmp.negotiate = negotiate

View File

@ -297,19 +297,6 @@ class AsyncProtocol(Generic[T]):
await self.accept() await self.accept()
assert self.runstate == Runstate.RUNNING assert self.runstate == Runstate.RUNNING
@upper_half
@require(Runstate.IDLE)
async def open_with_socket(self, sock: socket.socket) -> None:
"""
Start connection with given socket.
:param sock: A socket.
:raise StateError: When the `Runstate` is not `IDLE`.
"""
self._reader, self._writer = await asyncio.open_connection(sock=sock)
self._set_state(Runstate.CONNECTING)
@upper_half @upper_half
@require(Runstate.IDLE) @require(Runstate.IDLE)
async def start_server(self, address: SocketAddrT, async def start_server(self, address: SocketAddrT,
@ -357,12 +344,11 @@ class AsyncProtocol(Generic[T]):
protocol-level failure occurs while establishing a new protocol-level failure occurs while establishing a new
session, the wrapped error may also be an `QMPError`. session, the wrapped error may also be an `QMPError`.
""" """
if not self._reader: if self._accepted is None:
if self._accepted is None: raise QMPError("Cannot call accept() before start_server().")
raise QMPError("Cannot call accept() before start_server().") await self._session_guard(
await self._session_guard( self._do_accept(),
self._do_accept(), 'Failed to establish connection')
'Failed to establish connection')
await self._session_guard( await self._session_guard(
self._establish_session(), self._establish_session(),
'Failed to establish session') 'Failed to establish session')
@ -370,7 +356,7 @@ class AsyncProtocol(Generic[T]):
@upper_half @upper_half
@require(Runstate.IDLE) @require(Runstate.IDLE)
async def connect(self, address: SocketAddrT, async def connect(self, address: Union[SocketAddrT, socket.socket],
ssl: Optional[SSLContext] = None) -> None: ssl: Optional[SSLContext] = None) -> None:
""" """
Connect to the server and begin processing message queues. Connect to the server and begin processing message queues.
@ -615,7 +601,7 @@ class AsyncProtocol(Generic[T]):
self.logger.debug("Connection accepted.") self.logger.debug("Connection accepted.")
@upper_half @upper_half
async def _do_connect(self, address: SocketAddrT, async def _do_connect(self, address: Union[SocketAddrT, socket.socket],
ssl: Optional[SSLContext] = None) -> None: ssl: Optional[SSLContext] = None) -> None:
""" """
Acting as the transport client, initiate a connection to a server. Acting as the transport client, initiate a connection to a server.
@ -634,9 +620,17 @@ class AsyncProtocol(Generic[T]):
# otherwise yield. # otherwise yield.
await asyncio.sleep(0) await asyncio.sleep(0)
self.logger.debug("Connecting to %s ...", address) if isinstance(address, socket.socket):
self.logger.debug("Connecting with existing socket: "
if isinstance(address, tuple): "fd=%d, family=%r, type=%r",
address.fileno(), address.family, address.type)
connect = asyncio.open_connection(
limit=self._limit,
ssl=ssl,
sock=address,
)
elif isinstance(address, tuple):
self.logger.debug("Connecting to %s ...", address)
connect = asyncio.open_connection( connect = asyncio.open_connection(
address[0], address[0],
address[1], address[1],
@ -644,13 +638,14 @@ class AsyncProtocol(Generic[T]):
limit=self._limit, limit=self._limit,
) )
else: else:
self.logger.debug("Connecting to file://%s ...", address)
connect = asyncio.open_unix_connection( connect = asyncio.open_unix_connection(
path=address, path=address,
ssl=ssl, ssl=ssl,
limit=self._limit, limit=self._limit,
) )
self._reader, self._writer = await connect
self._reader, self._writer = await connect
self.logger.debug("Connected.") self.logger.debug("Connected.")
@upper_half @upper_half