python: introduce qmp-shell-wrap convenience tool
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>
This commit is contained in:
parent
31e3caf21b
commit
439125293c
@ -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()
|
||||
|
@ -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]
|
||||
|
11
scripts/qmp/qmp-shell-wrap
Executable file
11
scripts/qmp/qmp-shell-wrap
Executable file
@ -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()
|
Loading…
Reference in New Issue
Block a user