Cc: the qemu-ga maintainer John Snow <js...@redhat.com> writes:
> [Moving our discussion upstream, because it stopped being brief and simple.] Motivation: qemu-ga doesn't do capability negotiation as specified in docs/interop/qmp-spec.txt. Reminder: qmp-spec.txt specifies the server shall send a greeting containing the capabilities on offer. The client shall send a qmp_capabilities command before any other command. We can't just fix qemu-ga to comply, because it would break existing clients. We could document its behavior in qmp-spec.txt. Easy enough, but also kind of sad. Is there a way to add capability negotiation to qemu-ga without breaking existing clients? We obviously have to make it optional. The obvious idea "make qmp_capabilities optional" doesn't work, because the client needs to receive the greeting before sending qmp_capabilities, to learn what capabilities are on offer. This leads to... > What about something like this: > > Add a new "request-negotiation" command to qemu-guest-agent 7.0.0. > > [Modern client to unknown server] > 1. A modern client connects to a server of unknown version, and > without waiting, issues the "request-negotiation" command. > 2. An old server will reply with CommandNotFound. We are done negotiating. > 3. A modern server will reply with the greeting in the traditional > format, but as a reply object (to preserve "execute" semantics.) > 4. The modern client will now issue qmp-capabilities as normal. > 5. The server replies with success or failure as normal. > 6. Connection is fully established. > > [Old client to unknown server] > 1. An old client connects to an unknown version server. > 2. A command is issued some time later. > 2a. The server is old, the command worked as anticipated. > 2b. The server is new, the command fails with CommandNotFound and > urges the use of 'request-negotiation'. A new server could accept the command, too. This way, negotiation remains optional, unlike in "normal" QMP. Old clients don't negotiate, and get default capabilities. > Compatibility matrix summary: > Old client on old server: Works just fine, as always. > Old client on new server: Will fail; the new server requires the > negotiation step to be performed. This is a tractable problem. > POSSIBLY we need to send some kind of "warning event" for two versions > before making it genuinely mandatory. Also tractable. With optional negotiation, this works fine, too. > New client on old server: Works, albeit with a single failed execute > command now in the log file. > New client on new server: Works, though handshaking is now permanently > a little chattier than with any other QMP server. > > ***The QMP spec will need to be updated*** to state: the asynchronous > greeting is mandatory on all QMP implementations, EXCEPT for the > qemu-guest-agent, which for historical reasons, uses an alternate > handshaking process, ... > > Compatibility concerns: > - We must never remove the 'request-negotiation' command from QGA, > forever-and-ever, unless we also make a new error class for > "NegotiationRequired" that's distinct from "CommandNotFound", but > that's more divergence. Supporting the negotiation request command > forever-and-ever is probably fine. Yup. > - QGA is now officially on a different flavor of QMP protocol. You > still need to know in advance if you are connecting to QGA or anything > else. That's still a little sad, but maybe that's just simply an > impossible goal. > > Bonus: > - If an execution ID is used when sending "request-negotiation", we > know that the server is at least version 4.0.0 if it responds to us > using that ID. A modern client can then easily distinguish between > pre-4.0, post-4.0 and post-7.0 servers. It's a useful probe. Mike, thoughts?