qapi: Have each QAPI schema declare its returns white-list
qapi.py has a hardcoded white-list of command names that may violate the rules on permitted return types. Add a new pragma directive 'returns-whitelist', and use it to replace the hard-coded white-list. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1489582656-31133-6-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
700dc9f503
commit
1554a8fae9
@ -318,6 +318,9 @@ pragma to different values in parts of the schema doesn't work.
|
||||
Pragma 'doc-required' takes a boolean value. If true, documentation
|
||||
is required. Default is false.
|
||||
|
||||
Pragma 'returns-whitelist' takes a list of command names that may
|
||||
violate the rules on permitted return types. Default is none.
|
||||
|
||||
|
||||
=== Struct types ===
|
||||
|
||||
@ -566,12 +569,10 @@ The member is optional from the command declaration; if absent, the
|
||||
"return" member will be an empty dictionary. If 'returns' is present,
|
||||
it must be the string name of a complex or built-in type, a
|
||||
one-element array containing the name of a complex or built-in type.
|
||||
Although it is permitted to have the 'returns' member name a built-in
|
||||
type or an array of built-in types, any command that does this cannot
|
||||
be extended to return additional information in the future; thus, new
|
||||
commands should strongly consider returning a dictionary-based type or
|
||||
an array of dictionaries, even if the dictionary only contains one
|
||||
member at the present.
|
||||
To return anything else, you have to list the command in pragma
|
||||
'returns-whitelist'. If you do this, the command cannot be extended
|
||||
to return additional information in the future. Use of
|
||||
'returns-whitelist' for new commands is strongly discouraged.
|
||||
|
||||
All commands in Client JSON Protocol use a dictionary to report
|
||||
failure, with no way to specify that in QAPI. Where the error return
|
||||
|
@ -51,6 +51,18 @@
|
||||
|
||||
{ 'pragma': { 'doc-required': true } }
|
||||
|
||||
# Whitelists to permit QAPI rule violations; think twice before you
|
||||
# add to them!
|
||||
{ 'pragma': {
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
'human-monitor-command',
|
||||
'qom-get',
|
||||
'query-migrate-cache-size',
|
||||
'query-tpm-models',
|
||||
'query-tpm-types',
|
||||
'ringbuf-read' ] } }
|
||||
|
||||
# QAPI common definitions
|
||||
{ 'include': 'qapi/common.json' }
|
||||
|
||||
|
@ -13,6 +13,21 @@
|
||||
|
||||
{ 'pragma': { 'doc-required': true } }
|
||||
|
||||
# Whitelists to permit QAPI rule violations; think twice before you
|
||||
# add to them!
|
||||
{ 'pragma': {
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
'guest-file-open',
|
||||
'guest-fsfreeze-freeze',
|
||||
'guest-fsfreeze-freeze-list',
|
||||
'guest-fsfreeze-status',
|
||||
'guest-fsfreeze-thaw',
|
||||
'guest-get-time',
|
||||
'guest-set-vcpus',
|
||||
'guest-sync',
|
||||
'guest-sync-delimited' ] } }
|
||||
|
||||
##
|
||||
# @guest-sync-delimited:
|
||||
#
|
||||
|
@ -41,26 +41,7 @@ builtin_types = {
|
||||
doc_required = False
|
||||
|
||||
# Whitelist of commands allowed to return a non-dictionary
|
||||
returns_whitelist = [
|
||||
# From QMP:
|
||||
'human-monitor-command',
|
||||
'qom-get',
|
||||
'query-migrate-cache-size',
|
||||
'query-tpm-models',
|
||||
'query-tpm-types',
|
||||
'ringbuf-read',
|
||||
|
||||
# From QGA:
|
||||
'guest-file-open',
|
||||
'guest-fsfreeze-freeze',
|
||||
'guest-fsfreeze-freeze-list',
|
||||
'guest-fsfreeze-status',
|
||||
'guest-fsfreeze-thaw',
|
||||
'guest-get-time',
|
||||
'guest-set-vcpus',
|
||||
'guest-sync',
|
||||
'guest-sync-delimited',
|
||||
]
|
||||
returns_whitelist = []
|
||||
|
||||
# Whitelist of entities allowed to violate case conventions
|
||||
case_whitelist = [
|
||||
@ -321,12 +302,19 @@ class QAPISchemaParser(object):
|
||||
self.docs.extend(exprs_include.docs)
|
||||
|
||||
def _pragma(self, name, value, info):
|
||||
global doc_required
|
||||
global doc_required, returns_whitelist
|
||||
if name == 'doc-required':
|
||||
if not isinstance(value, bool):
|
||||
raise QAPISemError(info,
|
||||
"Pragma 'doc-required' must be boolean")
|
||||
doc_required = value
|
||||
elif name == 'returns-whitelist':
|
||||
if (not isinstance(value, list)
|
||||
or any([not isinstance(elt, str) for elt in value])):
|
||||
raise QAPISemError(info,
|
||||
"Pragma returns-whitelist must be"
|
||||
" a list of strings")
|
||||
returns_whitelist = value
|
||||
else:
|
||||
raise QAPISemError(info, "Unknown pragma '%s'" % name)
|
||||
|
||||
|
@ -444,6 +444,7 @@ qapi-schema += non-objects.json
|
||||
qapi-schema += pragma-doc-required-crap.json
|
||||
qapi-schema += pragma-extra-junk.json
|
||||
qapi-schema += pragma-non-dict.json
|
||||
qapi-schema += pragma-returns-whitelist-crap.json
|
||||
qapi-schema += qapi-schema-test.json
|
||||
qapi-schema += quoted-structural-chars.json
|
||||
qapi-schema += redefined-builtin.json
|
||||
|
1
tests/qapi-schema/pragma-returns-whitelist-crap.err
Normal file
1
tests/qapi-schema/pragma-returns-whitelist-crap.err
Normal file
@ -0,0 +1 @@
|
||||
tests/qapi-schema/pragma-returns-whitelist-crap.json:3: Pragma returns-whitelist must be a list of strings
|
1
tests/qapi-schema/pragma-returns-whitelist-crap.exit
Normal file
1
tests/qapi-schema/pragma-returns-whitelist-crap.exit
Normal file
@ -0,0 +1 @@
|
||||
1
|
3
tests/qapi-schema/pragma-returns-whitelist-crap.json
Normal file
3
tests/qapi-schema/pragma-returns-whitelist-crap.json
Normal file
@ -0,0 +1,3 @@
|
||||
# 'returns-whitelist' must be list of strings
|
||||
|
||||
{ 'pragma': { 'returns-whitelist': [ 'good', [ 'bad' ] ] } }
|
0
tests/qapi-schema/pragma-returns-whitelist-crap.out
Normal file
0
tests/qapi-schema/pragma-returns-whitelist-crap.out
Normal file
@ -3,6 +3,13 @@
|
||||
# This file is a stress test of supported qapi constructs that must
|
||||
# parse and compile correctly.
|
||||
|
||||
# Whitelists to permit QAPI rule violations
|
||||
{ 'pragma': {
|
||||
# Commands allowed to return a non-dictionary:
|
||||
'returns-whitelist': [
|
||||
'guest-get-time',
|
||||
'guest-sync' ] } }
|
||||
|
||||
{ 'struct': 'TestStruct',
|
||||
'data': { 'integer': 'int', 'boolean': 'bool', 'string': 'str' } }
|
||||
|
||||
|
@ -1 +1 @@
|
||||
tests/qapi-schema/returns-whitelist.json:10: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
|
||||
tests/qapi-schema/returns-whitelist.json:14: 'returns' for command 'no-way-this-will-get-whitelisted' cannot use built-in type 'int'
|
||||
|
@ -1,4 +1,8 @@
|
||||
# we enforce that 'returns' be a dict or array of dict unless whitelisted
|
||||
|
||||
{ 'pragma': { 'returns-whitelist': [
|
||||
'human-monitor-command', 'query-tpm-models', 'guest-get-time' ] } }
|
||||
|
||||
{ 'command': 'human-monitor-command',
|
||||
'data': {'command-line': 'str', '*cpu-index': 'int'},
|
||||
'returns': 'str' }
|
||||
|
Loading…
Reference in New Issue
Block a user