[libvirt] [PATCH v2] qemu: Add shortcut for HMP pass through

Jiri Denemark jdenemar at redhat.com
Thu Feb 3 09:43:10 UTC 2011


Currently users who want to use virDomainQemuMonitorCommand() API or
it's virsh equivalent has to use the same protocol as libvirt uses for
communication to qemu. Since the protocol is QMP with current qemu and
HMP much more usable for humans, one ends up typing something like the
following:

    virsh qemu-monitor-command DOM \
'{"execute":"human-monitor-command","arguments":{"command-line":"info kvm"}}'

which is not a very convenient way of debugging qemu.

This patch introduces --hmp option to qemu-monitor-command, which says
that the provided command is in HMP. If libvirt uses QMP to talk with
qemu, the command will automatically be converted into QMP. So the
example above is simplified to just

    virsh qemu-monitor-command --hmp DOM "info kvm"

Also the result is converted from

    {"return":"kvm support: enabled\r\n"}

to just plain HMP:

    kvm support: enabled

If libvirt talks to qemu in HMP, --hmp flag is obviously a noop.
---
Notes:
    Version 2:
    - document --hmp in virsh man page
    - add missing virReportOOMError() in qemuMonitorArbitraryCommand()

 include/libvirt/libvirt-qemu.h |    5 +++++
 src/internal.h                 |    1 +
 src/qemu/qemu_driver.c         |    7 +++++--
 src/qemu/qemu_monitor.c        |    9 ++++++---
 src/qemu/qemu_monitor.h        |    5 ++++-
 src/qemu/qemu_monitor_json.c   |   30 ++++++++++++++++++++++++++----
 src/qemu/qemu_monitor_json.h   |    3 ++-
 tools/virsh.c                  |    7 ++++++-
 tools/virsh.pod                |    7 +++++--
 9 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h
index 9c191c7..9257c2f 100644
--- a/include/libvirt/libvirt-qemu.h
+++ b/include/libvirt/libvirt-qemu.h
@@ -20,6 +20,11 @@
 extern "C" {
 # endif
 
+enum {
+    VIR_DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT = 0,
+    VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP     = (1 << 0), /* cmd is in HMP */
+} virDomainQemuMonitorCommandFlags;
+
 int virDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd,
                                 char **result, unsigned int flags);
 
diff --git a/src/internal.h b/src/internal.h
index 11ba45f..e263684 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -38,6 +38,7 @@
 # define N_(str) str
 
 # include "libvirt/libvirt.h"
+# include "libvirt/libvirt-qemu.h"
 # include "libvirt/virterror.h"
 
 # include "libvirt_internal.h"
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a3a68b1..cce115a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -10237,8 +10237,9 @@ static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
     virDomainObjPtr vm = NULL;
     int ret = -1;
     qemuDomainObjPrivatePtr priv;
+    bool hmp;
 
-    virCheckFlags(0, -1);
+    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
 
     qemuDriverLock(driver);
     vm = virDomainFindByUUID(&driver->domains, domain->uuid);
@@ -10264,10 +10265,12 @@ static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
         priv->monitor_warned = 1;
     }
 
+    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);
+
     if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
         goto cleanup;
     qemuDomainObjEnterMonitorWithDriver(driver, vm);
-    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result);
+    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
     qemuDomainObjExitMonitorWithDriver(driver, vm);
     if (qemuDomainObjEndJob(vm) == 0) {
         vm = NULL;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 0c14277..fdb6b79 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2007,14 +2007,17 @@ int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name)
     return ret;
 }
 
-int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply)
+int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
+                                const char *cmd,
+                                char **reply,
+                                bool hmp)
 {
     int ret;
 
-    DEBUG("mon=%p, cmd=%s, reply=%p", mon, cmd, reply);
+    DEBUG("mon=%p, cmd=%s, reply=%p, hmp=%d", mon, cmd, reply, hmp);
 
     if (mon->json)
-        ret = qemuMonitorJSONArbitraryCommand(mon, cmd, reply);
+        ret = qemuMonitorJSONArbitraryCommand(mon, cmd, reply, hmp);
     else
         ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply);
     return ret;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 92c550b..0ea1330 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -397,7 +397,10 @@ int qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name);
 int qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name);
 int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name);
 
-int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply);
+int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
+                                const char *cmd,
+                                char **reply,
+                                bool hmp);
 
 /**
  * When running two dd process and using <> redirection, we need a
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index ca06e7e..d5e8d37 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2457,22 +2457,44 @@ int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name)
 
 int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
                                     const char *cmd_str,
-                                    char **reply_str)
+                                    char **reply_str,
+                                    bool hmp)
 {
     virJSONValuePtr cmd = NULL;
     virJSONValuePtr reply = NULL;
     int ret = -1;
 
-    cmd = virJSONValueFromString(cmd_str);
+    if (!hmp) {
+        cmd = virJSONValueFromString(cmd_str);
+    } else {
+        cmd = qemuMonitorJSONMakeCommand("human-monitor-command",
+                                         "s:command-line", cmd_str,
+                                         NULL);
+    }
+
     if (!cmd)
         return -1;
 
     if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
         goto cleanup;
 
-    *reply_str = virJSONValueToString(reply);
-    if (!(*reply_str))
+    if (!hmp) {
+        if (!(*reply_str = virJSONValueToString(reply)))
+            goto cleanup;
+    } else if (qemuMonitorJSONCheckError(cmd, reply)) {
         goto cleanup;
+    } else {
+        const char *data;
+        if (!(data = virJSONValueObjectGetString(reply, "return"))) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("human monitor command was missing return data"));
+            goto cleanup;
+        }
+        if (!(*reply_str = strdup(data))) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    }
 
     ret = 0;
 
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 4c47f10..4ae472a 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -209,6 +209,7 @@ int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name);
 
 int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
                                     const char *cmd_str,
-                                    char **reply_str);
+                                    char **reply_str,
+                                    bool hmp);
 
 #endif /* QEMU_MONITOR_JSON_H */
diff --git a/tools/virsh.c b/tools/virsh.c
index 59d099e..1f820e8 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10176,6 +10176,7 @@ static const vshCmdInfo info_qemu_monitor_command[] = {
 static const vshCmdOptDef opts_qemu_monitor_command[] = {
     {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
     {"cmd", VSH_OT_DATA, VSH_OFLAG_REQ, N_("command")},
+    {"hmp", VSH_OT_BOOL, 0, N_("command is in human monitor protocol")},
     {NULL, 0, 0, NULL}
 };
 
@@ -10186,6 +10187,7 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
     int ret = FALSE;
     char *monitor_cmd;
     char *result = NULL;
+    unsigned int flags = 0;
 
     if (!vshConnectionUsability(ctl, ctl->conn))
         goto cleanup;
@@ -10200,7 +10202,10 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd)
         goto cleanup;
     }
 
-    if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, 0) < 0)
+    if (vshCommandOptBool(cmd, "hmp"))
+        flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP;
+
+    if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0)
         goto cleanup;
 
     printf("%s\n", result);
diff --git a/tools/virsh.pod b/tools/virsh.pod
index d6a16f2..bfaa67e 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1253,10 +1253,13 @@ problems to the libvirt developers; the reports will be ignored.
 
 =over 4
 
-=item B<qemu-monitor-command> I<domain> I<command>
+=item B<qemu-monitor-command> I<domain> I<command> optional I<--hmp>
 
 Send an arbitrary monitor command I<command> to domain I<domain> through the
-qemu monitor.  The results of the command will be printed on stdout.
+qemu monitor.  The results of the command will be printed on stdout.  If
+I<--hmp> is passed, the command is considered to be a human monitor command
+and libvirt will automatically convert it into QMP if needed.  In that case
+the result will also be converted back from QMP.
 
 =back
 
-- 
1.7.4




More information about the libvir-list mailing list