From: Damien Hedde <damien.hedde@greensocs.com>
To: qemu-devel@nongnu.org
Cc: Damien Hedde <damien.hedde@greensocs.com>,
Eduardo Habkost <eduardo@habkost.net>,
John Snow <jsnow@redhat.com>, Cleber Rosa <crosa@redhat.com>
Subject: [PATCH 4/5] python: qmp_shell: add -e/--exit-on-error option
Date: Mon, 21 Feb 2022 16:55:18 +0100 [thread overview]
Message-ID: <20220221155519.2367-5-damien.hedde@greensocs.com> (raw)
In-Reply-To: <20220221155519.2367-1-damien.hedde@greensocs.com>
This option makes qmp_shell exit (with error code 1)
as soon as one of the following error occurs:
+ command parsing error
+ disconnection
+ command failure (response is an error)
_execute_cmd() method now returns None or the response
so that read_exec_command() can do the last check.
This is meant to be used in combination with an input file
redirection. It allows to store a list of commands
into a file and try to run them by qmp_shell and easily
see if it failed or not.
Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
---
python/qemu/aqmp/qmp_shell.py | 39 +++++++++++++++++++++++++----------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/python/qemu/aqmp/qmp_shell.py b/python/qemu/aqmp/qmp_shell.py
index cce7732ba2..dd38ef8a13 100644
--- a/python/qemu/aqmp/qmp_shell.py
+++ b/python/qemu/aqmp/qmp_shell.py
@@ -11,7 +11,7 @@
"""
Low-level QEMU shell on top of QMP.
-usage: qmp-shell [-h] [-H] [-N] [-v] [-p] qmp_server
+usage: qmp-shell [-h] [-H] [-N] [-v] [-p] [-e] qmp_server
positional arguments:
qmp_server < UNIX socket path | TCP address:port >
@@ -23,6 +23,8 @@
Skip negotiate (for qemu-ga)
-v, --verbose Verbose (echo commands sent and received)
-p, --pretty Pretty-print JSON
+ -e, --exit-on-error Exit when an error occurs (command parsing,
+ disconnection and command failure)
Start QEMU with:
@@ -177,9 +179,11 @@ class QMPShell(QEMUMonitorProtocol):
:param address: Address of the QMP server.
:param pretty: Pretty-print QMP messages.
:param verbose: Echo outgoing QMP messages to console.
+ :param raise_error: Don't continue after an error occured
"""
def __init__(self, address: SocketAddrT,
- pretty: bool = False, verbose: bool = False):
+ pretty: bool = False, verbose: bool = False,
+ raise_error: bool = False):
super().__init__(address)
self._greeting: Optional[QMPMessage] = None
self._completer = QMPCompleter()
@@ -189,6 +193,7 @@ def __init__(self, address: SocketAddrT,
'.qmp-shell_history')
self.pretty = pretty
self.verbose = verbose
+ self.raise_error = raise_error
def close(self) -> None:
# Hook into context manager of parent to save shell history.
@@ -343,19 +348,19 @@ def _print_parse_error(self, err: QMPShellParseError) -> None:
file=sys.stderr
)
- def _execute_cmd(self, cmdline: str) -> bool:
+ def _execute_cmd(self, cmdline: str) -> Optional[QMPMessage]:
qmpcmd = self._build_cmd(cmdline)
# For transaction mode, we may have just cached the action:
if qmpcmd is None:
- return True
+ return None
if self.verbose:
self._print(qmpcmd)
resp = self.cmd_obj(qmpcmd)
if resp is None:
raise QMPShellConnectError('Disconnected')
self._print(resp)
- return True
+ return resp
def connect(self, negotiate: bool = True) -> None:
self._greeting = super().connect(negotiate)
@@ -401,8 +406,13 @@ def read_exec_command(self) -> bool:
print(event)
return True
+ if self.raise_error:
+ resp = self._execute_cmd(cmdline)
+ if resp and 'error' in resp:
+ raise QMPShellError(f"Command failed: {resp['error']}")
+ return True
try:
- return self._execute_cmd(cmdline)
+ self._execute_cmd(cmdline)
except QMPShellParseError as err:
self._print_parse_error(err)
except QMPShellConnectError as err:
@@ -477,7 +487,7 @@ def _cmd_passthrough(self, cmdline: str,
def _print_parse_error(self, err: QMPShellParseError) -> None:
print(f"{err!s}")
- def _execute_cmd(self, cmdline: str) -> bool:
+ def _execute_cmd(self, cmdline: str) -> Optional[QMPMessage]:
if cmdline.split()[0] == "cpu":
# trap the cpu command, it requires special setting
try:
@@ -498,7 +508,7 @@ def _execute_cmd(self, cmdline: str) -> bool:
else:
# Error
print('%s: %s' % (resp['error']['class'], resp['error']['desc']))
- return True
+ return resp
def show_banner(self, msg: str = 'Welcome to the HMP shell!') -> None:
QMPShell.show_banner(self, msg)
@@ -523,6 +533,9 @@ def main() -> None:
help='Verbose (echo commands sent and received)')
parser.add_argument('-p', '--pretty', action='store_true',
help='Pretty-print JSON')
+ parser.add_argument('-e', '--exit-on-error', action='store_true',
+ help='Exit when an error occurs (command parsing,'
+ ' disconnection and command failure)')
default_server = os.environ.get('QMP_SOCKET')
parser.add_argument('qmp_server', action='store',
@@ -541,7 +554,8 @@ def main() -> None:
parser.error(f"Bad port number: {args.qmp_server}")
return # pycharm doesn't know error() is noreturn
- with shell_class(address, args.pretty, args.verbose) as qemu:
+ with shell_class(address, args.pretty, args.verbose,
+ args.exit_on_error) as qemu:
try:
qemu.connect(negotiate=not args.skip_negotiation)
except ConnectError as err:
@@ -549,8 +563,11 @@ def main() -> None:
die(f"Couldn't connect to {args.qmp_server}: {err!s}")
die(str(err))
- for _ in qemu.repl():
- pass
+ try:
+ for _ in qemu.repl():
+ pass
+ except QMPShellError as err:
+ die(str(err))
if __name__ == '__main__':
--
2.35.1
next prev parent reply other threads:[~2022-02-21 16:02 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-02-21 15:55 [PATCH 0/5] qmp-shell modifications for non-interactive use Damien Hedde
2022-02-21 15:55 ` [PATCH 1/5] python: qmp_shell: don't prompt when stdin is non-interactive Damien Hedde
2022-02-21 15:55 ` [PATCH 2/5] python: qmp_shell: refactor the parsing error handling Damien Hedde
2022-02-21 15:55 ` [PATCH 3/5] python: qmp_shell: refactor disconnection handling Damien Hedde
2022-02-21 15:55 ` Damien Hedde [this message]
2022-02-23 15:22 ` [PATCH 4/5] python: qmp_shell: add -e/--exit-on-error option John Snow
2022-02-23 15:27 ` Daniel P. Berrangé
2022-02-23 15:41 ` John Snow
2022-02-23 15:44 ` Daniel P. Berrangé
2022-02-23 16:18 ` John Snow
2022-02-23 17:09 ` Damien Hedde
2022-02-23 18:20 ` John Snow
2022-02-24 11:20 ` Damien Hedde
2022-02-23 17:50 ` Daniel P. Berrangé
2022-02-23 16:43 ` Damien Hedde
2022-02-23 16:46 ` Damien Hedde
2022-02-21 15:55 ` [PATCH 5/5] python: qmp_shell: handle comment lines and escaped eol Damien Hedde
2022-02-22 6:10 ` [PATCH 0/5] qmp-shell modifications for non-interactive use Markus Armbruster
2022-02-22 7:57 ` Damien Hedde
2022-02-22 9:21 ` Daniel P. Berrangé
2022-02-22 9:38 ` Damien Hedde
2022-02-22 10:31 ` Daniel P. Berrangé
2022-02-23 9:57 ` Damien Hedde
2022-02-23 11:13 ` Daniel P. Berrangé
2022-02-23 15:01 ` John Snow
2022-02-23 15:08 ` Daniel P. Berrangé
2022-02-22 9:52 ` Markus Armbruster
2022-02-25 20:40 ` John Snow
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220221155519.2367-5-damien.hedde@greensocs.com \
--to=damien.hedde@greensocs.com \
--cc=crosa@redhat.com \
--cc=eduardo@habkost.net \
--cc=jsnow@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.