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

MATSUDA, Daiki matsudadik at intellilink.co.jp
Tue Jun 26 03:42:03 UTC 2012


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 am sorry that attached patch is against libvirt-0.9.13-rc1, because my
network environment can not access via git and header code is not built
with the problem gnulib...

Regards
MATSUDA Daiki

-------------- 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-06-26 11:34:02.058455043 +0900
@@ -3923,6 +3923,46 @@ cleanup:
     return rv;
 }
 
+static int remoteDispatchDomainGuestAgentInfo(virNetServerPtr server ATTRIBUTE_UNUSED,
+                                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
+                                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                                              virNetMessageErrorPtr rerr,
+                                              remote_domain_guest_agent_info_args *args,
+                                              remote_domain_guest_agent_info_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;
+
+    ret->buffer.buffer_len = REMOTE_DOMAIN_GA_INFO_BUFFER_MAX;
+    if (VIR_ALLOC_N (ret->buffer.buffer_val, REMOTE_DOMAIN_GA_INFO_BUFFER_MAX) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virDomainGuestAgentInfo(dom, &(ret->buffer.buffer_val)) < 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-26 11:36:45.846454615 +0900
@@ -12889,6 +12889,28 @@ static int remoteDispatchSupportsFeature
 
 
 
+static int remoteDispatchDomainGuestAgentInfo(
+    virNetServerPtr server,
+    virNetServerClientPtr client,
+    virNetMessagePtr msg,
+    virNetMessageErrorPtr rerr,
+    remote_domain_guest_agent_info_args *args,
+    remote_domain_guest_agent_info_ret *ret);
+static int remoteDispatchDomainGuestAgentInfoHelper(
+    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 remoteDispatchDomainGuestAgentInfo(server, client, msg, rerr, args, ret);
+}
+/* remoteDispatchDomainGuestAgentInfo body has to be implemented manually */
+
+
+
 virNetServerProgramProc remoteProcs[] = {
 { /* Unused 0 */
    NULL,
@@ -15374,5 +15396,14 @@ virNetServerProgramProc remoteProcs[] = 
    true,
    1
 },
+{ /* Method DomainGuestAgentInfo => 276 */
+   remoteDispatchDomainGuestAgentInfoHelper,
+   sizeof(remote_domain_guest_agent_info_args),
+   (xdrproc_t)xdr_remote_guest_agent_info_args,
+   sizeof(remote_domain_guest_agent_info_ret),
+   (xdrproc_t)remote_domain_guest_agent_info_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 16:06:18.000000000 +0900
+++ libvirt-0.9.13/include/libvirt/libvirt.h.in	2012-06-26 11:38:08.694455103 +0900
@@ -4128,6 +4128,11 @@ typedef struct _virTypedParameter virMem
  */
 typedef virMemoryParameter *virMemoryParameterPtr;
 
+/**
+ * Guest Agent Code:
+ */
+int virDomainGuestAgentInfo(virDomainPtr domain, char **buffer);
+
 #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-26 11:38:41.150580134 +0900
@@ -425,6 +425,7 @@ skip_impl = (
     'virDomainGetInterfaceParameters',
     'virDomainGetCPUStats',
     'virDomainGetDiskErrors',
+    'virDomainGuestAgentInfo',
 )
 
 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-26 11:39:18.182492585 +0900
@@ -487,5 +487,10 @@
       <arg name='domain' type='virDomainPtr' info='a domain object'/>
       <arg name='flags' type='unsigned int' info='unused, always pass 0'/>
     </function>
+    <function name='virDomainGuestAgentInfo' file='python'>
+      <info>guestagent-info</info>
+      <arg name='domain' type='virDomainPtr' info='pointer to the domain'/>
+      <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-26 11:40:17.312579756 +0900
@@ -5758,6 +5758,36 @@ cleanup:
     return py_retval;
 }
 
+static PyObject *
+libvirt_virDomainGuestAgentInfo(PyObject *self ATTRIBUTE_UNUSED, PyObject *args)
+{
+    PyObject *py_retval;
+    int c_retval;
+    char *info;
+    virDomainPtr domain;
+    PyObject *pyobj_domain;
+
+    if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainGuestAgentInfo", &pyobj_domain, &info)) {
+#if DEBUG_ERROR
+        printf("%s failed to parse tuple\n", __FUNCTION__);
+#endif
+        return(NULL);
+    }
+    domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+    LIBVIRT_BEGIN_ALLOW_THREADS;
+    c_retval = virDomainGuestAgentInfo(domain, &info);
+    LIBVIRT_END_ALLOW_THREADS;
+    if (c_retval < 0)
+        return VIR_PY_NONE;
+
+    py_retval = PyList_New(1);
+    PyList_SetItem(py_retval, 0, libvirt_constcharPtrWrap(info));
+
+    if (info) free(info);
+    return(py_retval);
+}
+
 /************************************************************************
  *									*
  *			The registration stuff				*
@@ -5865,6 +5895,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 *) "virDomainGuestAgentInfo", libvirt_virDomainGuestAgentInfo, 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-26 11:42:25.618580083 +0900
@@ -860,6 +860,10 @@ typedef char *
                                const char *uri,
                                unsigned int flags);
 
+typedef int
+    (*virDrvDomainGuestAgentInfo)(virDomainPtr dom,
+                                  char **buffer);
+
 /**
  * _virDriver:
  *
@@ -1041,6 +1045,7 @@ struct _virDriver {
     virDrvDomainGetDiskErrors           domainGetDiskErrors;
     virDrvDomainSetMetadata             domainSetMetadata;
     virDrvDomainGetMetadata             domainGetMetadata;
+    virDrvDomainGuestAgentInfo          domainGuestAgentInfo;
 };
 
 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-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/libvirt.c	2012-06-26 11:42:58.093454455 +0900
@@ -18973,3 +18973,38 @@ error:
     virDispatchError(dom->conn);
     return -1;
 }
+
+/**
+ * virDomainGuestAgentInfo:
+ * @domain: a domain object
+ * @buffer: returning Guest Agent information
+ *
+ * Provide a list of Guest Agent's support command.
+ * Returns 0 if succeeded, -1 in failing.
+ */
+int virDomainGuestAgentInfo(virDomainPtr domain, char **buffer)
+{
+    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->domainGuestAgentInfo) {
+        ret = conn->driver->domainGuestAgentInfo(domain, buffer);
+        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-26 11:43:29.939455045 +0900
@@ -542,6 +542,7 @@ LIBVIRT_0.9.13 {
         virDomainSnapshotIsCurrent;
         virDomainSnapshotListAllChildren;
         virDomainSnapshotRef;
+        virDomainGuestAgentInfo;
 } 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-26 11:44:35.332580082 +0900
@@ -1410,3 +1410,74 @@ qemuAgentSuspend(qemuAgentPtr mon,
     virJSONValueFree(reply);
     return ret;
 }
+
+static int qemuMonitorJSONExtractInfo(virJSONValuePtr reply, char **buffer)
+{
+    virJSONValuePtr data, data2;
+    int ret = -1;
+    int i;
+    char *pin = NULL;
+
+    pin = *buffer;
+
+    if (!(data = virJSONValueObjectGet(reply, "return")) ||
+        data->type != VIR_JSON_TYPE_OBJECT) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("guestagent-info reply was missing return data"));
+        goto cleanup;
+    }
+
+    if (!(data2 = virJSONValueObjectGet(data, "version")) ||
+        data2->type != VIR_JSON_TYPE_STRING) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("guestagent-info reply was not complete data(version)"));
+        goto cleanup;
+    }
+    sprintf(pin, "Version: %s\nCommands:", virJSONValueGetString(data2));
+    pin = strchr(pin, '\0');
+
+    if (!(data2 = virJSONValueObjectGet(data, "supported_commands")) ||
+        data2->type != VIR_JSON_TYPE_ARRAY) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("guestagent-info reply was not complete data(commands)"));
+        goto cleanup;
+    }
+
+    data = data2;
+    for (i = 0; i < virJSONValueArraySize(data); i++) {
+        bool value;
+        data2 = virJSONValueArrayGet(data, i);
+        if (!virJSONValueGetBoolean(virJSONValueObjectGet(data2, "enabled"), &value) && value) {
+            sprintf(pin, "\n\t%s", virJSONValueGetString(virJSONValueObjectGet(data2, "name")));
+            pin = strchr(pin, '\0');
+        }
+    }
+
+    ret = 0;
+
+cleanup:
+    return ret;
+}
+
+int qemuAgentInfo(qemuAgentPtr mon, char **buffer)
+{
+    int ret = -1;
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+
+    cmd = qemuAgentMakeCommand("guest-info", NULL);
+    if (!cmd)
+        return ret;
+
+    ret = qemuAgentCommand(mon, cmd, &reply);
+
+    if (ret == 0)
+        ret = qemuAgentCheckError(cmd, reply);
+
+    if (ret == 0)
+        ret = qemuMonitorJSONExtractInfo(reply, buffer);
+
+    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-06-26 11:44:57.044580088 +0900
@@ -80,4 +80,6 @@ int qemuAgentFSThaw(qemuAgentPtr mon);
 
 int qemuAgentSuspend(qemuAgentPtr mon,
                      unsigned int target);
+
+int qemuAgentInfo(qemuAgentPtr mon, char **buffer);
 #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-25 16:06:18.000000000 +0900
+++ libvirt-0.9.13/src/qemu/qemu_driver.c	2012-06-26 11:46:19.600454553 +0900
@@ -13157,6 +13157,59 @@ qemuListAllDomains(virConnectPtr conn,
     return ret;
 }
 
+static int qemuDomainGuestAgentInfo(virDomainPtr dom, char **buffer)
+{
+    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 = qemuAgentInfo(priv->agent, buffer);
+    qemuDomainObjExitAgent(driver, vm);
+
+    VIR_DEBUG ("guestagent-info ret: '%d' domain: '%s' string: %s", ret, vm->def->name, *buffer);
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    return ret;
+}
+
 static virDriver qemuDriver = {
     .no = VIR_DRV_QEMU,
     .name = QEMU_DRIVER_NAME,
@@ -13322,6 +13375,7 @@ static virDriver qemuDriver = {
     .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
     .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
     .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
+    .domainGuestAgentInfo = qemuDomainGuestAgentInfo, /* 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-26 11:47:41.600579693 +0900
@@ -5127,6 +5127,34 @@ make_nonnull_domain_snapshot (remote_non
     make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
 }
 
+static int
+remoteDomainGuestAgentInfo(virDomainPtr domain, char **buffer)
+{
+    int rv = -1;
+    struct private_data *priv = domain->conn->privateData;
+    remote_domain_guest_agent_info_args args;
+    remote_domain_guest_agent_info_ret ret;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain(&args.dom, domain);
+
+    memset (&ret, 0, sizeof ret);
+
+    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GUEST_AGENT_INFO,
+              (xdrproc_t) xdr_remote_domain_guest_agent_info_args, (char *) &args,
+              (xdrproc_t) xdr_remote_domain_guest_agent_info_ret, (char *) &ret) == -1)
+        goto done;
+    *buffer = strdup(ret.buffer.buffer_val);
+    rv = 0;
+
+    VIR_FREE(ret.buffer.buffer_val);
+
+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 */
+    .domainGuestAgentInfo = remoteDomainGuestAgentInfo, /* 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-26 11:50:00.761455124 +0900
@@ -2513,6 +2513,16 @@ struct remote_connect_list_all_domains_r
     unsigned int ret;
 };
 
+const REMOTE_DOMAIN_GA_INFO_BUFFER_MAX = 1024;
+
+struct remote_domain_guest_agent_info_args {
+    remote_nonnull_domain dom;
+};
+
+struct remote_domain_guest_agent_info_ret {
+    opaque buffer<REMOTE_DOMAIN_GA_INFO_BUFFER_MAX>;
+};
+
 
 /*----- 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_GUEST_AGENT_INFO = 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-25 19:07:41.000000000 +0900
+++ libvirt-0.9.13/tools/virsh.c	2012-06-26 11:52:42.751454461 +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
@@ -17947,6 +17948,44 @@ cleanup:
     return ret;
 }
 
+/*
+ * "guest-agent-info" command
+ */
+static const vshCmdInfo info_guest_agent_info[] = {
+    {"help", N_("Guest Agent Info")},
+    {"desc", N_("Guest Agent Info")},
+    {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_guest_agent_info[] = {
+    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+    {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdGuestAgentInfo(vshControl *ctl, const vshCmd *cmd)
+{
+    int ret = -1;
+    virDomainPtr dom;
+    char *info = NULL;
+
+    if (!vshConnectionUsability(ctl, ctl->conn))
+        return false;
+
+    if (!(dom = vshCommandOptDomainBy(ctl, cmd, NULL, VSH_BYNAME|VSH_BYUUID)))
+        return false;
+
+    if ((ret = virDomainGuestAgentInfo(dom, &info)) < 0 || !info) {
+        vshError(ctl, "%s", _("Failed to set guest-agent-info"));
+    } else {
+        vshPrint(ctl, "%s\n", info);
+    }
+
+    if (info) VIR_FREE(info);
+    virDomainFree(dom);
+    return ret < 0 ? false : true;
+}
+
 static const vshCmdDef domManagementCmds[] = {
     {"attach-device", cmdAttachDevice, opts_attach_device,
      info_attach_device, 0},
@@ -18261,6 +18300,11 @@ static const vshCmdDef hostAndHypervisor
     {NULL, NULL, NULL, NULL, 0}
 };
 
+static const vshCmdDef guestagentCmds[] = {
+    {"guest-agent-info", cmdGuestAgentInfo, opts_guest_agent_info, info_guest_agent_info, 0},
+    {NULL, NULL, NULL, NULL, 0}
+};
+
 static const vshCmdGrp cmdGroups[] = {
     {VSH_CMD_GRP_DOM_MANAGEMENT, "domain", domManagementCmds},
     {VSH_CMD_GRP_DOM_MONITORING, "monitor", domMonitoringCmds},
@@ -18273,6 +18317,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}
 };


More information about the libvir-list mailing list