qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/2] python: introduce qmp-shell-wrap convenience tool


From: John Snow
Subject: Re: [PATCH 1/2] python: introduce qmp-shell-wrap convenience tool
Date: Mon, 17 Jan 2022 18:27:24 -0500

On Mon, Jan 17, 2022 at 9:11 AM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> 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>
> ---
>  python/qemu/qmp/qmp_shell.py | 61 +++++++++++++++++++++++++++++++++---
>  scripts/qmp/qmp-shell-wrap   | 11 +++++++
>  2 files changed, 68 insertions(+), 4 deletions(-)
>  create mode 100755 scripts/qmp/qmp-shell-wrap
>
> diff --git a/python/qemu/qmp/qmp_shell.py b/python/qemu/qmp/qmp_shell.py
> index e7d7eb18f1..12f7d28afc 100644
> --- a/python/qemu/qmp/qmp_shell.py
> +++ b/python/qemu/qmp/qmp_shell.py
> @@ -86,6 +86,7 @@
>  import os
>  import re
>  import readline
> +from subprocess import Popen
>  import sys
>  from typing import (
>      Iterator,
> @@ -162,8 +163,10 @@ class QMPShell(qmp.QEMUMonitorProtocol):
>      :param verbose: Echo outgoing QMP messages to console.
>      """
>      def __init__(self, address: qmp.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
> @@ -404,8 +407,10 @@ class HMPShell(QMPShell):
>      :param verbose: Echo outgoing QMP messages to console.
>      """
>      def __init__(self, address: qmp.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:
> @@ -529,6 +534,54 @@ def main() -> None:
>          for _ in qemu.repl():
>              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 qmp.QMPBadPortError:
> +        parser.error(f"Bad port number: {socketpath}")
> +        return  # pycharm doesn't know error() is noreturn
> +
> +    with shell_class(address, args.pretty, args.verbose, True) as qemu:
> +        qemuproc = Popen(cmd)
> +
> +        try:
> +            qemu.accept()
> +        except qmp.QMPConnectError:
> +            die("Didn't get QMP greeting message")
> +        except qmp.QMPCapabilitiesError:
> +            die("Couldn't negotiate capabilities")
> +        except OSError as err:
> +            die(f"Couldn't connect to {sockpath}: {err!s}")
> +
> +        for _ in qemu.repl():
> +            pass
>
>  if __name__ == '__main__':
>      main()
> diff --git a/scripts/qmp/qmp-shell-wrap b/scripts/qmp/qmp-shell-wrap
> new file mode 100755
> index 0000000000..9e94da114f
> --- /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()
> --
> 2.33.1
>

Adds some new failures to the python linters; try "make check-dev" in
the python sub-dir.

... Though, due to a bug in avocado, this helpfully doesn't actually
show you the failure output right now ...

making this little edit should fix that, sorry for the inconvenience here.

diff --git a/python/avocado.cfg b/python/avocado.cfg
index c7722e7ecd..a460420059 100644
--- a/python/avocado.cfg
+++ b/python/avocado.cfg
@@ -1,5 +1,5 @@
 [run]
-test_runner = runner
+test_runner = nrunner




reply via email to

[Prev in Thread] Current Thread [Next in Thread]