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

Michal Privoznik mprivozn at redhat.com
Wed Jul 4 13:30:58 UTC 2012


[I am pasting your patch here so I can point out some nits]

On 03.07.2012 02:56, MATSUDA, Daiki wrote:
> 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-02 10:02:54.400454470 +0900
> @@ -3923,6 +3923,42 @@ cleanup:
>      return rv;
>  }
>  
> +
> +static int
> +qemuDispatchGuestAgentCommand(virNetServerPtr server ATTRIBUTE_UNUSED,
> +                              virNetServerClientPtr client ATTRIBUTE_UNUSED,
> +                              virNetMessagePtr msg ATTRIBUTE_UNUSED,
> +                              virNetMessageErrorPtr rerr,
> +                              qemu_guest_agent_command_args *args,
> +                              qemu_guest_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 (virDomainGuestAgentCommand(dom, args->cmd, &ret->result, args->flags) <0) {
> +        virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("Guest Agent Error"));

This is wrong as it overwrites any error reported by virDomainGuestAgentCommand.
Moreover, there should be space between '<' and '0' in if statement which is btw longer than 80 characters.

> +        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/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-02 10:02:54.401454277 +0900
> @@ -32,6 +32,9 @@ virDomainPtr virDomainQemuAttach(virConn
>                                   unsigned int pid_value,
>                                   unsigned int flags);
>  
> +int virDomainGuestAgentCommand(virDomainPtr domain, const char *cmd,
> +                               char **result, unsigned int flags);
> +

Do we really want this name? I mean in case of monitor we are qemu specific. So I think this should be either virDomainQemuAgentCommand or virDomainQemuGuestAgentCommand. We expose this as qemu-agent-command after all!

>  # 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-02 10:03:01.616454719 +0900
> @@ -429,6 +429,7 @@ skip_impl = (
>  
>  qemu_skip_impl = (
>      'virDomainQemuMonitorCommand',
> +    'virDomainGuestAgentCommand',
>  )
>  
>  
> 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-02 10:02:54.403454795 +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='virDomainGuestAgentCommand' 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-02 10:02:54.404454019 +0900
> @@ -82,6 +82,35 @@ libvirt_qemu_virDomainQemuMonitorCommand
>      return py_retval;
>  }
>  
> +static PyObject *
> +libvirt_qemu_virDomainGuestAgentCommand(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:virDomainGuestAgentCommand",
> +                          &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 = virDomainGuestAgentCommand(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 +119,7 @@ libvirt_qemu_virDomainQemuMonitorCommand
>  static PyMethodDef libvirtQemuMethods[] = {
>  #include "libvirt-qemu-export.c"
>      {(char *) "virDomainQemuMonitorCommand", libvirt_qemu_virDomainQemuMonitorCommand, METH_VARARGS, NULL},
> +    {(char *) "virDomainGuestAgentCommand", libvirt_qemu_virDomainGuestAgentCommand, 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-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.

>  
>  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-02 10:02:54.407454078 +0900
> @@ -185,3 +185,48 @@ error:
>      virDispatchError(conn);
>      return NULL;
>  }
> +
> +/**
> + * virDomainGuestAgentCommand:
> + * @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
> +virDomainGuestAgentCommand(virDomainPtr domain,
> +                          const char *cmd,
> +                          char **result,
> +                          unsigned int flags)
> +{
> +    virConnectPtr conn;
> +

VIR_DEBUG() or equivalent is missing here. Each API must log arguments it was called with.

> +    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->qemuDomainGuestAgentCommand) {
> +        int ret;
> +        ret = conn->driver->qemuDomainGuestAgentCommand(domain, cmd, result, flags);

Long line.

> +        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-02 10:02:54.407454078 +0900
> @@ -19,3 +19,8 @@ LIBVIRT_QEMU_0.9.4 {
>      global:
>          virDomainQemuAttach;
>  } LIBVIRT_QEMU_0.8.3;
> +
> +LIBVIRT_QEMU_0.9.14 {
> +    global:
> +        virDomainGuestAgentCommand;
> +} 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-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.

> +
> +    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-07-02 10:02:54.409454807 +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-07-02 10:02:54.419455949 +0900
> @@ -13158,6 +13158,78 @@ qemuListAllDomains(virConnectPtr conn,
>      return ret;
>  }
>  
> +static int
> +qemuDomainGuestAgentCommand(virDomainPtr domain,
> +                            const char *cmd,
> +                            char **result,
> +                            unsigned int flags ATTRIBUTE_UNUSED)
> +{
> +    struct qemud_driver *driver = domain->conn->privateData;
> +    virDomainObjPtr vm;
> +    int ret = -1;
> +    qemuDomainObjPrivatePtr priv;

virCheckFlags(0, -1); what means flags can't be ATTRIBUTE_UNUSED.

> +
> +    qemuDriverLock(driver);
> +    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
> +
> +    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;
> +    }

Do we really want to hold driver locked through whole API?

> +
> +    if (!virDomainObjIsActive(vm)) {
> +        qemuReportError(VIR_ERR_OPERATION_INVALID,
> +                        "%s", _("domain is not running"));
> +        goto cleanup;
> +    }
> +
> +    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
> +        goto cleanup;
> +
> +    if (!virDomainObjIsActive(vm)) {
> +        qemuReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                        _("domain is not running"));
> +        goto endjob;
> +    }
> +
> +    priv = vm->privateData;
> +
> +    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
> +
> +    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);
> +
> +endjob:
> +    if (qemuDomainObjEndJob(driver, vm) == 0) {
> +        vm = NULL;
> +    }
> +
> +cleanup:
> +    if (vm)
> +        virDomainObjUnlock(vm);
> +    qemuDriverUnlock(driver);
> +    return ret;
> +}
> +
>  static virDriver qemuDriver = {
>      .no = VIR_DRV_QEMU,
>      .name = QEMU_DRIVER_NAME,
> @@ -13323,6 +13380,7 @@ static virDriver qemuDriver = {
>      .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
>      .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
>      .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
> +    .qemuDomainGuestAgentCommand = qemuDomainGuestAgentCommand, /* 0.9.14 */
>  };
>  
>  
> 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-02 10:02:54.421454763 +0900
> @@ -47,6 +47,16 @@ struct qemu_domain_attach_ret {
>      remote_nonnull_domain dom;
>  };
>  
> +struct qemu_guest_agent_command_args {
> +    remote_nonnull_domain dom;
> +    remote_nonnull_string cmd;
> +    u_int flags;
> +};
> +
> +struct qemu_guest_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_GUEST_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-02 10:02:54.425455211 +0900
> @@ -5127,6 +5127,44 @@ make_nonnull_domain_snapshot (remote_non
>      make_nonnull_domain(&snapshot_dst->dom, snapshot_src->domain);
>  }
>  
> +static int
> +remoteQemuDomainGuestAgentCommand (virDomainPtr domain, const char *cmd,
> +                                   char **result, unsigned int flags)
> +{
> +    int rv = -1;
> +    qemu_guest_agent_command_args args;
> +    qemu_guest_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);

We require sizeof to be used as function:
memset(&ret, 0, sizeof(ret));

> +
> +    if (call (domain->conn, priv, REMOTE_CALL_QEMU, QEMU_PROC_GUEST_AGENT_COMMAND,
> +              (xdrproc_t) xdr_qemu_guest_agent_command_args, (char *) &args,
> +              (xdrproc_t) xdr_qemu_guest_agent_command_ret, (char *) &ret) == -1)
> +        goto done;

Again long line, but it's among whole file so I think I can close one eye..

> +
> +    *result = strdup(ret.result);
> +    if (*result == NULL) {
> +        virReportOOMError();
> +        goto cleanup;
> +    }
> +
> +    rv = 0;
> +
> +cleanup:
> +    xdr_free ((xdrproc_t) xdr_qemu_guest_agent_command_ret, (char *) &ret);
> +
> +done:
> +    remoteDriverUnlock(priv);
> +    return rv;
> +}
> +
>  /*----------------------------------------------------------------------*/
>  
>  unsigned long remoteVersion(void)
> @@ -5303,6 +5339,7 @@ static virDriver remote_driver = {
>      .domainGetDiskErrors = remoteDomainGetDiskErrors, /* 0.9.10 */
>      .domainSetMetadata = remoteDomainSetMetadata, /* 0.9.10 */
>      .domainGetMetadata = remoteDomainGetMetadata, /* 0.9.10 */
> +    .qemuDomainGuestAgentCommand = remoteQemuDomainGuestAgentCommand, /* 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-06-28 12:05:04.000000000 +0900
> +++ libvirt-0.9.13/tools/virsh.c	2012-07-02 10:02:54.441454424 +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"

Why this? I mean, qemu-monitor-command is under VSH_CMD_GRP_HOST_AND_HV so I think we should keep things consistent.

>  
>  /*
>   * 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 (virDomainGuestAgentCommand(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}
>


Plus, you need to update src/qemu_protocol-structs as well


For future version, can you please utilize git and git-send-email? It makes review simpler. Thanks.

Michal




More information about the libvir-list mailing list