mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
virsh: Add QMP command wrapping for 'qemu-monitor-command'
Issuing simple QMP commands is pain as they need to be wrapped by the JSON wrapper: { "execute": "COMMAND" } and optionally also: { "execute": "COMMAND", "arguments":...} For simple commands without arguments we can add syntax sugar to virsh which allows simple usage of QMP and additionally prepares also for passing through of the 'arguments' section: virsh qemu-monitor-command $VM query-status is equivalent to virsh qemu-monitor-command $VM '{"execute":"query-status"}' and virsh qemu-monitor-command $VM query-named-block-nodes '{"flat":true}' or virsh qemu-monitor-command $VM query-named-block-nodes '"flat":true' is equivalent to virsh qemu-monitor-command $VM '{"execute":"query-named-block-nodes", "arguments":{"flat":true}}' Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
82c2196840
commit
289aa4bc5b
@ -7802,7 +7802,21 @@ If more than one argument is provided for *command*, they are concatenated with
|
||||
a space in between before passing the single command to the monitor.
|
||||
|
||||
Note that libvirt uses the QMP to talk to qemu so *command* must be valid JSON
|
||||
in QMP format to work properly.
|
||||
in QMP format to work properly. If *command* is not a JSON object libvirt tries
|
||||
to wrap it as a JSON object to provide convenient interface such as the groups
|
||||
of commands with identical handling:
|
||||
|
||||
::
|
||||
|
||||
# simple command
|
||||
$ virsh qemu-monitor-command VM commandname
|
||||
$ virsh qemu-monitor-command VM '{"execute":"commandname"}'
|
||||
|
||||
# with arguments
|
||||
$ virsh qemu-monitor-command VM commandname '"arg1":123' '"arg2":"test"'
|
||||
$ virsh qemu-monitor-command VM commandname '{"arg1":123,"arg2":"test"}'
|
||||
$ virsh qemu-monitor-command VM '{"execute":"commandname", "arguments":{"arg1":123,"arg2":"test"}}'
|
||||
|
||||
|
||||
If *--pretty* is given the QMP reply is pretty-printed.
|
||||
|
||||
|
@ -9555,6 +9555,84 @@ static const vshCmdOptDef opts_qemu_monitor_command[] = {
|
||||
{.name = NULL}
|
||||
};
|
||||
|
||||
|
||||
static char *
|
||||
cmdQemuMonitorCommandConcatCmd(vshControl *ctl,
|
||||
const vshCmd *cmd,
|
||||
const vshCmdOpt *opt)
|
||||
{
|
||||
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
||||
virBufferAsprintf(&buf, "%s ", opt->data);
|
||||
|
||||
virBufferTrim(&buf, " ");
|
||||
|
||||
return virBufferContentAndReset(&buf);
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
cmdQemuMonitorCommandQMPWrap(vshControl *ctl,
|
||||
const vshCmd *cmd)
|
||||
{
|
||||
g_autofree char *fullcmd = cmdQemuMonitorCommandConcatCmd(ctl, cmd, NULL);
|
||||
g_autoptr(virJSONValue) fullcmdjson = virJSONValueFromString(fullcmd);
|
||||
g_autofree char *fullargs = NULL;
|
||||
g_autoptr(virJSONValue) fullargsjson = NULL;
|
||||
const vshCmdOpt *opt = NULL;
|
||||
const char *commandname = NULL;
|
||||
g_autoptr(virJSONValue) command = NULL;
|
||||
g_autoptr(virJSONValue) arguments = NULL;
|
||||
|
||||
/* if we've got a JSON object, pass it through */
|
||||
if (virJSONValueIsObject(fullcmdjson))
|
||||
return g_steal_pointer(&fullcmd);
|
||||
|
||||
/* we try to wrap the command and possible arguments into a JSON object, if
|
||||
* we as fall back we pass through what we've got from the user */
|
||||
|
||||
if ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
||||
commandname = opt->data;
|
||||
|
||||
/* now we process arguments similarly to how we've dealt with the full command */
|
||||
if ((fullargs = cmdQemuMonitorCommandConcatCmd(ctl, cmd, opt)))
|
||||
fullargsjson = virJSONValueFromString(fullargs);
|
||||
|
||||
/* for empty args or a valid JSON object we just use that */
|
||||
if (!fullargs || virJSONValueIsObject(fullargsjson)) {
|
||||
arguments = g_steal_pointer(&fullargsjson);
|
||||
} else {
|
||||
/* for a non-object we try to concatenate individual _ARGV bits into a
|
||||
* JSON object wrapper and try using that */
|
||||
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
||||
|
||||
virBufferAddLit(&buf, "{");
|
||||
/* opt points to the _ARGV option bit containing the command so we'll
|
||||
* iterate through the arguments now */
|
||||
while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
||||
virBufferAsprintf(&buf, "%s,", opt->data);
|
||||
|
||||
virBufferTrim(&buf, ",");
|
||||
virBufferAddLit(&buf, "}");
|
||||
|
||||
if (!(arguments = virJSONValueFromString(virBufferCurrentContent(&buf)))) {
|
||||
vshError(ctl, _("failed to wrap arguments '%s' into a QMP command wrapper"),
|
||||
fullargs);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (virJSONValueObjectCreate(&command,
|
||||
"s:execute", commandname,
|
||||
"A:arguments", &arguments,
|
||||
NULL) < 0)
|
||||
return NULL;
|
||||
|
||||
return virJSONValueToString(command, false);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
|
||||
{
|
||||
@ -9563,8 +9641,6 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
|
||||
g_autofree char *result = NULL;
|
||||
g_autoptr(virJSONValue) resultjson = NULL;
|
||||
unsigned int flags = 0;
|
||||
const vshCmdOpt *opt = NULL;
|
||||
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
||||
bool pretty = vshCommandOptBool(cmd, "pretty");
|
||||
bool returnval = vshCommandOptBool(cmd, "return-value");
|
||||
virJSONValue *formatjson;
|
||||
@ -9576,15 +9652,17 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
|
||||
if (!(dom = virshCommandOptDomain(ctl, cmd, NULL)))
|
||||
return false;
|
||||
|
||||
while ((opt = vshCommandOptArgv(ctl, cmd, opt)))
|
||||
virBufferAsprintf(&buf, "%s ", opt->data);
|
||||
|
||||
virBufferTrim(&buf, " ");
|
||||
|
||||
monitor_cmd = virBufferContentAndReset(&buf);
|
||||
|
||||
if (vshCommandOptBool(cmd, "hmp"))
|
||||
if (vshCommandOptBool(cmd, "hmp")) {
|
||||
flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP;
|
||||
monitor_cmd = cmdQemuMonitorCommandConcatCmd(ctl, cmd, NULL);
|
||||
} else {
|
||||
monitor_cmd = cmdQemuMonitorCommandQMPWrap(ctl, cmd);
|
||||
}
|
||||
|
||||
if (!monitor_cmd) {
|
||||
vshSaveLibvirtError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0)
|
||||
return false;
|
||||
|
Loading…
Reference in New Issue
Block a user