[libvirt] [PATCH 3/5] add virDomainQemuAgentCommand() to qemu driver and remote driver

MATSUDA, Daiki matsudadik at intellilink.co.jp
Wed Aug 8 00:05:02 UTC 2012


    Add virDomainQemuAgentCommand() to qemu driver and remote driver
    to support qemuAgentCommand().

 daemon/remote.c                |   35 ++++++++++++++++++++
 include/libvirt/libvirt-qemu.h |    3 +
 src/driver.h                   |    6 +++
 src/libvirt-qemu.c             |   58 +++++++++++++++++++++++++++++++++
 src/libvirt_qemu.syms          |    5 ++
 src/qemu/qemu_driver.c         |   71 +++++++++++++++++++++++++++++++++++++++++
 src/qemu_protocol-structs      |   10 +++++
 src/remote/qemu_protocol.x     |   14 +++++++-
 src/remote/remote_driver.c     |   41 +++++++++++++++++++++++
 9 files changed, 242 insertions(+), 1 deletion(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 832307e..4fd5c9b 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -3948,6 +3948,41 @@ 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->timeout, 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 --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h
index ffc5ae5..aed1259 100644
--- a/include/libvirt/libvirt-qemu.h
+++ b/include/libvirt/libvirt-qemu.h
@@ -49,6 +49,9 @@ typedef enum {
     VIR_DOMAIN_QEMU_AGENT_COMMAND_NOWAIT = 0,
 } virDomainQemuAgentCommandTimeoutFlags;

+int virDomainQemuAgentCommand(virDomainPtr domain, const char *cmd,
+                              char **result, int timeout, unsigned int flags);
+
 # ifdef __cplusplus
 }
 # endif
diff --git a/src/driver.h b/src/driver.h
index aab9766..c368273 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -689,6 +689,11 @@ typedef int
     (*virDrvDomainQemuMonitorCommand)(virDomainPtr domain, const char *cmd,
                                       char **result, unsigned int flags);

+typedef int
+    (*virDrvDomainQemuAgentCommand)(virDomainPtr domain, const char *cmd,
+                                    char **result, int timeout,
+                                    unsigned int flags);
+
 /* Choice of unsigned int rather than pid_t is intentional.  */
 typedef virDomainPtr
     (*virDrvDomainQemuAttach)(virConnectPtr conn,
@@ -1048,6 +1053,7 @@ struct _virDriver {
     virDrvDomainGetDiskErrors           domainGetDiskErrors;
     virDrvDomainSetMetadata             domainSetMetadata;
     virDrvDomainGetMetadata             domainGetMetadata;
+    virDrvDomainQemuAgentCommand        qemuDomainQemuAgentCommand;
 };

 typedef int
diff --git a/src/libvirt-qemu.c b/src/libvirt-qemu.c
index 78480bb..0e12425 100644
--- a/src/libvirt-qemu.c
+++ b/src/libvirt-qemu.c
@@ -185,3 +185,61 @@ error:
     virDispatchError(conn);
     return NULL;
 }
+
+/**
+ * virDomainQemuAgentCommand:
+ * @domain: a domain object
+ * @cmd: the guest agent command string
+ * @result: a string returned by @cmd
+ * @timeout: timeout seconds
+ * @flags: execution flags
+ *
+ * Execution Guest Agent Command
+ *
+ * Issue @cmd to the guest agent running in @domain.
+ * If @result is NULL, then don't wait for a result (and @timeout
+ * must be 0).  Otherwise, wait for @timeout seconds for a
+ * successful result to be populated into *@result, with
+ * VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK (-1) meaning to block
+ * forever waiting for a result.
+ *
+ * Returns 0 if succeeded, -1 in failing.
+ */
+int
+virDomainQemuAgentCommand(virDomainPtr domain,
+                          const char *cmd,
+                          char **result,
+                          int timeout,
+                          unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DEBUG("domain=%p, cmd=%s, result=%p, timeout=%d, flags=%x",
+              domain, cmd, result, timeout, 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,
+                                                       timeout, 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 --git a/src/libvirt_qemu.syms b/src/libvirt_qemu.syms
index 8447730..f968d91 100644
--- a/src/libvirt_qemu.syms
+++ b/src/libvirt_qemu.syms
@@ -19,3 +19,8 @@ LIBVIRT_QEMU_0.9.4 {
     global:
         virDomainQemuAttach;
 } LIBVIRT_QEMU_0.8.3;
+
+LIBVIRT_QEMU_0.10.0 {
+    global:
+        virDomainQemuAgentCommand;
+} LIBVIRT_QEMU_0.9.4;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index dee1268..750577e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -13204,6 +13204,76 @@ qemuListAllDomains(virConnectPtr conn,
     return ret;
 }

+static int
+qemuDomainQemuAgentCommand(virDomainPtr domain,
+                           const char *cmd,
+                           char **result,
+                           int timeout,
+                           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, timeout);
+    qemuDomainObjExitAgent(driver, vm);
+
+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,
@@ -13369,6 +13439,7 @@ static virDriver qemuDriver = {
     .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
     .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
     .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
+    .qemuDomainQemuAgentCommand = qemuDomainQemuAgentCommand, /* 0.10.0 */
 };


diff --git a/src/qemu_protocol-structs b/src/qemu_protocol-structs
index 67968eb..624fa7b 100644
--- a/src/qemu_protocol-structs
+++ b/src/qemu_protocol-structs
@@ -19,7 +19,17 @@ 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;
+        int                        timeout;
+        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 --git a/src/remote/qemu_protocol.x b/src/remote/qemu_protocol.x
index c06339c..67c6493 100644
--- a/src/remote/qemu_protocol.x
+++ b/src/remote/qemu_protocol.x
@@ -47,6 +47,17 @@ struct qemu_domain_attach_ret {
     remote_nonnull_domain dom;
 };

+struct qemu_agent_command_args {
+    remote_nonnull_domain dom;
+    remote_nonnull_string cmd;
+    int timeout;
+    unsigned 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 +72,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 --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 353a153..6f27f59 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -5191,6 +5191,46 @@ make_nonnull_domain_snapshot (remote_nonnull_domain_snapshot *snapshot_dst, virD
     make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
 }

+static int
+remoteQemuDomainQemuAgentCommand (virDomainPtr domain, const char *cmd,
+                                  char **result, int timeout,
+                                  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.timeout = timeout;
+    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)
@@ -5368,6 +5408,7 @@ static virDriver remote_driver = {
     .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */
     .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */
     .domainGetHostname = remoteDomainGetHostname, /* 0.10.0 */
+    .qemuDomainQemuAgentCommand = remoteQemuDomainQemuAgentCommand, /* 0.10.0 */
 };

 static virNetworkDriver network_driver = {




More information about the libvir-list mailing list