aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-02-01 16:15:55 +0000
committerPeter Maydell <peter.maydell@linaro.org>2023-02-01 16:15:56 +0000
commit026817fb69414c9d3909d8b1a209f90180d777d6 (patch)
tree013be1b0b48eb4920c3bf713ded9bbcc142e734a
parent13356edb87506c148b163b8c7eb0695647d00c2a (diff)
parentbd4c0ef409140bd1be393407c04005ac077d4574 (diff)
Merge tag 'python-pull-request' of https://gitlab.com/jsnow/qemu into staging
Python Bits and pieces, kibbles'n'bits # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE+ber27ys35W+dsvQfe+BBqr8OQ4FAmPQlMIACgkQfe+BBqr8 # OQ5RIxAAqaG8Dx63CXa8WHMsGWc0CKTOcwTcRDw92GT3qhVkebZiNmNlZwckaU/c # CkVunJnU5T6T2qkploysUXwdlQ+XsY4fQlACNciZeffmT2E4siNQ/4H1uPB4xca6 # 8Sgmg2VH7OF+EWwuBihY1pbe7g+sOJg9w9isRduBnLGrLbOrewGIJBNbiVzFlz5W # 30RdvfLoUUak5qTlMT/6yl98r6fkkDmfPX653iYmpA/H/Ah+17ZJXB2XNigkqBdD # Cp8OxtFceKQdZOqNiADJRzT3Gore4lBkPnULKwct/5U0B/tUiBdZ2YDJW8EObUMY # zFE7giE5mCnyFSmfBmjKu8yS8zJm9NooYEjunTcodop/FDb96c3sh8376ZLamTii # /p5WSwfo4a6DXPUTx0aiCkqpeCdPncRgwKc5TvqyKLKxQHbfjt6UZrcL6iYbe6O6 # ltBcdvfdzL41TNjS678QqiGuYkADVa/nhig3ano4msx/Tf5e0O8eMoK9bDbVS9KF # QuONtOcut1YhnAHJp4oYN2Nimtr0t8j07iOOfc4X3+WwdbMCfR+toDM4wWVJ3u/O # 8Phy8hinfndMXdP9Q4eeFAiJ1zuD/XkpaKoDe0gHcEvp3zMEXmHiEOdv4hFeWTQB # ivU3oM/j2uVcHU4CSxra3B54vfLc1gudJ2yLPvhwPKoIRbJ/kbc= # =36NA # -----END PGP SIGNATURE----- # gpg: Signature made Wed 25 Jan 2023 02:32:34 GMT # gpg: using RSA key F9B7ABDBBCACDF95BE76CBD07DEF8106AAFC390E # gpg: Good signature from "John Snow (John Huston) <jsnow@redhat.com>" [full] # 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: python/qemu/machine: use socketpair() for QMP by default python/qmp/legacy: make QEMUMonitorProtocol accept a socket python/qmp/protocol: add open_with_socket() python/qmp: increase read buffer size python/machine: Fix AF_UNIX path too long on macOS python: QEMUMachine: enable qmp accept timeout by default Fix some typos Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--python/qemu/machine/console_socket.py2
-rw-r--r--python/qemu/machine/machine.py31
-rw-r--r--python/qemu/machine/qtest.py2
-rw-r--r--python/qemu/qmp/legacy.py18
-rw-r--r--python/qemu/qmp/protocol.py27
-rw-r--r--python/qemu/qmp/qmp_client.py4
-rw-r--r--python/qemu/qmp/qmp_tui.py6
-rw-r--r--tests/avocado/avocado_qemu/__init__.py2
8 files changed, 64 insertions, 28 deletions
diff --git a/python/qemu/machine/console_socket.py b/python/qemu/machine/console_socket.py
index 8c4ff598ad..4e28ba9bb2 100644
--- a/python/qemu/machine/console_socket.py
+++ b/python/qemu/machine/console_socket.py
@@ -68,7 +68,7 @@ class ConsoleSocket(socket.socket):
"""Kick off a thread to drain the socket."""
# Configure socket to not block and timeout.
# This allows our drain thread to not block
- # on recieve and exit smoothly.
+ # on receive and exit smoothly.
socket.socket.setblocking(self, False)
socket.socket.settimeout(self, 1)
drain_thread = threading.Thread(target=self._drain_fn)
diff --git a/python/qemu/machine/machine.py b/python/qemu/machine/machine.py
index 748a0d807c..e57c254484 100644
--- a/python/qemu/machine/machine.py
+++ b/python/qemu/machine/machine.py
@@ -131,7 +131,7 @@ class QEMUMachine:
drain_console: bool = False,
console_log: Optional[str] = None,
log_dir: Optional[str] = None,
- qmp_timer: Optional[float] = None):
+ qmp_timer: Optional[float] = 30):
'''
Initialize a QEMUMachine
@@ -157,18 +157,14 @@ class QEMUMachine:
self._wrapper = wrapper
self._qmp_timer = qmp_timer
- self._name = name or f"qemu-{os.getpid()}-{id(self):02x}"
+ self._name = name or f"{id(self):x}"
+ self._sock_pair: Optional[Tuple[socket.socket, socket.socket]] = None
self._temp_dir: Optional[str] = None
self._base_temp_dir = base_temp_dir
self._sock_dir = sock_dir
self._log_dir = log_dir
- if monitor_address is not None:
- self._monitor_address = monitor_address
- else:
- self._monitor_address = os.path.join(
- self.sock_dir, f"{self._name}-monitor.sock"
- )
+ self._monitor_address = monitor_address
self._console_log_path = console_log
if self._console_log_path:
@@ -192,7 +188,7 @@ class QEMUMachine:
self._console_set = False
self._console_device_type: Optional[str] = None
self._console_address = os.path.join(
- self.sock_dir, f"{self._name}-console.sock"
+ self.sock_dir, f"{self._name}.con"
)
self._console_socket: Optional[socket.socket] = None
self._remove_files: List[str] = []
@@ -303,7 +299,11 @@ class QEMUMachine:
args = ['-display', 'none', '-vga', 'none']
if self._qmp_set:
- if isinstance(self._monitor_address, tuple):
+ if self._sock_pair:
+ fd = self._sock_pair[0].fileno()
+ os.set_inheritable(fd, True)
+ moncdev = f"socket,id=mon,fd={fd}"
+ elif isinstance(self._monitor_address, tuple):
moncdev = "socket,id=mon,host={},port={}".format(
*self._monitor_address
)
@@ -337,10 +337,17 @@ class QEMUMachine:
self._remove_files.append(self._console_address)
if self._qmp_set:
+ monitor_address = None
+ sock = None
+ if self._monitor_address is None:
+ self._sock_pair = socket.socketpair()
+ sock = self._sock_pair[1]
if isinstance(self._monitor_address, str):
self._remove_files.append(self._monitor_address)
+ monitor_address = self._monitor_address
self._qmp_connection = QEMUMonitorProtocol(
- self._monitor_address,
+ address=monitor_address,
+ sock=sock,
server=True,
nickname=self._name
)
@@ -360,6 +367,8 @@ class QEMUMachine:
))
def _post_launch(self) -> None:
+ if self._sock_pair:
+ self._sock_pair[0].close()
if self._qmp_connection:
self._qmp.accept(self._qmp_timer)
diff --git a/python/qemu/machine/qtest.py b/python/qemu/machine/qtest.py
index 1a1fc6c9b0..1c46138bd0 100644
--- a/python/qemu/machine/qtest.py
+++ b/python/qemu/machine/qtest.py
@@ -42,7 +42,7 @@ class QEMUQtestProtocol:
:raise socket.error: on socket connection errors
.. note::
- No conection is estabalished by __init__(), this is done
+ No connection is established by __init__(), this is done
by the connect() or accept() methods.
"""
def __init__(self, address: SocketAddrT,
diff --git a/python/qemu/qmp/legacy.py b/python/qemu/qmp/legacy.py
index 1951754455..8b09ee7dbb 100644
--- a/python/qemu/qmp/legacy.py
+++ b/python/qemu/qmp/legacy.py
@@ -22,6 +22,7 @@ old interface.
#
import asyncio
+import socket
from types import TracebackType
from typing import (
Any,
@@ -69,22 +70,32 @@ class QEMUMonitorProtocol:
:param address: QEMU address, can be either a unix socket path (string)
or a tuple in the form ( address, port ) for a TCP
- connection
+ connection or None
+ :param sock: a socket or None
:param server: Act as the socket server. (See 'accept')
:param nickname: Optional nickname used for logging.
"""
- def __init__(self, address: SocketAddrT,
+ def __init__(self,
+ address: Optional[SocketAddrT] = None,
+ sock: Optional[socket.socket] = None,
server: bool = False,
nickname: Optional[str] = None):
+ assert address or sock
self._qmp = QMPClient(nickname)
self._aloop = asyncio.get_event_loop()
self._address = address
+ self._sock = sock
self._timeout: Optional[float] = None
if server:
- self._sync(self._qmp.start_server(self._address))
+ if sock:
+ assert self._sock is not None
+ 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')
@@ -139,6 +150,7 @@ class QEMUMonitorProtocol:
:return: QMP greeting dict, or None if negotiate is false
:raise ConnectError: on connection errors
"""
+ assert self._address is not None
self._qmp.await_greeting = negotiate
self._qmp.negotiate = negotiate
diff --git a/python/qemu/qmp/protocol.py b/python/qemu/qmp/protocol.py
index 6ea86650ad..6d3d739daa 100644
--- a/python/qemu/qmp/protocol.py
+++ b/python/qemu/qmp/protocol.py
@@ -18,6 +18,7 @@ from asyncio import StreamReader, StreamWriter
from enum import Enum
from functools import wraps
import logging
+import socket
from ssl import SSLContext
from typing import (
Any,
@@ -298,6 +299,19 @@ class AsyncProtocol(Generic[T]):
@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
+ @require(Runstate.IDLE)
async def start_server(self, address: SocketAddrT,
ssl: Optional[SSLContext] = None) -> None:
"""
@@ -343,11 +357,12 @@ class AsyncProtocol(Generic[T]):
protocol-level failure occurs while establishing a new
session, the wrapped error may also be an `QMPError`.
"""
- if self._accepted is None:
- raise QMPError("Cannot call accept() before start_server().")
- await self._session_guard(
- self._do_accept(),
- 'Failed to establish connection')
+ if not self._reader:
+ if self._accepted is None:
+ raise QMPError("Cannot call accept() before start_server().")
+ await self._session_guard(
+ self._do_accept(),
+ 'Failed to establish connection')
await self._session_guard(
self._establish_session(),
'Failed to establish session')
@@ -812,7 +827,7 @@ class AsyncProtocol(Generic[T]):
@bottom_half
async def _bh_close_stream(self, error_pathway: bool = False) -> None:
- # NB: Closing the writer also implcitly closes the reader.
+ # NB: Closing the writer also implicitly closes the reader.
if not self._writer:
return
diff --git a/python/qemu/qmp/qmp_client.py b/python/qemu/qmp/qmp_client.py
index 5dcda04a75..b5772e7f32 100644
--- a/python/qemu/qmp/qmp_client.py
+++ b/python/qemu/qmp/qmp_client.py
@@ -197,8 +197,8 @@ class QMPClient(AsyncProtocol[Message], Events):
#: Logger object used for debugging messages.
logger = logging.getLogger(__name__)
- # Read buffer limit; large enough to accept query-qmp-schema
- _limit = (256 * 1024)
+ # Read buffer limit; 10MB like libvirt default
+ _limit = (10 * 1024 * 1024)
# Type alias for pending execute() result items
_PendingT = Union[Message, ExecInterruptedError]
diff --git a/python/qemu/qmp/qmp_tui.py b/python/qemu/qmp/qmp_tui.py
index ce239d8979..8369144723 100644
--- a/python/qemu/qmp/qmp_tui.py
+++ b/python/qemu/qmp/qmp_tui.py
@@ -71,7 +71,7 @@ def format_json(msg: str) -> str:
due to an decoding error then a simple string manipulation is done to
achieve a single line JSON string.
- Converting into single line is more asthetically pleasing when looking
+ Converting into single line is more aesthetically pleasing when looking
along with error messages.
Eg:
@@ -91,7 +91,7 @@ def format_json(msg: str) -> str:
[1, true, 3]: QMP message is not a JSON object.
- The single line mode is more asthetically pleasing.
+ The single line mode is more aesthetically pleasing.
:param msg:
The message to formatted into single line.
@@ -498,7 +498,7 @@ class EditorWidget(urwid.Filler):
class HistoryBox(urwid.ListBox):
"""
This widget is modelled using the ListBox widget, contains the list of
- all messages both QMP messages and log messsages to be shown in the TUI.
+ all messages both QMP messages and log messages to be shown in the TUI.
The messages are urwid.Text widgets. On every append of a message, the
focus is shifted to the last appended message.
diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py
index 910f3ba1ea..25a546842f 100644
--- a/tests/avocado/avocado_qemu/__init__.py
+++ b/tests/avocado/avocado_qemu/__init__.py
@@ -306,7 +306,7 @@ class QemuSystemTest(QemuBaseTest):
self.cancel('no support for user networking')
def _new_vm(self, name, *args):
- self._sd = tempfile.TemporaryDirectory(prefix="avo_qemu_sock_")
+ self._sd = tempfile.TemporaryDirectory(prefix="qemu_")
vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir,
sock_dir=self._sd.name, log_dir=self.logdir)
self.log.debug('QEMUMachine "%s" created', name)