01f9005feb
- Backport aqmp patches from upstream which can fix iotest issues * Patches added: python-aqmp-add-__del__-method-to-legacy.patch python-aqmp-add-_session_guard.patch python-aqmp-add-SocketAddrT-to-package-r.patch python-aqmp-add-socket-bind-step-to-lega.patch python-aqmp-add-start_server-and-accept-.patch python-aqmp-copy-type-definitions-from-q.patch python-aqmp-drop-_bind_hack.patch python-aqmp-fix-docstring-typo.patch python-aqmp-Fix-negotiation-with-pre-oob.patch python-aqmp-fix-race-condition-in-legacy.patch Python-aqmp-fix-type-definitions-for-myp.patch python-aqmp-handle-asyncio.TimeoutError-.patch python-aqmp-refactor-_do_accept-into-two.patch python-aqmp-remove-_new_session-and-_est.patch python-aqmp-rename-accept-to-start_serve.patch python-aqmp-rename-AQMPError-to-QMPError.patch python-aqmp-split-_client_connected_cb-o.patch python-aqmp-squelch-pylint-warning-for-t.patch python-aqmp-stop-the-server-during-disco.patch python-introduce-qmp-shell-wrap-convenie.patch python-machine-raise-VMLaunchFailure-exc.patch python-move-qmp-shell-under-the-AQMP-pac.patch python-move-qmp-utilities-to-python-qemu.patch python-qmp-switch-qmp-shell-to-AQMP.patch python-support-recording-QMP-session-to-.patch python-upgrade-mypy-to-0.780.patch - Drop the patches which are workaround to fix iotest issues * Patches dropped: Revert-python-iotests-replace-qmp-with-a.patch Revert-python-machine-add-instance-disam.patch Revert-python-machine-add-sock_dir-prope.patch Revert-python-machine-handle-fast-QEMU-t.patch Revert-python-machine-move-more-variable.patch Revert-python-machine-remove-_remove_mon.patch OBS-URL: https://build.opensuse.org/request/show/966963 OBS-URL: https://build.opensuse.org/package/show/Virtualization/qemu?expand=0&rev=708
168 lines
5.6 KiB
Diff
168 lines
5.6 KiB
Diff
From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= <berrange@redhat.com>
|
|
Date: Fri, 28 Jan 2022 16:11:56 +0000
|
|
Subject: python: introduce qmp-shell-wrap convenience tool
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
Git-commit: 439125293cc9cfb684eb4db23db04199f5f435a2
|
|
|
|
With the current 'qmp-shell' tool developers must first spawn QEMU with
|
|
a suitable -qmp arg and then spawn qmp-shell in a separate terminal
|
|
pointing to the right socket.
|
|
|
|
With 'qmp-shell-wrap' developers can ignore QMP sockets entirely and
|
|
just pass the QEMU command and arguments they want. The program will
|
|
listen on a UNIX socket and tell QEMU to connect QMP to that.
|
|
|
|
For example, this:
|
|
|
|
# qmp-shell-wrap -- qemu-system-x86_64 -display none
|
|
|
|
Is roughly equivalent of running:
|
|
|
|
# qemu-system-x86_64 -display none -qmp qmp-shell-1234 &
|
|
# qmp-shell qmp-shell-1234
|
|
|
|
Except that 'qmp-shell-wrap' switches the socket peers around so that
|
|
it is the UNIX socket server and QEMU is the socket client. This makes
|
|
QEMU reliably go away when qmp-shell-wrap exits, closing the server
|
|
socket.
|
|
|
|
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
|
|
Message-id: 20220128161157.36261-2-berrange@redhat.com
|
|
[Edited for rebase. --js]
|
|
Signed-off-by: John Snow <jsnow@redhat.com>
|
|
Signed-off-by: Li Zhang <lizhang@suse.de>
|
|
---
|
|
python/qemu/aqmp/qmp_shell.py | 65 ++++++++++++++++++++++++++++++++---
|
|
python/setup.cfg | 1 +
|
|
scripts/qmp/qmp-shell-wrap | 11 ++++++
|
|
3 files changed, 73 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/aqmp/qmp_shell.py
|
|
index d11bf54b00e5d56616ae57be0006..c60df787fcd50bf8a0109e5f5cd3 100644
|
|
--- a/python/qemu/aqmp/qmp_shell.py
|
|
+++ b/python/qemu/aqmp/qmp_shell.py
|
|
@@ -86,6 +86,7 @@ import logging
|
|
import os
|
|
import re
|
|
import readline
|
|
+from subprocess import Popen
|
|
import sys
|
|
from typing import (
|
|
Iterator,
|
|
@@ -167,8 +168,10 @@ class QMPShell(QEMUMonitorProtocol):
|
|
:param verbose: Echo outgoing QMP messages to console.
|
|
"""
|
|
def __init__(self, address: SocketAddrT,
|
|
- pretty: bool = False, verbose: bool = False):
|
|
- super().__init__(address)
|
|
+ pretty: bool = False,
|
|
+ verbose: bool = False,
|
|
+ server: bool = False):
|
|
+ super().__init__(address, server=server)
|
|
self._greeting: Optional[QMPMessage] = None
|
|
self._completer = QMPCompleter()
|
|
self._transmode = False
|
|
@@ -409,8 +412,10 @@ class HMPShell(QMPShell):
|
|
:param verbose: Echo outgoing QMP messages to console.
|
|
"""
|
|
def __init__(self, address: SocketAddrT,
|
|
- pretty: bool = False, verbose: bool = False):
|
|
- super().__init__(address, pretty, verbose)
|
|
+ pretty: bool = False,
|
|
+ verbose: bool = False,
|
|
+ server: bool = False):
|
|
+ super().__init__(address, pretty, verbose, server)
|
|
self._cpu_index = 0
|
|
|
|
def _cmd_completion(self) -> None:
|
|
@@ -533,5 +538,57 @@ def main() -> None:
|
|
pass
|
|
|
|
|
|
+def main_wrap() -> None:
|
|
+ """
|
|
+ qmp-shell-wrap entry point: parse command line arguments and
|
|
+ start the REPL.
|
|
+ """
|
|
+ parser = argparse.ArgumentParser()
|
|
+ parser.add_argument('-H', '--hmp', action='store_true',
|
|
+ help='Use HMP interface')
|
|
+ parser.add_argument('-v', '--verbose', action='store_true',
|
|
+ help='Verbose (echo commands sent and received)')
|
|
+ parser.add_argument('-p', '--pretty', action='store_true',
|
|
+ help='Pretty-print JSON')
|
|
+
|
|
+ parser.add_argument('command', nargs=argparse.REMAINDER,
|
|
+ help='QEMU command line to invoke')
|
|
+
|
|
+ args = parser.parse_args()
|
|
+
|
|
+ cmd = args.command
|
|
+ if len(cmd) != 0 and cmd[0] == '--':
|
|
+ cmd = cmd[1:]
|
|
+ if len(cmd) == 0:
|
|
+ cmd = ["qemu-system-x86_64"]
|
|
+
|
|
+ sockpath = "qmp-shell-wrap-%d" % os.getpid()
|
|
+ cmd += ["-qmp", "unix:%s" % sockpath]
|
|
+
|
|
+ shell_class = HMPShell if args.hmp else QMPShell
|
|
+
|
|
+ try:
|
|
+ address = shell_class.parse_address(sockpath)
|
|
+ except QMPBadPortError:
|
|
+ parser.error(f"Bad port number: {sockpath}")
|
|
+ return # pycharm doesn't know error() is noreturn
|
|
+
|
|
+ try:
|
|
+ with shell_class(address, args.pretty, args.verbose, True) as qemu:
|
|
+ with Popen(cmd):
|
|
+
|
|
+ try:
|
|
+ qemu.accept()
|
|
+ except ConnectError as err:
|
|
+ if isinstance(err.exc, OSError):
|
|
+ die(f"Couldn't connect to {args.qmp_server}: {err!s}")
|
|
+ die(str(err))
|
|
+
|
|
+ for _ in qemu.repl():
|
|
+ pass
|
|
+ finally:
|
|
+ os.unlink(sockpath)
|
|
+
|
|
+
|
|
if __name__ == '__main__':
|
|
main()
|
|
diff --git a/python/setup.cfg b/python/setup.cfg
|
|
index 0063c757b78638ef651a362af338..bec54e8b0d663191e2b7afbfa350 100644
|
|
--- a/python/setup.cfg
|
|
+++ b/python/setup.cfg
|
|
@@ -68,6 +68,7 @@ console_scripts =
|
|
qom-fuse = qemu.utils.qom_fuse:QOMFuse.entry_point [fuse]
|
|
qemu-ga-client = qemu.utils.qemu_ga_client:main
|
|
qmp-shell = qemu.aqmp.qmp_shell:main
|
|
+ qmp-shell-wrap = qemu.aqmp.qmp_shell:main_wrap
|
|
aqmp-tui = qemu.aqmp.aqmp_tui:main [tui]
|
|
|
|
[flake8]
|
|
diff --git a/scripts/qmp/qmp-shell-wrap b/scripts/qmp/qmp-shell-wrap
|
|
new file mode 100755
|
|
index 0000000000000000000000000000000000000000..9e94da114f5f87588639f6b2cc636391e80c3864
|
|
--- /dev/null
|
|
+++ b/scripts/qmp/qmp-shell-wrap
|
|
@@ -0,0 +1,11 @@
|
|
+#!/usr/bin/env python3
|
|
+
|
|
+import os
|
|
+import sys
|
|
+
|
|
+sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'python'))
|
|
+from qemu.qmp import qmp_shell
|
|
+
|
|
+
|
|
+if __name__ == '__main__':
|
|
+ qmp_shell.main_wrap()
|