[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [libvirt] [PATCH] qemu_agent: support guest-info command



Daniel

Thank you for your comment. And I rewrite the patch with
    int virDomainQemuAgentCommand(virDomainPtr domain, const char *cmd,
                                  char **result, unsigned int flags);
that you suggested.

The attached patch is against libvirt-0.9.13-rc2

virsh # qemu-agent-command RHEL58_64 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"}]}}

On Tue, Jun 26, 2012 at 12:42:03PM +0900, MATSUDA, Daiki wrote:
Currently, libvirt qemu agent supports some QEMU Guest Agent's commands
or use them. But they are not adapted to communication test to the
Domain OS.

So, QEMU Guest Agent provide 'guest-info' command to display its version
and their commands. And I wrote the codes for supporting it.

virsh # guest-agent-info RHEL62_32
Version: 1.1.0
Commands:
         guest-network-get-interfaces
         guest-suspend-hybrid
         guest-suspend-ram
         guest-suspend-disk
         guest-fsfreeze-thaw
         guest-fsfreeze-freeze
         guest-fsfreeze-status
         guest-file-flush
         guest-file-seek
         guest-file-write
         guest-file-read
         guest-file-close
         guest-file-open
         guest-shutdown
         guest-info
         guest-ping
         guest-sync
         guest-sync-delimited

I don't really think that this kind of API is relevant for the
libvirt public API. Individual agent commands are wired up to
specific libvirt public APIs as required. There is no compelling
reason why an end user needs to know what agent commands are
present.

I would, however, support the introduction of an API

   int virDomainQemuAgentCommand(virDomainPtr domain, const char *cmd,
                                 char **result, unsigned int flags);

and virsh command 'qemu-agent-command' as part of libvirt-qemu.h and
libvirt-qemu.so. Basically an equivalent of the existing QEMU specific
API virDomainQemuMonitorCommand(), but talking to the agent instead of
the monitor

Regards,
Daniel



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-06-29 12:50:03.752806682 +0900
@@ -3923,6 +3923,42 @@ cleanup:
     return rv;
 }
 
+
+static int
+remoteDispatchDomainQemuAgentCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                     virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                     virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                                     virNetMessageErrorPtr rerr,
+                                     remote_domain_qemu_agent_command_args *args,
+                                     remote_domain_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) {
+        virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("Guest Agent Error"));
+        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/daemon/remote_dispatch.h libvirt-0.9.13/daemon/remote_dispatch.h
--- libvirt-0.9.13.orig/daemon/remote_dispatch.h	2012-06-25 19:48:08.000000000 +0900
+++ libvirt-0.9.13/daemon/remote_dispatch.h	2012-06-29 10:21:21.460454579 +0900
@@ -12889,6 +12889,28 @@ static int remoteDispatchSupportsFeature
 
 
 
+static int remoteDispatchDomainQemuAgentCommand(
+    virNetServerPtr server,
+    virNetServerClientPtr client,
+    virNetMessagePtr msg,
+    virNetMessageErrorPtr rerr,
+    remote_domain_qemu_agent_command_args *args,
+    remote_domain_qemu_agent_command_ret *ret);
+static int remoteDispatchDomainQemuAgentCommandHelper(
+    virNetServerPtr server,
+    virNetServerClientPtr client,
+    virNetMessagePtr msg,
+    virNetMessageErrorPtr rerr,
+    void *args,
+    void *ret)
+{
+  VIR_DEBUG("server=%p client=%p msg=%p rerr=%p args=%p ret=%p", server, client, msg, rerr, args, ret);
+  return remoteDispatchDomainQemuAgentCommand(server, client, msg, rerr, args, ret);
+}
+/* remoteDispatchDomainQemuAgentCommand body has to be implemented manually */
+
+
+
 virNetServerProgramProc remoteProcs[] = {
 { /* Unused 0 */
    NULL,
@@ -15374,5 +15396,14 @@ virNetServerProgramProc remoteProcs[] = 
    true,
    1
 },
+{ /* Method DomainQemuAgentCommand => 276 */
+   remoteDispatchDomainQemuAgentCommandHelper,
+   sizeof(remote_domain_qemu_agent_command_args),
+   (xdrproc_t)xdr_remote_qemu_agent_command_args,
+   sizeof(remote_domain_qemu_agent_command_ret),
+   (xdrproc_t)remote_domain_qemu_agent_command_ret,
+   true,
+   0
+},
 };
 size_t remoteNProcs = ARRAY_CARDINALITY(remoteProcs);
diff -uNrp libvirt-0.9.13.orig/include/libvirt/libvirt.h.in libvirt-0.9.13/include/libvirt/libvirt.h.in
--- libvirt-0.9.13.orig/include/libvirt/libvirt.h.in	2012-06-25 21:42:32.000000000 +0900
+++ libvirt-0.9.13/include/libvirt/libvirt.h.in	2012-06-29 11:22:38.113455058 +0900
@@ -4132,6 +4132,9 @@ typedef struct _virTypedParameter virMem
  */
 typedef virMemoryParameter *virMemoryParameterPtr;
 
+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-06-29 09:06:42.661580125 +0900
@@ -425,6 +425,7 @@ skip_impl = (
     'virDomainGetInterfaceParameters',
     'virDomainGetCPUStats',
     'virDomainGetDiskErrors',
+    'virDomainQemuAgentCommand',
 )
 
 qemu_skip_impl = (
diff -uNrp libvirt-0.9.13.orig/python/libvirt-override-api.xml libvirt-0.9.13/python/libvirt-override-api.xml
--- libvirt-0.9.13.orig/python/libvirt-override-api.xml	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/python/libvirt-override-api.xml	2012-06-29 09:18:20.454455098 +0900
@@ -487,5 +487,13 @@
       <arg name='domain' type='virDomainPtr' info='a domain object'/>
       <arg name='flags' type='unsigned int' info='unused, always pass 0'/>
     </function>
+    <function name='virDomainQemuAgentCommand' file='python'>
+      <info>qemu-agent-command</info>
+      <arg name='domain' type='virDomainPtr' info='pointer to the domain'/>
+      <arg name='cmd' type='const char *' info='guest agent command on domain'/>
+      <arg name='result' type='char **' info='returning strings from domain'/>
+      <arg name='flags' type='unsinged int' info='execution flags'/>
+      <return type='int' info='more than 0 if successed, negative on failure.'/>
+    </function>
   </symbols>
 </api>
diff -uNrp libvirt-0.9.13.orig/python/libvirt-override.c libvirt-0.9.13/python/libvirt-override.c
--- libvirt-0.9.13.orig/python/libvirt-override.c	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/python/libvirt-override.c	2012-06-29 13:03:12.362579580 +0900
@@ -5758,6 +5758,34 @@ cleanup:
     return py_retval;
 }
 
+static PyObject *
+libvirt_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				*
@@ -5865,6 +5893,7 @@ static PyMethodDef libvirtMethods[] = {
     {(char *) "virDomainBlockPeek", libvirt_virDomainBlockPeek, METH_VARARGS, NULL},
     {(char *) "virDomainMemoryPeek", libvirt_virDomainMemoryPeek, METH_VARARGS, NULL},
     {(char *) "virDomainGetDiskErrors", libvirt_virDomainGetDiskErrors, METH_VARARGS, NULL},
+    {(char *) "virDomainQemuAgentCommand", libvirt_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-06-29 10:17:17.486454901 +0900
@@ -860,6 +860,10 @@ typedef char *
                                const char *uri,
                                unsigned int flags);
 
+typedef int
+    (*virDrvDomainQemuAgentCommand)(virDomainPtr domain, const char *cmd,
+                                    char **result, unsigned int flags);
+
 /**
  * _virDriver:
  *
@@ -1041,6 +1045,7 @@ struct _virDriver {
     virDrvDomainGetDiskErrors           domainGetDiskErrors;
     virDrvDomainSetMetadata             domainSetMetadata;
     virDrvDomainGetMetadata             domainGetMetadata;
+    virDrvDomainQemuAgentCommand        domainQemuAgentCommand;
 };
 
 typedef int
diff -uNrp libvirt-0.9.13.orig/src/libvirt.c libvirt-0.9.13/src/libvirt.c
--- libvirt-0.9.13.orig/src/libvirt.c	2012-06-28 12:05:04.000000000 +0900
+++ libvirt-0.9.13/src/libvirt.c	2012-06-29 12:51:51.336454508 +0900
@@ -18973,3 +18973,44 @@ error:
     virDispatchError(dom->conn);
     return -1;
 }
+
+/**
+ * virDomainQemuAgentCommand:
+ * @domain: a domain object
+ * @cmd: execution command on domain's guest agent
+ * @result: returning strings
+ * @flags: execution flags
+ *
+ * Provide a list of Guest Agent's support command.
+ * Returns 0 if succeeded, -1 in failing.
+ */
+int
+virDomainQemuAgentCommand(virDomainPtr domain,
+                          const char *cmd,
+                          char **result,
+                          unsigned int flags)
+{
+    virConnectPtr conn;
+    int ret = -1;
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return ret;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainQemuAgentCommand) {
+        ret = conn->driver->domainQemuAgentCommand(domain, cmd, result, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virDispatchError(domain->conn);
+    return ret;
+}
diff -uNrp libvirt-0.9.13.orig/src/libvirt_public.syms libvirt-0.9.13/src/libvirt_public.syms
--- libvirt-0.9.13.orig/src/libvirt_public.syms	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/libvirt_public.syms	2012-06-29 09:07:00.357580129 +0900
@@ -542,6 +542,7 @@ LIBVIRT_0.9.13 {
         virDomainSnapshotIsCurrent;
         virDomainSnapshotListAllChildren;
         virDomainSnapshotRef;
+        virDomainQemuAgentCommand;
 } LIBVIRT_0.9.11;
 
 # .... define new API here using predicted next version number ....
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-06-29 09:46:46.833456703 +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;
+
+    ret = qemuAgentCommand(mon, jcmd, &reply);
+
+    if (ret == 0) {
+        ret = qemuAgentCheckError(jcmd, reply);
+        *result = virJSONValueToString(reply);
+    } else {
+        *result = NULL;
+    }
+
+    virJSONValueFree(jcmd);
+    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-06-29 09:45:16.203455093 +0900
@@ -80,4 +80,8 @@ int qemuAgentFSThaw(qemuAgentPtr mon);
 
 int qemuAgentSuspend(qemuAgentPtr mon,
                      unsigned int target);
+
+int qemuAgentGuestAgentCommand(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-06-29 10:13:23.333579412 +0900
@@ -13158,6 +13158,63 @@ qemuListAllDomains(virConnectPtr conn,
     return ret;
 }
 
+static int
+qemuDomainQemuAgentCommand(virDomainPtr dom,
+                           const char *cmd,
+                           char **result,
+                           unsigned int flags ATTRIBUTE_UNUSED)
+{
+    int ret = -1;
+
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm;
+    qemuDomainObjPrivatePtr priv;
+
+    qemuDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    qemuDriverUnlock(driver);
+
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        qemuReportError(VIR_ERR_NO_DOMAIN,
+                         _("no domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    if (!virDomainObjIsActive(vm)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                        "%s", _("domain is not running"));
+        goto cleanup;
+    }
+
+    priv = vm->privateData;
+
+    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;
+    }
+
+    qemuDomainObjEnterAgent(driver, vm);
+    ret = qemuAgentGuestAgentCommand(priv->agent, cmd, result);
+    qemuDomainObjExitAgent(driver, vm);
+
+    VIR_DEBUG ("qemu-agent-command ret: '%d' domain: '%s' string: %s", ret, vm->def->name, *result);
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    return ret;
+}
+
 static virDriver qemuDriver = {
     .no = VIR_DRV_QEMU,
     .name = QEMU_DRIVER_NAME,
@@ -13323,6 +13379,7 @@ static virDriver qemuDriver = {
     .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
     .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
     .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
+    .domainQemuAgentCommand = qemuDomainQemuAgentCommand, /* 0.9.13 */
 };
 
 
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-06-29 12:57:47.771455113 +0900
@@ -5127,6 +5127,41 @@ make_nonnull_domain_snapshot (remote_non
     make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
 }
 
+static int
+remoteDomainQemuAgentCommand(virDomainPtr domain, const char *cmd, char **result, unsigned int flags)
+{
+    int rv = -1;
+    struct private_data *priv = domain->conn->privateData;
+    remote_domain_qemu_agent_command_args args;
+    remote_domain_qemu_agent_command_ret ret;
+
+    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, 0, REMOTE_PROC_DOMAIN_QEMU_AGENT_COMMAND,
+              (xdrproc_t) xdr_remote_domain_qemu_agent_command_args, (char *) &args,
+              (xdrproc_t) xdr_remote_domain_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_remote_domain_qemu_agent_command_ret, (char *) &ret);
+
+done:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
 /*----------------------------------------------------------------------*/
 
 unsigned long remoteVersion(void)
@@ -5303,6 +5331,7 @@ static virDriver remote_driver = {
     .domainGetDiskErrors = remoteDomainGetDiskErrors, /* 0.9.10 */
     .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */
     .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */
+    .domainQemuAgentCommand = remoteDomainQemuAgentCommand, /* 0.9.13 */
 };
 
 static virNetworkDriver network_driver = {
diff -uNrp libvirt-0.9.13.orig/src/remote/remote_protocol.x libvirt-0.9.13/src/remote/remote_protocol.x
--- libvirt-0.9.13.orig/src/remote/remote_protocol.x	2012-06-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/remote/remote_protocol.x	2012-06-29 12:55:43.752580212 +0900
@@ -2513,6 +2513,16 @@ struct remote_connect_list_all_domains_r
     unsigned int ret;
 };
 
+struct remote_domain_qemu_agent_command_args {
+    remote_nonnull_domain dom;
+    remote_nonnull_string cmd;
+    u_int flags;
+};
+
+struct remote_domain_qemu_agent_command_ret {
+    remote_nonnull_string result;
+};
+
 
 /*----- Protocol. -----*/
 
@@ -2838,7 +2848,8 @@ enum remote_procedure {
     REMOTE_PROC_DOMAIN_SNAPSHOT_HAS_METADATA = 272, /* autogen autogen */
     REMOTE_PROC_CONNECT_LIST_ALL_DOMAINS = 273, /* skipgen skipgen priority:high */
     REMOTE_PROC_DOMAIN_LIST_ALL_SNAPSHOTS = 274, /* skipgen skipgen priority:high */
-    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275 /* skipgen skipgen priority:high */
+    REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_ALL_CHILDREN = 275, /* skipgen skipgen priority:high */
+    REMOTE_PROC_DOMAIN_QEMU_AGENT_COMMAND = 276 /* skipgen skipgen */
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
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-06-28 12:05:04.000000000 +0900
+++ libvirt-0.9.13/tools/virsh.c	2012-06-29 11:12:55.900579561 +0900
@@ -160,6 +160,7 @@ typedef enum {
 #define VSH_CMD_GRP_SNAPSHOT         "Snapshot"
 #define VSH_CMD_GRP_HOST_AND_HV      "Host and Hypervisor"
 #define VSH_CMD_GRP_VIRSH            "Virsh itself"
+#define VSH_CMD_GRP_GUESTAGENT       "QEMU Guest Agent"
 
 /*
  * Command Option Flags
@@ -18138,6 +18139,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},
@@ -18453,6 +18516,11 @@ static const vshCmdDef hostAndHypervisor
     {NULL, NULL, NULL, NULL, 0}
 };
 
+static const vshCmdDef guestagentCmds[] = {
+    {"qemu-agent-command", cmdQemuAgentCommand, opts_qemu_agent_command, info_qemu_agent_command, 0},
+    {NULL, NULL, NULL, NULL, 0}
+};
+
 static const vshCmdGrp cmdGroups[] = {
     {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds},
     {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds},
@@ -18465,6 +18533,7 @@ static const vshCmdGrp cmdGroups[] = {
     {VSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds},
     {VSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds},
     {VSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds},
+    {VSH_CMD_GRP_GUESTAGENT, "guestagent", guestagentCmds},
     {VSH_CMD_GRP_VIRSH, "virsh", virshCmds},
     {NULL, NULL, NULL}
 };

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]