qapi: introduce new cmd option "allow-preconfig"
New option will be used to allow commands, which are prepared/need to run, during preconfig state. Other commands that should be able to run in preconfig state, should be amended to not expect machine in initialized state or deal with it. For compatibility reasons, commands that don't use new flag 'allow-preconfig' explicitly are not permitted to run in preconfig state but allowed in all other states like they used to be. Within this patch allow following commands in preconfig state: qmp_capabilities query-qmp-schema query-commands query-command-line-options query-status exit-preconfig to allow qmp connection, basic introspection and moving to the next state. PS: set-numa-node and query-hotpluggable-cpus will be enabled later in a separate patches. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Message-Id: <1526057503-39287-1-git-send-email-imammedo@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> [ehabkost: Changed "since 2.13" to "since 3.0"] Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
This commit is contained in:
parent
71dc578e11
commit
d6fe3d02e9
@ -559,7 +559,7 @@ following example objects:
|
||||
Usage: { 'command': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
|
||||
'*returns': TYPE-NAME, '*boxed': true,
|
||||
'*gen': false, '*success-response': false,
|
||||
'*allow-oob': true }
|
||||
'*allow-oob': true, '*allow-preconfig': true }
|
||||
|
||||
Commands are defined by using a dictionary containing several members,
|
||||
where three members are most common. The 'command' member is a
|
||||
@ -683,6 +683,15 @@ OOB command handlers must satisfy the following conditions:
|
||||
|
||||
If in doubt, do not implement OOB execution support.
|
||||
|
||||
A command may use the optional 'allow-preconfig' key to permit its execution
|
||||
at early runtime configuration stage (preconfig runstate).
|
||||
If not specified then a command defaults to 'allow-preconfig': false.
|
||||
|
||||
An example of declaring a command that is enabled during preconfig:
|
||||
{ 'command': 'qmp_capabilities',
|
||||
'data': { '*enable': [ 'QMPCapability' ] },
|
||||
'allow-preconfig': true }
|
||||
|
||||
=== Events ===
|
||||
|
||||
Usage: { 'event': STRING, '*data': COMPLEX-TYPE-NAME-OR-DICT,
|
||||
|
@ -23,6 +23,7 @@ typedef enum QmpCommandOptions
|
||||
QCO_NO_OPTIONS = 0x0,
|
||||
QCO_NO_SUCCESS_RESP = (1U << 0),
|
||||
QCO_ALLOW_OOB = (1U << 1),
|
||||
QCO_ALLOW_PRECONFIG = (1U << 2),
|
||||
} QmpCommandOptions;
|
||||
|
||||
typedef struct QmpCommand
|
||||
|
@ -1179,8 +1179,7 @@ static void monitor_init_qmp_commands(void)
|
||||
qmp_init_marshal(&qmp_commands);
|
||||
|
||||
qmp_register_command(&qmp_commands, "query-qmp-schema",
|
||||
qmp_query_qmp_schema,
|
||||
QCO_NO_OPTIONS);
|
||||
qmp_query_qmp_schema, QCO_ALLOW_PRECONFIG);
|
||||
qmp_register_command(&qmp_commands, "device_add", qmp_device_add,
|
||||
QCO_NO_OPTIONS);
|
||||
qmp_register_command(&qmp_commands, "netdev_add", qmp_netdev_add,
|
||||
@ -1190,7 +1189,7 @@ static void monitor_init_qmp_commands(void)
|
||||
|
||||
QTAILQ_INIT(&qmp_cap_negotiation_commands);
|
||||
qmp_register_command(&qmp_cap_negotiation_commands, "qmp_capabilities",
|
||||
qmp_marshal_qmp_capabilities, QCO_NO_OPTIONS);
|
||||
qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG);
|
||||
}
|
||||
|
||||
static bool qmp_cap_enabled(Monitor *mon, QMPCapability cap)
|
||||
|
@ -262,13 +262,16 @@
|
||||
# @allow-oob: whether the command allows out-of-band execution.
|
||||
# (Since: 2.12)
|
||||
#
|
||||
# @allow-preconfig: command can be executed in preconfig runstate,
|
||||
# default: false (Since 3.0)
|
||||
#
|
||||
# TODO: @success-response (currently irrelevant, because it's QGA, not QMP)
|
||||
#
|
||||
# Since: 2.5
|
||||
##
|
||||
{ 'struct': 'SchemaInfoCommand',
|
||||
'data': { 'arg-type': 'str', 'ret-type': 'str',
|
||||
'allow-oob': 'bool' } }
|
||||
'allow-oob': 'bool', 'allow-preconfig': 'bool' } }
|
||||
|
||||
##
|
||||
# @SchemaInfoEvent:
|
||||
|
@ -37,7 +37,8 @@
|
||||
#
|
||||
##
|
||||
{ 'command': 'qmp_capabilities',
|
||||
'data': { '*enable': [ 'QMPCapability' ] } }
|
||||
'data': { '*enable': [ 'QMPCapability' ] },
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @QMPCapability:
|
||||
@ -155,7 +156,8 @@
|
||||
# Note: This example has been shortened as the real response is too long.
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-commands', 'returns': ['CommandInfo'] }
|
||||
{ 'command': 'query-commands', 'returns': ['CommandInfo'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @LostTickPolicy:
|
||||
@ -2648,7 +2650,8 @@
|
||||
#
|
||||
##
|
||||
{'command': 'query-command-line-options', 'data': { '*option': 'str' },
|
||||
'returns': ['CommandLineOptionInfo'] }
|
||||
'returns': ['CommandLineOptionInfo'],
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @X86CPURegister32:
|
||||
|
@ -94,7 +94,8 @@
|
||||
# "status": "running" } }
|
||||
#
|
||||
##
|
||||
{ 'command': 'query-status', 'returns': 'StatusInfo' }
|
||||
{ 'command': 'query-status', 'returns': 'StatusInfo',
|
||||
'allow-preconfig': true }
|
||||
|
||||
##
|
||||
# @SHUTDOWN:
|
||||
|
@ -193,13 +193,15 @@ out:
|
||||
return ret
|
||||
|
||||
|
||||
def gen_register_command(name, success_response, allow_oob):
|
||||
def gen_register_command(name, success_response, allow_oob, allow_preconfig):
|
||||
options = []
|
||||
|
||||
if not success_response:
|
||||
options += ['QCO_NO_SUCCESS_RESP']
|
||||
if allow_oob:
|
||||
options += ['QCO_ALLOW_OOB']
|
||||
if allow_preconfig:
|
||||
options += ['QCO_ALLOW_PRECONFIG']
|
||||
|
||||
if not options:
|
||||
options = ['QCO_NO_OPTIONS']
|
||||
@ -275,8 +277,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
|
||||
c_prefix=c_name(self._prefix, protect=False)))
|
||||
genc.add(gen_registry(self._regy, self._prefix))
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response, boxed, allow_oob):
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
if not gen:
|
||||
return
|
||||
self._genh.add(gen_command_decl(name, arg_type, boxed, ret_type))
|
||||
@ -285,7 +287,8 @@ void %(c_prefix)sqmp_init_marshal(QmpCommandList *cmds);
|
||||
self._genc.add(gen_marshal_output(ret_type))
|
||||
self._genh.add(gen_marshal_decl(name))
|
||||
self._genc.add(gen_marshal(name, arg_type, boxed, ret_type))
|
||||
self._regy += gen_register_command(name, success_response, allow_oob)
|
||||
self._regy += gen_register_command(name, success_response, allow_oob,
|
||||
allow_preconfig)
|
||||
|
||||
|
||||
def gen_commands(schema, output_dir, prefix):
|
||||
|
@ -872,7 +872,8 @@ def check_keys(expr_elem, meta, required, optional=[]):
|
||||
raise QAPISemError(info,
|
||||
"'%s' of %s '%s' should only use false value"
|
||||
% (key, meta, name))
|
||||
if (key == 'boxed' or key == 'allow-oob') and value is not True:
|
||||
if (key == 'boxed' or key == 'allow-oob' or
|
||||
key == 'allow-preconfig') and value is not True:
|
||||
raise QAPISemError(info,
|
||||
"'%s' of %s '%s' should only use true value"
|
||||
% (key, meta, name))
|
||||
@ -922,7 +923,7 @@ def check_exprs(exprs):
|
||||
meta = 'command'
|
||||
check_keys(expr_elem, 'command', [],
|
||||
['data', 'returns', 'gen', 'success-response',
|
||||
'boxed', 'allow-oob'])
|
||||
'boxed', 'allow-oob', 'allow-preconfig'])
|
||||
elif 'event' in expr:
|
||||
meta = 'event'
|
||||
check_keys(expr_elem, 'event', [], ['data', 'boxed'])
|
||||
@ -1044,8 +1045,8 @@ class QAPISchemaVisitor(object):
|
||||
def visit_alternate_type(self, name, info, variants):
|
||||
pass
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response, boxed, allow_oob):
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
pass
|
||||
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
@ -1422,7 +1423,7 @@ class QAPISchemaAlternateType(QAPISchemaType):
|
||||
|
||||
class QAPISchemaCommand(QAPISchemaEntity):
|
||||
def __init__(self, name, info, doc, arg_type, ret_type,
|
||||
gen, success_response, boxed, allow_oob):
|
||||
gen, success_response, boxed, allow_oob, allow_preconfig):
|
||||
QAPISchemaEntity.__init__(self, name, info, doc)
|
||||
assert not arg_type or isinstance(arg_type, str)
|
||||
assert not ret_type or isinstance(ret_type, str)
|
||||
@ -1434,6 +1435,7 @@ class QAPISchemaCommand(QAPISchemaEntity):
|
||||
self.success_response = success_response
|
||||
self.boxed = boxed
|
||||
self.allow_oob = allow_oob
|
||||
self.allow_preconfig = allow_preconfig
|
||||
|
||||
def check(self, schema):
|
||||
if self._arg_type_name:
|
||||
@ -1458,7 +1460,8 @@ class QAPISchemaCommand(QAPISchemaEntity):
|
||||
visitor.visit_command(self.name, self.info,
|
||||
self.arg_type, self.ret_type,
|
||||
self.gen, self.success_response,
|
||||
self.boxed, self.allow_oob)
|
||||
self.boxed, self.allow_oob,
|
||||
self.allow_preconfig)
|
||||
|
||||
|
||||
class QAPISchemaEvent(QAPISchemaEntity):
|
||||
@ -1678,6 +1681,7 @@ class QAPISchema(object):
|
||||
success_response = expr.get('success-response', True)
|
||||
boxed = expr.get('boxed', False)
|
||||
allow_oob = expr.get('allow-oob', False)
|
||||
allow_preconfig = expr.get('allow-preconfig', False)
|
||||
if isinstance(data, OrderedDict):
|
||||
data = self._make_implicit_object_type(
|
||||
name, info, doc, 'arg', self._make_members(data, info))
|
||||
@ -1686,7 +1690,7 @@ class QAPISchema(object):
|
||||
rets = self._make_array_type(rets[0], info)
|
||||
self._def_entity(QAPISchemaCommand(name, info, doc, data, rets,
|
||||
gen, success_response,
|
||||
boxed, allow_oob))
|
||||
boxed, allow_oob, allow_preconfig))
|
||||
|
||||
def _def_event(self, expr, info, doc):
|
||||
name = expr['event']
|
||||
|
@ -226,8 +226,8 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
|
||||
name=doc.symbol,
|
||||
body=texi_entity(doc, 'Members')))
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response, boxed, allow_oob):
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
doc = self.cur_doc
|
||||
if boxed:
|
||||
body = texi_body(doc)
|
||||
|
@ -171,14 +171,15 @@ const QLitObject %(c_name)s = %(c_string)s;
|
||||
{'members': [{'type': self._use_type(m.type)}
|
||||
for m in variants.variants]})
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response, boxed, allow_oob):
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
arg_type = arg_type or self._schema.the_empty_object_type
|
||||
ret_type = ret_type or self._schema.the_empty_object_type
|
||||
self._gen_qlit(name, 'command',
|
||||
{'arg-type': self._use_type(arg_type),
|
||||
'ret-type': self._use_type(ret_type),
|
||||
'allow-oob': allow_oob})
|
||||
'allow-oob': allow_oob,
|
||||
'allow-preconfig': allow_preconfig})
|
||||
|
||||
def visit_event(self, name, info, arg_type, boxed):
|
||||
arg_type = arg_type or self._schema.the_empty_object_type
|
||||
|
@ -41,8 +41,8 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
|
||||
print('alternate %s' % name)
|
||||
self._print_variants(variants)
|
||||
|
||||
def visit_command(self, name, info, arg_type, ret_type,
|
||||
gen, success_response, boxed, allow_oob):
|
||||
def visit_command(self, name, info, arg_type, ret_type, gen,
|
||||
success_response, boxed, allow_oob, allow_preconfig):
|
||||
print('command %s %s -> %s' % \
|
||||
(name, arg_type and arg_type.name, ret_type and ret_type.name))
|
||||
print(' gen=%s success_response=%s boxed=%s oob=%s' % \
|
||||
|
Loading…
Reference in New Issue
Block a user