This is useful for testing QMP commands in scripts.
Example usage, combined with 'jq' for filtering the results:
$ ./scripts/qmp/qmp-shell /tmp/qmp qom-list path=/ | jq -r .return[].name
machine
type
chardevs
backend
$
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
---
Changes v1 -> v2:
* Rewritten using optparse module
---
scripts/qmp/qmp-shell | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
index 4b9a420..4b7374e 100755
--- a/scripts/qmp/qmp-shell
+++ b/scripts/qmp/qmp-shell
@@ -400,7 +400,7 @@ def die(msg):
def main():
parser = optparse.OptionParser(description='QMP shell utility')
- parser.set_usage("%prog [options] <UNIX socket path> | <TCP address:port>")
+ parser.set_usage("%prog [options] <UNIX socket path> | <TCP address:port> [COMMAND [ARG=VALUE]...]")
parser.add_option('-v', action='store_true', dest='verbose',
help='Verbose (echo command sent and received)')
parser.add_option('-p', action='store_true', dest='pretty',
@@ -411,10 +411,11 @@ def main():
default=True, help='Skip negotiate (for qemu-ga)')
opts,args = parser.parse_args()
- if len(args) != 1:
+ if len(args) < 1:
parser.print_help(sys.stderr)
sys.exit(1)
addr = args[0]
+ cmdargs = args[1:]
try:
if opts.hmp:
@@ -433,10 +434,13 @@ def main():
except qemu.error:
die('Could not connect to %s' % addr)
- qemu.show_banner()
qemu.set_verbosity(opts.verbose)
- while qemu.read_exec_command(qemu.get_prompt()):
- pass
+ if len(cmdargs):
+ qemu.execute_cmdargs(cmdargs)
+ else:
+ qemu.show_banner()
+ while qemu.read_exec_command(qemu.get_prompt()):
+ pass
qemu.close()
if __name__ == '__main__':
--
2.9.4
On Tue, Aug 08, 2017 at 05:39:34PM -0300, Eduardo Habkost wrote: > This is useful for testing QMP commands in scripts. > > Example usage, combined with 'jq' for filtering the results: > > $ ./scripts/qmp/qmp-shell /tmp/qmp qom-list path=/ | jq -r .return[].name > machine > type > chardevs > backend > $ > > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> > --- > Changes v1 -> v2: > * Rewritten using optparse module > --- > scripts/qmp/qmp-shell | 14 +++++++++----- > 1 file changed, 9 insertions(+), 5 deletions(-) Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Eduardo Habkost <ehabkost@redhat.com> writes:
Suggest to insert here:
If additional arguments QMP-COMMAND ARG=VAL... are given, run just
that QMP command instead of the REPL.
Question: is this limited to simple arguments? If no, how would I write
an object argument? For instance, how would I do
{ "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "nbd", "server": { "type": "inet", "host": "localhost", "port": "12345" } } }
?
> This is useful for testing QMP commands in scripts.
>
> Example usage, combined with 'jq' for filtering the results:
>
> $ ./scripts/qmp/qmp-shell /tmp/qmp qom-list path=/ | jq -r .return[].name
> machine
> type
> chardevs
> backend
What's jq?
> $
Let's drop this line.
>
> Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> ---
> Changes v1 -> v2:
> * Rewritten using optparse module
> ---
> scripts/qmp/qmp-shell | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
> index 4b9a420..4b7374e 100755
> --- a/scripts/qmp/qmp-shell
> +++ b/scripts/qmp/qmp-shell
> @@ -400,7 +400,7 @@ def die(msg):
>
> def main():
> parser = optparse.OptionParser(description='QMP shell utility')
> - parser.set_usage("%prog [options] <UNIX socket path> | <TCP address:port>")
> + parser.set_usage("%prog [options] <UNIX socket path> | <TCP address:port> [COMMAND [ARG=VALUE]...]")
> parser.add_option('-v', action='store_true', dest='verbose',
> help='Verbose (echo command sent and received)')
> parser.add_option('-p', action='store_true', dest='pretty',
> @@ -411,10 +411,11 @@ def main():
> default=True, help='Skip negotiate (for qemu-ga)')
> opts,args = parser.parse_args()
>
> - if len(args) != 1:
> + if len(args) < 1:
> parser.print_help(sys.stderr)
> sys.exit(1)
> addr = args[0]
> + cmdargs = args[1:]
>
> try:
> if opts.hmp:
> @@ -433,10 +434,13 @@ def main():
> except qemu.error:
> die('Could not connect to %s' % addr)
>
> - qemu.show_banner()
> qemu.set_verbosity(opts.verbose)
> - while qemu.read_exec_command(qemu.get_prompt()):
> - pass
> + if len(cmdargs):
Superfluous len().
> + qemu.execute_cmdargs(cmdargs)
> + else:
> + qemu.show_banner()
> + while qemu.read_exec_command(qemu.get_prompt()):
> + pass
> qemu.close()
>
> if __name__ == '__main__':
On Tue, Aug 15, 2017 at 12:03:53PM +0200, Markus Armbruster wrote:
> Eduardo Habkost <ehabkost@redhat.com> writes:
>
> Suggest to insert here:
>
> If additional arguments QMP-COMMAND ARG=VAL... are given, run just
> that QMP command instead of the REPL.
>
> Question: is this limited to simple arguments? If no, how would I write
> an object argument? For instance, how would I do
>
> { "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "nbd", "server": { "type": "inet", "host": "localhost", "port": "12345" } } }
>
> ?
Exactly the same way you would write it when running qmp-shell in
interactive mode. e.g.:
$ ./scripts/qmp/qmp-shell /tmp/qmp blockdev-add driver=qcow2 node-name=node-E 'file={"driver":"file","filename":"/path/to/file.qcow2"}'
>
> > This is useful for testing QMP commands in scripts.
> >
> > Example usage, combined with 'jq' for filtering the results:
> >
> > $ ./scripts/qmp/qmp-shell /tmp/qmp qom-list path=/ | jq -r .return[].name
> > machine
> > type
> > chardevs
> > backend
>
> What's jq?
https://stedolan.github.io/jq/
"like sed for JSON data"
>
> > $
>
> Let's drop this line.
Will do it.
>
> >
> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
> > ---
> > Changes v1 -> v2:
> > * Rewritten using optparse module
> > ---
> > scripts/qmp/qmp-shell | 14 +++++++++-----
> > 1 file changed, 9 insertions(+), 5 deletions(-)
> >
> > diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell
> > index 4b9a420..4b7374e 100755
> > --- a/scripts/qmp/qmp-shell
> > +++ b/scripts/qmp/qmp-shell
> > @@ -400,7 +400,7 @@ def die(msg):
> >
> > def main():
> > parser = optparse.OptionParser(description='QMP shell utility')
> > - parser.set_usage("%prog [options] <UNIX socket path> | <TCP address:port>")
> > + parser.set_usage("%prog [options] <UNIX socket path> | <TCP address:port> [COMMAND [ARG=VALUE]...]")
> > parser.add_option('-v', action='store_true', dest='verbose',
> > help='Verbose (echo command sent and received)')
> > parser.add_option('-p', action='store_true', dest='pretty',
> > @@ -411,10 +411,11 @@ def main():
> > default=True, help='Skip negotiate (for qemu-ga)')
> > opts,args = parser.parse_args()
> >
> > - if len(args) != 1:
> > + if len(args) < 1:
> > parser.print_help(sys.stderr)
> > sys.exit(1)
> > addr = args[0]
> > + cmdargs = args[1:]
> >
> > try:
> > if opts.hmp:
> > @@ -433,10 +434,13 @@ def main():
> > except qemu.error:
> > die('Could not connect to %s' % addr)
> >
> > - qemu.show_banner()
> > qemu.set_verbosity(opts.verbose)
> > - while qemu.read_exec_command(qemu.get_prompt()):
> > - pass
> > + if len(cmdargs):
>
> Superfluous len().
Will fix it in the next version.
>
> > + qemu.execute_cmdargs(cmdargs)
> > + else:
> > + qemu.show_banner()
> > + while qemu.read_exec_command(qemu.get_prompt()):
> > + pass
> > qemu.close()
> >
> > if __name__ == '__main__':
--
Eduardo
Eduardo Habkost <ehabkost@redhat.com> writes:
> On Tue, Aug 15, 2017 at 12:03:53PM +0200, Markus Armbruster wrote:
>> Eduardo Habkost <ehabkost@redhat.com> writes:
>>
>> Suggest to insert here:
>>
>> If additional arguments QMP-COMMAND ARG=VAL... are given, run just
>> that QMP command instead of the REPL.
>>
>> Question: is this limited to simple arguments? If no, how would I write
>> an object argument? For instance, how would I do
>>
>> { "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "nbd", "server": { "type": "inet", "host": "localhost", "port": "12345" } } }
>>
>> ?
>
> Exactly the same way you would write it when running qmp-shell in
> interactive mode. e.g.:
>
> $ ./scripts/qmp/qmp-shell /tmp/qmp blockdev-add driver=qcow2 node-name=node-E 'file={"driver":"file","filename":"/path/to/file.qcow2"}'
I see.
The QEMU command line uses dotted key syntax instead.
To be honest, the less qmp-shell is used, the happier I am. Would you
like to serve as its sub-maintainer?
>> > This is useful for testing QMP commands in scripts.
>> >
>> > Example usage, combined with 'jq' for filtering the results:
>> >
>> > $ ./scripts/qmp/qmp-shell /tmp/qmp qom-list path=/ | jq -r .return[].name
>> > machine
>> > type
>> > chardevs
>> > backend
>>
>> What's jq?
>
> https://stedolan.github.io/jq/
>
> "like sed for JSON data"
A fine addition to your commit message.
>>
>> > $
>>
>> Let's drop this line.
>
> Will do it.
>
>>
>> >
>> > Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
[...]
On Wed, Aug 16, 2017 at 08:25:41AM +0200, Markus Armbruster wrote:
> Eduardo Habkost <ehabkost@redhat.com> writes:
>
> > On Tue, Aug 15, 2017 at 12:03:53PM +0200, Markus Armbruster wrote:
> >> Eduardo Habkost <ehabkost@redhat.com> writes:
> >>
> >> Suggest to insert here:
> >>
> >> If additional arguments QMP-COMMAND ARG=VAL... are given, run just
> >> that QMP command instead of the REPL.
> >>
> >> Question: is this limited to simple arguments? If no, how would I write
> >> an object argument? For instance, how would I do
> >>
> >> { "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "nbd", "server": { "type": "inet", "host": "localhost", "port": "12345" } } }
> >>
> >> ?
> >
> > Exactly the same way you would write it when running qmp-shell in
> > interactive mode. e.g.:
> >
> > $ ./scripts/qmp/qmp-shell /tmp/qmp blockdev-add driver=qcow2 node-name=node-E 'file={"driver":"file","filename":"/path/to/file.qcow2"}'
>
> I see.
>
> The QEMU command line uses dotted key syntax instead.
You mean -blockdev, or is there another way to send QMP commands
to QEMU that I'm not aware of?
>
> To be honest, the less qmp-shell is used, the happier I am.
What people would use instead of it?
> Would you
> like to serve as its sub-maintainer?
I'd be glad to.
--
Eduardo
Eduardo Habkost <ehabkost@redhat.com> writes:
> On Wed, Aug 16, 2017 at 08:25:41AM +0200, Markus Armbruster wrote:
>> Eduardo Habkost <ehabkost@redhat.com> writes:
>>
>> > On Tue, Aug 15, 2017 at 12:03:53PM +0200, Markus Armbruster wrote:
>> >> Eduardo Habkost <ehabkost@redhat.com> writes:
>> >>
>> >> Suggest to insert here:
>> >>
>> >> If additional arguments QMP-COMMAND ARG=VAL... are given, run just
>> >> that QMP command instead of the REPL.
>> >>
>> >> Question: is this limited to simple arguments? If no, how would I write
>> >> an object argument? For instance, how would I do
>> >>
>> >> { "execute": "blockdev-add", "arguments": { "node-name": "foo", "driver": "nbd", "server": { "type": "inet", "host": "localhost", "port": "12345" } } }
>> >>
>> >> ?
>> >
>> > Exactly the same way you would write it when running qmp-shell in
>> > interactive mode. e.g.:
>> >
>> > $ ./scripts/qmp/qmp-shell /tmp/qmp blockdev-add driver=qcow2 node-name=node-E 'file={"driver":"file","filename":"/path/to/file.qcow2"}'
>>
>> I see.
>>
>> The QEMU command line uses dotted key syntax instead.
>
> You mean -blockdev, or is there another way to send QMP commands
> to QEMU that I'm not aware of?
Dotted keys were invented for the block layer's -drive. I adopted them
for -blockdev after considerable discussion. The -blockdev code is all
new, and it even has documentation and tests.
>> To be honest, the less qmp-shell is used, the happier I am.
>
> What people would use instead of it?
The syntactic sugar qmp-shell provides over plain QMP doesn't simplify
its use all that much, and it can get in the way.
For my interactive QMP needs, I use
$ socat UNIX:/wherever/qmp-socket READLINE,history=$HOME/.qmp_history,prompt='QMP> '
In programs, I send or receive either plain text or JSON objects,
depending on the program's needs. Libqtest supports the latter.
>> Would you
>> like to serve as its sub-maintainer?
>
> I'd be glad to.
Great! Please post a suitable MAINTAINERS stanza.
© 2016 - 2026 Red Hat, Inc.