On 03/19/2012 06:45 PM, Michael Roth wrote:
So IMO, returning arguments actually seems easier for both clients and the
server, and is more resilient to downstream changes. It does require a more
formal specification of the protocol though. Basically: "an option/field
may not be supported in older/future versions of QEMU, so it is up to
the client to check in advance by referencing the QAPI schema for their
qemu version or programatically via get_schema(<command>)"
The complexity of writing a client using get_schema() is close to staggering :-/
I'm not sure, I mean, take libvirt, you need to marshall up the
arguments anyway and put them into a QMP payload, so in that case the
client developer is aware of the schema that they're coding against,
and also understand the QAPI schema specification, and if the schema
is nested then so is the client version of that "schema".
So, conceptually at least, it seems like it wouldn't be that big a jump
to maintain an internal representation of their schema to
programatically check against the specification they were coding
against, it's just the part where they then need to bake it into the
client implementation that's a bit heavy-handed.
So let's work through a few examples. Today, you have to maintain a list of
commands returned from query-commands and check for set membership:
if 'query-netdev2' in commands:
qmp.query_netdev2(foo)
else:
qmp.query_netdev()
Pretty simple. If we have a schema representation, we'll need to be able to
check for arguments. That means we need a way to check if a command has an
argument. We could do this as nested lists:
if (commands.has_key('query-netdev') and
commands['query-netdev']['args'].has_key('interface')):
qmp.query_netdev(foo)
else:
qmp.query_netdev()
This is only really possible in a dynamically typed language, which sucks, but
let's ignore that for now. This is a bit more complicated but unfortunately,
it's not enough.
Because we can add members to structures and structures can be arguments. So we
really need a way to say:
1) Do we have the query-netdev command
2) Does it take a parameter called interface of type NetDevArgument
3) Does the NetDevArgument have a member called 'foo'.
But this actually can be arbitrarily deep in terms of complex. Maybe you make a
simple query language so you can execute schema queries in a single line.
So you have an interface definition that is the schema that describes an
unstructured wire protocol and a query language to determine when and how the
schema changes. If that doesn't ring a bell to you, congratulations, you've
invented SOAP.
The interface description in SOAP is WSDL and XPath is the query language.
Writing a SOAP client is a train wreck. It's so bad that even in dynamic
languages, people almost always use code generators.
A good RPC makes the client simple. If that means we need to take care when
introducing new interfaces, then it's a small price to pay for avoiding the
nightmares of an over engineered RPC like SOAP.
Regards,
Anthony Liguori
Thinking about it more the, this does seem to be completely at odds with
any future prospects of a libqmp, so that's a pretty big trade-off...
Regards,
Anthony Liguori