qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Michael Roth <mdroth@linux.vnet.ibm.com>
To: Markus Armbruster <armbru@redhat.com>, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH RFC v4 30/32] qapi: New QMP command query-schema for QMP schema introspection
Date: Thu, 03 Sep 2015 18:59:41 -0500	[thread overview]
Message-ID: <20150903235941.10296.72342@loki> (raw)
In-Reply-To: <1441290623-13631-31-git-send-email-armbru@redhat.com>

Quoting Markus Armbruster (2015-09-03 09:30:21)
> qapi/introspect.json defines the introspection schema.  It's designed
> for QMP introspection, but should do for similar uses, such as QGA.
> 
> The introspection schema does not reflect all the rules and
> restrictions that apply to QAPI schemata.  A valid QAPI schema has an
> introspection value conforming to the introspection schema, but the
> converse is not true.
> 
> Introspection lowers away a number of schema details, and makes
> implicit things explicit:
> 
> * The built-in types are declared with their JSON type.
> 
>   TODO Should we map all the integer types to just int?
> 
> * Implicit type definitions are made explicit, and given
>   auto-generated names:
> 
>   - Array types, named by appending "List" to the name of their
>     element type, like in generated C.
> 
>   - The enumeration types implicitly defined by simple union types,
>     named by appending "Kind" to the name of their simple union type,
>     like in generated C.
> 
>   - Types that don't occur in generated C.  Their names start with ':'
>     so they don't clash with the user's names.
> 
> * All type references are by name.
> 
> * The struct and union types are generalized into an object type.
> 
> * Base types are flattened.
> 
> * Commands take a single argument and return a single result.
> 
>   Dictionary argument or list result is an implicit type definition.
> 
>   The empty object type is used when a command takes no arguments or
>   produces no results.
> 
>   The argument is always of object type, but the introspection schema
>   doesn't reflect that.
> 
>   The 'gen': false directive is omitted as implementation detail.
> 
>   The 'success-response' directive is omitted as well for now, even
>   though it's not an implementation detail, because it's not used by
>   QMP.
> 
> * Events carry a single data value.
> 
>   Implicit type definition and empty object type use, just like for
>   commands.
> 
>   The value is of object type, but the introspection schema doesn't
>   reflect that.
> 
> * Types not used by commands or events are omitted.
> 
>   Indirect use counts as use.
> 
> * Optional members have a default, which can only be null right now
> 
>   Instead of a mandatory "optional" flag, we have an optional default.
>   No default means mandatory, default null means optional without
>   default value.  Non-null is available for optional with default
>   (possible future extension).
> 
> * Clients should *not* look up types by name, because type names are
>   not ABI.  Look up the command or event you're interested in, then
>   follow the references.
> 
>   TODO Should we hide the type names to eliminate the temptation?
> 
> New generator scripts/qapi-introspect.py computes an introspection
> value for its input, and generates a C variable holding it.
> 
> It can generate awfully long lines.  Marked TODO.
> 
> A new test-qmp-input-visitor test case feeds its result for both
> tests/qapi-schema/qapi-schema-test.json and qapi-schema.json to a
> QmpInputVisitor to verify it actually conforms to the schema.
> 
> New QMP command query-schema takes its return value from that
> variable.  Its reply is some 85KiBytes for me right now.
> 
> If this turns out to be too much, we have a couple of options:
> 
> * We can use shorter names in the JSON.  Not the QMP style.
> 
> * Optionally return the sub-schema for commands and events given as
>   arguments.
> 
>   Right now qmp_query_schema() sends the string literal computed by
>   qmp-introspect.py.  To compute sub-schema at run time, we'd have to
>   duplicate parts of qapi-introspect.py in C.  Unattractive.
> 
> * Let clients cache the output of query-schema.
> 
>   It changes only on QEMU upgrades, i.e. rarely.  Provide a command
>   query-schema-hash.  Clients can have a cache indexed by hash, and
>   re-query the schema only when they don't have it cached.  Even
>   simpler: put the hash in the QMP greeting.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  .gitignore                                      |   1 +
>  Makefile                                        |   9 +-
>  Makefile.objs                                   |   4 +-
>  docs/qapi-code-gen.txt                          | 226 +++++++++++++++++++-
>  monitor.c                                       |  15 ++
>  qapi-schema.json                                |   3 +
>  qapi/introspect.json                            | 271 ++++++++++++++++++++++++
>  qmp-commands.hx                                 |  17 ++
>  scripts/qapi-introspect.py                      | 174 +++++++++++++++
>  scripts/qapi.py                                 |  12 +-
>  tests/.gitignore                                |   1 +
>  tests/Makefile                                  |  10 +-
>  tests/qapi-schema/alternate-good.out            |   1 +
>  tests/qapi-schema/args-member-array.out         |   1 +
>  tests/qapi-schema/comments.out                  |   1 +
>  tests/qapi-schema/empty.out                     |   1 +
>  tests/qapi-schema/enum-empty.out                |   1 +
>  tests/qapi-schema/event-case.out                |   1 +
>  tests/qapi-schema/flat-union-reverse-define.out |   1 +
>  tests/qapi-schema/ident-with-escape.out         |   1 +
>  tests/qapi-schema/include-relpath.out           |   1 +
>  tests/qapi-schema/include-repetition.out        |   1 +
>  tests/qapi-schema/include-simple.out            |   1 +
>  tests/qapi-schema/indented-expr.out             |   1 +
>  tests/qapi-schema/qapi-schema-test.out          |   1 +
>  tests/qapi-schema/returns-int.out               |   1 +
>  tests/test-qmp-input-strict.c                   |  55 +++++
>  27 files changed, 801 insertions(+), 11 deletions(-)
>  create mode 100644 qapi/introspect.json
>  create mode 100644 scripts/qapi-introspect.py
> 

<snip>

> diff --git a/qapi-schema.json b/qapi-schema.json
> index e91e3b9..af19810 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -14,6 +14,9 @@
>  # Tracing commands
>  { 'include': 'qapi/trace.json' }
> 
> +# QAPI introspection
> +{ 'include': 'qapi/introspect.json' }
> +
>  ##
>  # @LostTickPolicy:
>  #
> diff --git a/qapi/introspect.json b/qapi/introspect.json
> new file mode 100644
> index 0000000..171baba
> --- /dev/null
> +++ b/qapi/introspect.json
> @@ -0,0 +1,271 @@
> +# -*- Mode: Python -*-
> +#
> +# QAPI/QMP introspection
> +#
> +# Copyright (C) 2015 Red Hat, Inc.
> +#
> +# Authors:
> +#  Markus Armbruster <armbru@redhat.com>
> +#
> +# This work is licensed under the terms of the GNU GPL, version 2 or later.
> +# See the COPYING file in the top-level directory.
> +
> +##
> +# @query-schema
> +#
> +# Command query-schema exposes the QMP wire ABI as an array of
> +# SchemaInfo.  This lets QMP clients figure out what commands and
> +# events are available in this QEMU, and their parameters and results.
> +#
> +# Returns: array of @SchemaInfo, where each element describes an
> +# entity in the ABI: command, event, type, ...
> +#
> +# Note: the QAPI schema is also used to help define *internal*
> +# interfaces, by defining QAPI types.  These are not part of the QMP
> +# wire ABI, and therefore not returned by this command.

Maybe add something like:

"These internal interfaces may place additional restrictions on the
values of individual fields, so users should reference the QAPI schema
to avoid unexpected behavior resulting from invalid field values."

<snip>

> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index b06d74c..6232ca0 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -2168,6 +2168,23 @@ EQMP
>      },
> 
>  SQMP
> +query-schema
> +------------
> +
> +Return the QMP wire schema.  The returned value is a json-array of
> +named schema entities.  Entities are commands, events and various
> +types.  See docs/qapi-code-gen.txt for information on their structure
> +and intended use.

We should probably duplicate any notes from QAPI schema description here
as well, or at least direct users to reference them.

> +
> +EQMP
> +
> +    {
> +        .name       = "query-schema",
> +        .args_type  = "",
> +        .mhandler.cmd_new = qmp_query_schema,
> +    },
> +
> +SQMP
>  query-chardev
>  -------------
> 
> diff --git a/scripts/qapi-introspect.py b/scripts/qapi-introspect.py
> new file mode 100644
> index 0000000..4bcffc4
> --- /dev/null
> +++ b/scripts/qapi-introspect.py
> @@ -0,0 +1,174 @@
> +#
> +# QAPI introspection generator
> +#
> +# Copyright (C) 2015 Red Hat, Inc.
> +#
> +# Authors:
> +#  Markus Armbruster <armbru@redhat.com>
> +#
> +# This work is licensed under the terms of the GNU GPL, version 2.
> +# See the COPYING file in the top-level directory.
> +
> +from qapi import *
> +import string
> +
> +# Caveman's json.dumps() replacement (we're stuck at 2.4)
> +# TODO try to use json.dumps() once we get unstuck
> +def to_json(obj, level=0):
> +    if obj == None:
> +        ret = 'null'
> +    elif isinstance(obj, str):
> +        ret = '"' + obj.replace('"', r'\"') + '"'
> +    elif isinstance(obj, list):
> +        elts = [to_json(elt, level + 1)
> +                for elt in obj]
> +        ret = '[' + ', '.join(elts) + ']'
> +    elif isinstance(obj, dict):
> +        elts = ['"%s": %s' % (key, to_json(obj[key], level + 1))
> +                for key in sorted(obj.keys())]
> +        ret = '{' + ', '.join(elts) + '}'
> +    else:
> +        assert False                # not implemented
> +    if level == 1:
> +        ret = '\n' + ret
> +    return ret
> +
> +def to_c_string(string):
> +    return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"'
> +
> +class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
> +    def __init__(self):
> +        self.defn = None
> +        self.decl = None
> +        self.schema = None
> +        self.jsons = None
> +        self.used_types = None
> +
> +    def visit_begin(self, schema):
> +        self.schema = schema
> +        self.jsons = []
> +        self.used_types = []
> +        return QAPISchemaType   # don't visit types for now
> +
> +    def visit_end(self):
> +        # visit the types that are actually used
> +        for typ in self.used_types:
> +            typ.visit(self)
> +        self.jsons.sort()
> +        # generate C
> +        # TODO can generate awfully long lines

Not sure if this is planned for this series, but a multi-line
representation in the generated files would make things a bit
easier to review/check. If we went a little further and made
them pretty-printed it might make some of the docs referencing
the output a bit more clear as well. Not a huge deal, but don't
think it would take much code. Would suggest a JSON library or
something but that would probably mangle the ordering, which
wouldn't help with readability.

> +        name = prefix + 'qmp_schema_json'
> +        self.decl = mcgen('''
> +extern const char %(c_name)s[];
> +''',
> +                          c_name=c_name(name))
> +        lines = to_json(self.jsons).split('\n')
> +        c_string = '\n    '.join([to_c_string(line) for line in lines])
> +        self.defn = mcgen('''
> +const char %(c_name)s[] = %(c_string)s;
> +''',
> +                          c_name=c_name(name),
> +                          c_string=c_string)
> +        self.schema = None
> +        self.jsons = None
> +        self.used_types = None

  parent reply	other threads:[~2015-09-03 23:59 UTC|newest]

Thread overview: 75+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-09-03 14:29 [Qemu-devel] [PATCH RFC v4 00/32] qapi: QMP introspection Markus Armbruster
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 01/32] qapi: Rename class QAPISchema to QAPISchemaParser Markus Armbruster
2015-09-03 15:55   ` Daniel P. Berrange
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 02/32] qapi: New QAPISchema intermediate reperesentation Markus Armbruster
2015-09-03 16:11   ` Daniel P. Berrange
2015-09-04  7:12     ` Markus Armbruster
2015-09-04  8:51       ` Daniel P. Berrange
2015-09-04 11:13         ` Markus Armbruster
2015-09-04  3:05   ` Eric Blake
2015-09-04 12:34   ` Eric Blake
2015-09-04 14:40     ` Markus Armbruster
2015-09-04 23:51       ` [Qemu-devel] [PATCH RFC v4 02.5/32] qapi: Hide internal data members of schema objects Eric Blake
2015-09-05 13:19         ` Eric Blake
2015-09-05 13:25           ` Eric Blake
2015-09-05 13:45             ` Eric Blake
2015-09-07  6:57               ` Markus Armbruster
2015-09-07  6:58         ` Markus Armbruster
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 03/32] qapi: QAPISchema code generation helper methods Markus Armbruster
2015-09-03 16:13   ` Daniel P. Berrange
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 04/32] qapi: New QAPISchemaVisitor Markus Armbruster
2015-09-03 16:16   ` Daniel P. Berrange
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 05/32] tests/qapi-schema: Convert test harness to QAPISchemaVisitor Markus Armbruster
2015-09-03 16:18   ` Daniel P. Berrange
2015-09-03 16:24   ` Eric Blake
2015-09-05 13:23   ` Eric Blake
2015-09-07  7:10     ` Markus Armbruster
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 06/32] qapi: Split up some typedefs to ease review Markus Armbruster
2015-09-03 16:19   ` Daniel P. Berrange
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 07/32] qapi: Generate comments to simplify splitting for review Markus Armbruster
2015-09-03 16:21   ` Daniel P. Berrange
2015-09-03 14:29 ` [Qemu-devel] [PATCH RFC v4 08/32] Revert "qapi: Generate comments to simplify splitting for review" Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 09/32] Revert "qapi: Split up some typedefs to ease review" Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 10/32] qapi-types: Convert to QAPISchemaVisitor, fixing flat unions Markus Armbruster
2015-09-04  3:11   ` Eric Blake
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 11/32] qapi-visit: Convert to QAPISchemaVisitor, fixing bugs Markus Armbruster
2015-09-04  3:14   ` Eric Blake
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 12/32] qapi-commands: Convert to QAPISchemaVisitor Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 13/32] qapi: De-duplicate enum code generation Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 14/32] qapi-event: Eliminate global variable event_enum_value Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 15/32] qapi-event: Convert to QAPISchemaVisitor, fixing data with base Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 16/32] qapi: Generate comments to simplify splitting for review Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 17/32] Revert "qapi: Generate comments to simplify splitting for review" Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 18/32] qapi: Replace dirty is_c_ptr() by method c_null() Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 19/32] qapi: Clean up after recent conversions to QAPISchemaVisitor Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 20/32] qapi-visit: Rearrange code a bit Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 21/32] qapi-commands: Rearrange code Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 22/32] qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO() Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 23/32] qapi: De-duplicate parameter list generation Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 24/32] qapi-commands: De-duplicate output marshaling functions Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 25/32] qapi: Improve built-in type documentation Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 26/32] qapi: Introduce a first class 'any' type Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 27/32] qom: Don't use 'gen': false for qom-get, qom-set, object-add Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 28/32] qapi-schema: Fix up misleading specification of netdev_add Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 29/32] qapi: Pseudo-type '**' is now unused, drop it Markus Armbruster
2015-09-03 20:42   ` Eric Blake
2015-09-04  7:14     ` Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 30/32] qapi: New QMP command query-schema for QMP schema introspection Markus Armbruster
2015-09-03 20:50   ` Eric Blake
2015-09-04  0:04     ` Michael Roth
2015-09-04  7:19       ` Markus Armbruster
2015-09-03 23:59   ` Michael Roth [this message]
2015-09-04  8:54     ` Markus Armbruster
2015-09-04  2:03   ` Eric Blake
2015-09-04  3:12     ` Eric Blake
2015-09-04  9:55     ` Markus Armbruster
2015-09-04 13:58       ` Eric Blake
2015-09-04 15:08         ` Markus Armbruster
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 31/32] qapi-introspect: Map all integer types to 'int' Markus Armbruster
2015-09-04 14:00   ` Eric Blake
2015-09-03 14:30 ` [Qemu-devel] [PATCH RFC v4 32/32] qapi-introspect: Hide type names Markus Armbruster
2015-09-04 14:07   ` Eric Blake
2015-09-04 15:52     ` Markus Armbruster
2015-09-04 12:57 ` [Qemu-devel] [PATCH RFC v4 00/32] qapi: QMP introspection Marc-André Lureau
2015-09-04 14:14   ` Eric Blake
2015-09-04 15:55   ` Markus Armbruster

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=20150903235941.10296.72342@loki \
    --to=mdroth@linux.vnet.ibm.com \
    --cc=armbru@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).