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 @@
+
+ Send a Guest Agent command to domain
+
+
+
+
+
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},