[libvirt] [PATCH] qemu_agent: support qemu agent general command

MATSUDA, Daiki matsudadik at intellilink.co.jp
Fri Jul 6 01:29:57 UTC 2012


Hi, All.

Thank you for many comments.
And I extremely apologize not to use git... My company's network closes 
the almost port and only http via proxy and simple mail are available.

The attached patch is reflected all comments.

Especially,
 >> diff -uNrp libvirt-0.9.13.orig/src/driver.h libvirt-0.9.13/src/driver.h
 >> --- libvirt-0.9.13.orig/src/driver.h	2012-06-25 16:06:18.000000000 +0900
 >> +++ libvirt-0.9.13/src/driver.h	2012-07-02 10:02:54.405454285 +0900
 >> @@ -860,6 +860,10 @@ typedef char *
 >>                                  const char *uri,
 >>                                  unsigned int flags);
 >>
 >> +typedef int
 >> +    (*virDrvDomainGuestAgentCommand)(virDomainPtr domain, const 
char *cmd,
 >> +                                     char **result, unsigned int 
flags);
 >> +
 >>   /**
 >>    * _virDriver:
 >>    *
 >> @@ -1041,6 +1045,7 @@ struct _virDriver {
 >>       virDrvDomainGetDiskErrors           domainGetDiskErrors;
 >>       virDrvDomainSetMetadata             domainSetMetadata;
 >>       virDrvDomainGetMetadata             domainGetMetadata;
 >> +    virDrvDomainGuestAgentCommand       qemuDomainGuestAgentCommand;
 >>   };
 >
 > I'd move these two as close as possible to 
virDrvDomainQemuMonitorCommand so we have similar commands grouped.

I moved virDrvDomainQemuMonitorCommand to virDrvDomainQemuSupportCommand 
to close two functions.

In addition,
 >> diff -uNrp libvirt-0.9.13.orig/src/qemu/qemu_agent.c 
libvirt-0.9.13/src/qemu/qemu_agent.c
 >> --- libvirt-0.9.13.orig/src/qemu/qemu_agent.c	2012-06-25 
16:06:18.000000000 +0900
 >> +++ libvirt-0.9.13/src/qemu/qemu_agent.c	2012-07-02 
10:02:54.408488163 +0900
 >> @@ -1410,3 +1410,29 @@ qemuAgentSuspend(qemuAgentPtr mon,
 >>       virJSONValueFree(reply);
 >>       return ret;
 >>   }
 >> +
 >> +int qemuAgentGuestAgentCommand(qemuAgentPtr mon,
 >> +                               const char *cmd,
 >> +                               char **result)
 >> +{
 >> +    int ret = -1;
 >> +    virJSONValuePtr jcmd;
 >> +    virJSONValuePtr reply = NULL;
 >> +
 >> +    jcmd = qemuAgentMakeCommand(cmd, NULL);
 >> +    if (!jcmd)
 >> +        return ret;
 >
 > This is confusing. In case of qemu-monitor-command we require user to 
pass whole command string:
 >      {'execute':'some-dummy-command'}
 > which is correct as we don't lock them in {'execute':'%s'} scheme. 
Remember, we want them to
 > use commands/features not yet exposed by libvirt. So if qemu will 
ever come up with different
 > command scheme this API will remain broken. In addition - and this is 
even more serious - there is
 > no way of specifying arguments to a command, e.g. guest-sync take an 
integer:
 >       {'execute':'guest-sync', 'arguments':{'id':123}}
 > Therefore I think we need to drop qemuAgentMakeCommand() here and 
require users to do
 > the very same here as they do in qemu-monitor-command.

I prefer to the type of 'virsh qemu-agent-command guest-info', bacause 
it is user friendly. But I understood the problem and fixed.

Regards
MATSUDA Daiki

$ diffstat libvirt-0.9.13_qemu_agent_command3.patch
  daemon/remote.c                      |   36 +++++++++++++++++
  docs/hvsupport.pl                    |    1
  include/libvirt/libvirt-qemu.h       |    3 +
  python/generator.py                  |    1
  python/libvirt-qemu-override-api.xml |    7 +++
  python/libvirt-qemu-override.c       |   31 ++++++++++++++
  src/driver.h                         |    5 +-
  src/libvirt-qemu.c                   |   49 +++++++++++++++++++++++
  src/libvirt_qemu.syms                |    5 ++
  src/qemu/qemu_agent.c                |   26 ++++++++++++
  src/qemu/qemu_agent.h                |    4 +
  src/qemu/qemu_driver.c               |   73 
+++++++++++++++++++++++++++++++++++
  src/qemu_protocol-structs            |    9 ++++
  src/remote/qemu_protocol.x           |   13 +++++-
  src/remote/remote_driver.c           |   39 ++++++++++++++++++
  tools/virsh.c                        |   64 ++++++++++++++++++++++++++++++
  16 files changed, 363 insertions(+), 3 deletions(-)


virsh # qemu-agent-command RHEL58_64 '{"execute":"guest-info"}'
{"return":{"version":"1.1.50","supported_commands":[{"enabled":true,"name":"guest-network-get-interfaces"},{"enabled":true,"name":"guest-suspend-hybrid"},{"enabled":true,"name":"guest-suspend-ram"},{"enabled":true,"name":"guest-suspend-disk"},{"enabled":true,"name":"guest-fsfreeze-thaw"},{"enabled":true,"name":"guest-fsfreeze-freeze"},{"enabled":true,"name":"guest-fsfreeze-status"},{"enabled":true,"name":"guest-file-flush"},{"enabled":true,"name":"guest-file-seek"},{"enabled":true,"name":"guest-file-write"},{"enabled":true,"name":"guest-file-read"},{"enabled":true,"name":"guest-file-close"},{"enabled":true,"name":"guest-file-open"},{"enabled":true,"name":"guest-shutdown"},{"enabled":true,"name":"guest-info"},{"enabled":true,"name":"guest-ping"},{"enabled":true,"name":"guest-sync"},{"enabled":true,"name":"guest-sync-delimited"}]}}

virsh # qemu-agent-command RHEL58_64 '{"execute":"guest-sync", 
"arguments":{"id":123}}'
{"return":123}



-------------- next part --------------
diff -uNrp libvirt-0.9.13.orig/daemon/remote.c libvirt-0.9.13/daemon/remote.c
--- libvirt-0.9.13.orig/daemon/remote.c	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/daemon/remote.c	2012-07-06 09:18:12.494454191 +0900
@@ -3923,6 +3923,42 @@ cleanup:
     return rv;
 }
 
+
+static int
+qemuDispatchAgentCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
+                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                              virNetMessageErrorPtr rerr,
+                              qemu_agent_command_args *args,
+                              qemu_agent_command_ret *ret)
+{
+    virDomainPtr dom = NULL;
+    int rv = -1;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    if (!priv->conn) {
+        virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+        goto cleanup;
+    }
+
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+        goto cleanup;
+
+    if (virDomainQemuAgentCommand(dom, args->cmd, &ret->result,
+                                  args->flags) < 0) {
+        goto cleanup;
+    }
+
+    rv = 0;
+cleanup:
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    if (dom)
+        virDomainFree(dom);
+    return rv;
+}
+
 /*----- Helpers. -----*/
 
 /* get_nonnull_domain and get_nonnull_network turn an on-wire
diff -uNrp libvirt-0.9.13.orig/docs/hvsupport.pl libvirt-0.9.13/docs/hvsupport.pl
--- libvirt-0.9.13.orig/docs/hvsupport.pl	2011-06-10 15:50:11.000000000 +0900
+++ libvirt-0.9.13/docs/hvsupport.pl	2012-07-06 09:18:36.363454752 +0900
@@ -129,6 +129,7 @@ $apis{virDomainMigratePerform3} = "0.9.2
 $apis{virDomainMigrateFinish3} = "0.9.2";
 $apis{virDomainMigrateConfirm3} = "0.9.2";
 
+$apis{virDomainQemuSupportCommand} = "0.9.14";
 
 
 # Now we want to get the mapping between public APIs
diff -uNrp libvirt-0.9.13.orig/include/libvirt/libvirt-qemu.h libvirt-0.9.13/include/libvirt/libvirt-qemu.h
--- libvirt-0.9.13.orig/include/libvirt/libvirt-qemu.h	2012-03-06 22:59:21.000000000 +0900
+++ libvirt-0.9.13/include/libvirt/libvirt-qemu.h	2012-07-06 09:18:12.494454191 +0900
@@ -32,6 +32,9 @@ virDomainPtr virDomainQemuAttach(virConn
                                  unsigned int pid_value,
                                  unsigned int flags);
 
+int virDomainQemuAgentCommand(virDomainPtr domain, const char *cmd,
+                              char **result, unsigned int flags);
+
 # ifdef __cplusplus
 }
 # endif
diff -uNrp libvirt-0.9.13.orig/python/generator.py libvirt-0.9.13/python/generator.py
--- libvirt-0.9.13.orig/python/generator.py	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/python/generator.py	2012-07-06 09:18:12.495454550 +0900
@@ -429,6 +429,7 @@ skip_impl = (
 
 qemu_skip_impl = (
     'virDomainQemuMonitorCommand',
+    'virDomainQemuAgentCommand',
 )
 
 
diff -uNrp libvirt-0.9.13.orig/python/libvirt-qemu-override-api.xml libvirt-0.9.13/python/libvirt-qemu-override-api.xml
--- libvirt-0.9.13.orig/python/libvirt-qemu-override-api.xml	2011-09-14 15:24:44.000000000 +0900
+++ libvirt-0.9.13/python/libvirt-qemu-override-api.xml	2012-07-06 09:18:12.496455183 +0900
@@ -8,5 +8,12 @@
         <arg name='cmd' type='const char *' info='the command which will be passed to QEMU monitor'/>
         <arg name='flags' type='unsigned int' info='an OR'ed set of virDomainQemuMonitorCommandFlags'/>
       </function>
+      <function name='virDomainQemuAgentCommand' file='python-qemu'>
+        <info>Send a Guest Agent command to domain</info>
+        <return type='str *' info='the command output or None in case of error'/>
+        <arg name='domain' type='virDomainPtr' info='pointer to the domain'/>
+        <arg name='cmd' type='const char *' info='guest agent command on domain'/>
+        <arg name='flags' type='unsigned int' info='execution flags'/>
+      </function>
   </symbols>
 </api>
diff -uNrp libvirt-0.9.13.orig/python/libvirt-qemu-override.c libvirt-0.9.13/python/libvirt-qemu-override.c
--- libvirt-0.9.13.orig/python/libvirt-qemu-override.c	2012-03-30 11:45:28.000000000 +0900
+++ libvirt-0.9.13/python/libvirt-qemu-override.c	2012-07-06 09:18:12.496455183 +0900
@@ -82,6 +82,36 @@ libvirt_qemu_virDomainQemuMonitorCommand
     return py_retval;
 }
 
+static PyObject *
+libvirt_qemu_virDomainQemuAgentCommand(PyObject *self ATTRIBUTE_UNUSED,
+                                       PyObject *args)
+{
+    PyObject *py_retval;
+    char *result = NULL;
+    virDomainPtr domain;
+    PyObject *pyobj_domain;
+    unsigned int flags;
+    char *cmd;
+    int c_retval;
+
+    if (!PyArg_ParseTuple(args, (char *)"Ozi:virDomainQemuAgentCommand",
+                          &pyobj_domain, &cmd, &flags))
+        return NULL;
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    if (domain == NULL)
+        return VIR_PY_NONE;
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    c_retval = virDomainQemuAgentCommand(domain, cmd, &result, flags);
+    LIBVIRT_END_ALLOW_THREADS;
+
+    if (c_retval < 0)
+        return VIR_PY_NONE;
+
+    py_retval = PyString_FromString(result);
+    return py_retval;
+}
+
 /************************************************************************
  *									*
  *			The registration stuff				*
@@ -90,6 +120,7 @@ libvirt_qemu_virDomainQemuMonitorCommand
 static PyMethodDef libvirtQemuMethods[] = {
 #include "libvirt-qemu-export.c"
     {(char *) "virDomainQemuMonitorCommand", libvirt_qemu_virDomainQemuMonitorCommand, METH_VARARGS, NULL},
+    {(char *) "virDomainQemuAgentCommand", libvirt_qemu_virDomainQemuAgentCommand, METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}
 };
 
diff -uNrp libvirt-0.9.13.orig/src/driver.h libvirt-0.9.13/src/driver.h
--- libvirt-0.9.13.orig/src/driver.h	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/driver.h	2012-07-06 09:18:12.497454257 +0900
@@ -680,7 +680,7 @@ typedef int
                                   unsigned int flags);
 
 typedef int
-    (*virDrvDomainQemuMonitorCommand)(virDomainPtr domain, const char *cmd,
+    (*virDrvDomainQemuSupportCommand)(virDomainPtr domain, const char *cmd,
                                       char **result, unsigned int flags);
 
 /* Choice of unsigned int rather than pid_t is intentional.  */
@@ -1015,7 +1015,7 @@ struct _virDriver {
     virDrvDomainSnapshotHasMetadata     domainSnapshotHasMetadata;
     virDrvDomainRevertToSnapshot        domainRevertToSnapshot;
     virDrvDomainSnapshotDelete          domainSnapshotDelete;
-    virDrvDomainQemuMonitorCommand      qemuDomainMonitorCommand;
+    virDrvDomainQemuSupportCommand      qemuDomainMonitorCommand;
     virDrvDomainQemuAttach              qemuDomainAttach;
     virDrvDomainOpenConsole             domainOpenConsole;
     virDrvDomainOpenGraphics            domainOpenGraphics;
@@ -1041,6 +1041,7 @@ struct _virDriver {
     virDrvDomainGetDiskErrors           domainGetDiskErrors;
     virDrvDomainSetMetadata             domainSetMetadata;
     virDrvDomainGetMetadata             domainGetMetadata;
+    virDrvDomainQemuSupportCommand      qemuDomainQemuAgentCommand;
 };
 
 typedef int
diff -uNrp libvirt-0.9.13.orig/src/libvirt-qemu.c libvirt-0.9.13/src/libvirt-qemu.c
--- libvirt-0.9.13.orig/src/libvirt-qemu.c	2012-05-31 23:23:22.000000000 +0900
+++ libvirt-0.9.13/src/libvirt-qemu.c	2012-07-06 09:18:12.497454257 +0900
@@ -185,3 +185,52 @@ error:
     virDispatchError(conn);
     return NULL;
 }
+
+/**
+ * virDomainQemuAgentCommand:
+ * @domain: a domain object
+ * @cmd: the guest agent command string
+ * @result: a string returned by @cmd
+ * @flags: execution flags
+ *
+ * Execution Guest Agent Command
+ *
+ * Returns 0 if succeeded, -1 in failing.
+ */
+int
+virDomainQemuAgentCommand(virDomainPtr domain,
+                          const char *cmd,
+                          char **result,
+                          unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DEBUG("domain=%p, cmd=%s, result=%p, flags=%x",
+              domain, cmd, result, flags);
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        virDispatchError(NULL);
+        return -1;
+    }
+
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(result, error);
+
+    if (conn->driver->qemuDomainQemuAgentCommand) {
+        int ret;
+        ret = conn->driver->qemuDomainQemuAgentCommand(domain, cmd, result,
+                                                       flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virDispatchError(domain->conn);
+    return -1;
+}
diff -uNrp libvirt-0.9.13.orig/src/libvirt_qemu.syms libvirt-0.9.13/src/libvirt_qemu.syms
--- libvirt-0.9.13.orig/src/libvirt_qemu.syms	2011-07-14 12:00:39.000000000 +0900
+++ libvirt-0.9.13/src/libvirt_qemu.syms	2012-07-06 09:18:12.498454377 +0900
@@ -19,3 +19,8 @@ LIBVIRT_QEMU_0.9.4 {
     global:
         virDomainQemuAttach;
 } LIBVIRT_QEMU_0.8.3;
+
+LIBVIRT_QEMU_0.9.14 {
+    global:
+        virDomainQemuAgentCommand;
+} LIBVIRT_QEMU_0.9.4;
diff -uNrp libvirt-0.9.13.orig/src/qemu/qemu_agent.c libvirt-0.9.13/src/qemu/qemu_agent.c
--- libvirt-0.9.13.orig/src/qemu/qemu_agent.c	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/qemu/qemu_agent.c	2012-07-06 09:18:12.498454377 +0900
@@ -1410,3 +1410,29 @@ qemuAgentSuspend(qemuAgentPtr mon,
     virJSONValueFree(reply);
     return ret;
 }
+
+int qemuAgentQemuAgentCommand(qemuAgentPtr mon,
+                              const char *cmd_str,
+                              char **result)
+{
+    int ret = -1;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+
+    cmd = virJSONValueFromString(cmd_str);
+    if (!cmd)
+        return ret;
+
+    ret = qemuAgentCommand(mon, cmd, &reply);
+
+    if (ret == 0) {
+        ret = qemuAgentCheckError(cmd, reply);
+        *result = virJSONValueToString(reply);
+    } else {
+        *result = NULL;
+    }
+
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
diff -uNrp libvirt-0.9.13.orig/src/qemu/qemu_agent.h libvirt-0.9.13/src/qemu/qemu_agent.h
--- libvirt-0.9.13.orig/src/qemu/qemu_agent.h	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/qemu/qemu_agent.h	2012-07-06 09:18:12.499545367 +0900
@@ -80,4 +80,8 @@ int qemuAgentFSThaw(qemuAgentPtr mon);
 
 int qemuAgentSuspend(qemuAgentPtr mon,
                      unsigned int target);
+
+int qemuAgentQemuAgentCommand(qemuAgentPtr mon,
+                              const char *cmd,
+                              char **result);
 #endif /* __QEMU_AGENT_H__ */
diff -uNrp libvirt-0.9.13.orig/src/qemu/qemu_driver.c libvirt-0.9.13/src/qemu/qemu_driver.c
--- libvirt-0.9.13.orig/src/qemu/qemu_driver.c	2012-06-27 10:44:39.000000000 +0900
+++ libvirt-0.9.13/src/qemu/qemu_driver.c	2012-07-06 09:18:12.503579712 +0900
@@ -13158,6 +13158,78 @@ qemuListAllDomains(virConnectPtr conn,
     return ret;
 }
 
+static int
+qemuDomainQemuAgentCommand(virDomainPtr domain,
+                           const char *cmd,
+                           char **result,
+                           unsigned int flags)
+{
+    struct qemud_driver *driver = domain->conn->privateData;
+    virDomainObjPtr vm;
+    int ret = -1;
+    qemuDomainObjPrivatePtr priv;
+
+    virCheckFlags(0, -1);
+
+    qemuDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
+    qemuDriverUnlock(driver);
+
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(domain->uuid, uuidstr);
+        qemuReportError(VIR_ERR_NO_DOMAIN,
+                         _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    priv = vm->privateData;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                        "%s", _("domain is not running"));
+        goto cleanup;
+    }
+
+    if (priv->agentError) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("QEMU guest agent is not available due to an error"));
+        goto cleanup;
+    }
+
+    if (!priv->agent) {
+        qemuReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                        _("QEMU guest agent is not configured"));
+        goto cleanup;
+    }
+
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                        "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+    qemuDomainObjEnterAgent(driver, vm);
+    ret = qemuAgentQemuAgentCommand(priv->agent, cmd, result);
+    qemuDomainObjExitAgent(driver, vm);
+
+    VIR_DEBUG ("qemu-agent-command ret: '%d' domain: '%s' string: %s",
+               ret, vm->def->name, *result);
+
+endjob:
+    if (qemuDomainObjEndJob(driver, vm) == 0) {
+        vm = NULL;
+    }
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    return ret;
+}
+
 static virDriver qemuDriver = {
     .no = VIR_DRV_QEMU,
     .name = QEMU_DRIVER_NAME,
@@ -13323,6 +13395,7 @@ static virDriver qemuDriver = {
     .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
     .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
     .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
+    .qemuDomainQemuAgentCommand = qemuDomainQemuAgentCommand, /* 0.9.14 */
 };
 
 
diff -uNrp libvirt-0.9.13.orig/src/qemu_protocol-structs libvirt-0.9.13/src/qemu_protocol-structs
--- libvirt-0.9.13.orig/src/qemu_protocol-structs	2012-03-06 22:59:21.000000000 +0900
+++ libvirt-0.9.13/src/qemu_protocol-structs	2012-07-06 09:18:12.505455079 +0900
@@ -19,7 +19,16 @@ struct qemu_domain_attach_args {
 struct qemu_domain_attach_ret {
         remote_nonnull_domain      dom;
 };
+struct qemu_agent_command_args {
+        remote_nonnull_domain      dom;
+        remote_nonnull_string      cmd;
+        u_int                      flags;
+};
+struct qemu_agent_command_ret {
+        remote_nonnull_string      result;
+};
 enum qemu_procedure {
         QEMU_PROC_MONITOR_COMMAND = 1,
         QEMU_PROC_DOMAIN_ATTACH = 2,
+        QEMU_PROC_AGENT_COMMAND = 3,
 };
diff -uNrp libvirt-0.9.13.orig/src/remote/qemu_protocol.x libvirt-0.9.13/src/remote/qemu_protocol.x
--- libvirt-0.9.13.orig/src/remote/qemu_protocol.x	2012-03-06 22:59:21.000000000 +0900
+++ libvirt-0.9.13/src/remote/qemu_protocol.x	2012-07-06 09:18:12.506618309 +0900
@@ -47,6 +47,16 @@ struct qemu_domain_attach_ret {
     remote_nonnull_domain dom;
 };
 
+struct qemu_agent_command_args {
+    remote_nonnull_domain dom;
+    remote_nonnull_string cmd;
+    u_int flags;
+};
+
+struct qemu_agent_command_ret {
+    remote_nonnull_string result;
+};
+
 /* Define the program number, protocol version and procedure numbers here. */
 const QEMU_PROGRAM = 0x20008087;
 const QEMU_PROTOCOL_VERSION = 1;
@@ -61,5 +71,6 @@ enum qemu_procedure {
      * are some exceptions to this rule, e.g. domainDestroy. Other APIs MAY
      * be marked as high priority. If in doubt, it's safe to choose low. */
     QEMU_PROC_MONITOR_COMMAND = 1, /* skipgen skipgen priority:low */
-    QEMU_PROC_DOMAIN_ATTACH = 2 /* autogen autogen priority:low */
+    QEMU_PROC_DOMAIN_ATTACH = 2, /* autogen autogen priority:low */
+    QEMU_PROC_AGENT_COMMAND = 3 /* skipgen skipgen priority:low */
 };
diff -uNrp libvirt-0.9.13.orig/src/remote/remote_driver.c libvirt-0.9.13/src/remote/remote_driver.c
--- libvirt-0.9.13.orig/src/remote/remote_driver.c	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/remote/remote_driver.c	2012-07-06 09:18:12.508579685 +0900
@@ -5127,6 +5127,44 @@ make_nonnull_domain_snapshot (remote_non
     make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
 }
 
+static int
+remoteQemuDomainQemuAgentCommand (virDomainPtr domain, const char *cmd,
+                                   char **result, unsigned int flags)
+{
+    int rv = -1;
+    qemu_agent_command_args args;
+    qemu_agent_command_ret ret;
+    struct private_data *priv = domain->conn->privateData;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain(&args.dom, domain);
+    args.cmd = (char *)cmd;
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof(ret));
+
+    if (call (domain->conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_AGENT_COMMAND,
+              (xdrproc_t) xdr_qemu_agent_command_args, (char *) &args,
+              (xdrproc_t) xdr_qemu_agent_command_ret, (char *) &ret) == -1)
+        goto done;
+
+    *result = strdup(ret.result);
+    if (*result == NULL) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    rv = 0;
+
+cleanup:
+    xdr_free ((xdrproc_t) xdr_qemu_agent_command_ret, (char *) &ret);
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
 /*----------------------------------------------------------------------*/
 
 unsigned long remoteVersion(void)
@@ -5303,6 +5341,7 @@ static virDriver remote_driver = {
     .domainGetDiskErrors = remoteDomainGetDiskErrors, /* 0.9.10 */
     .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */
     .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */
+    .qemuDomainQemuAgentCommand = remoteQemuDomainQemuAgentCommand, /* 0.9.14 */
 };
 
 static virNetworkDriver network_driver = {
diff -uNrp libvirt-0.9.13.orig/tools/virsh.c libvirt-0.9.13/tools/virsh.c
--- libvirt-0.9.13.orig/tools/virsh.c	2012-07-02 10:45:49.000000000 +0900
+++ libvirt-0.9.13/tools/virsh.c	2012-07-06 09:18:12.514579757 +0900
@@ -18138,6 +18138,68 @@ cleanup:
     return ret;
 }
 
+/*
+ * "qemu-agent-command" command
+ */
+static const vshCmdInfo info_qemu_agent_command[] = {
+    {"help", N_("Qemu Guest Agent Command")},
+    {"desc", N_("Qemu Guest Agent Command")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_qemu_agent_command[] = {
+    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+    {"cmd", VSH_OT_ARGV, VSH_OFLAG_REQ, N_("command")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdQemuAgentCommand(vshControl *ctl, const vshCmd *cmd)
+{
+    virDomainPtr dom = NULL;
+    bool ret = false;
+    char *guest_agent_cmd = NULL;
+    char *result = NULL;
+    unsigned int flags = 0;
+    const vshCmdOpt *opt = NULL;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    bool pad = false;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        goto cleanup;
+
+    dom = vshCommandOptDomain(ctl, cmd, NULL);
+    if (dom == NULL)
+        goto cleanup;
+
+    while ((opt = vshCommandOptArgv(cmd, opt))) {
+        if (pad)
+            virBufferAddChar(&buf, ' ');
+        pad = true;
+        virBufferAdd(&buf, opt->data, -1);
+    }
+    if (virBufferError(&buf)) {
+        vshPrint(ctl, "%s", _("Failed to collect command"));
+        goto cleanup;
+    }
+    guest_agent_cmd = virBufferContentAndReset(&buf);
+
+    if (virDomainQemuAgentCommand(dom, guest_agent_cmd, &result, flags) < 0)
+        goto cleanup;
+
+    printf("%s\n", result);
+
+    ret = true;
+
+cleanup:
+    VIR_FREE(result);
+    VIR_FREE(guest_agent_cmd);
+    if (dom)
+        virDomainFree(dom);
+
+    return ret;
+}
+
 static const vshCmdDef domManagementCmds[] = {
     {"attach-device", cmdAttachDevice, opts_attach_device,
      info_attach_device, 0},
@@ -18447,6 +18509,8 @@ static const vshCmdDef hostAndHypervisor
     {"qemu-attach", cmdQemuAttach, opts_qemu_attach, info_qemu_attach, 0},
     {"qemu-monitor-command", cmdQemuMonitorCommand, opts_qemu_monitor_command,
      info_qemu_monitor_command, 0},
+    {"qemu-agent-command", cmdQemuAgentCommand, opts_qemu_agent_command,
+     info_qemu_agent_command, 0},
     {"sysinfo", cmdSysinfo, NULL, info_sysinfo, 0},
     {"uri", cmdURI, NULL, info_uri, 0},
     {"version", cmdVersion, opts_version, info_version, 0},


More information about the libvir-list mailing list