From 057e855324f71d919a05397701c586a46d06cf37 Mon Sep 17 00:00:00 2001 From: Chris Lalancette Date: Fri, 16 Apr 2010 22:12:45 -0400 Subject: [PATCH] Qemu arbitrary monitor commands. Implement the qemu driver's virDomainQemuMonitorCommand and hook it into the API entry point. Changes since v1: - Rename the (external) qemuMonitorCommand to qemuDomainMonitorCommand - Add virCheckFlags to qemuDomainMonitorCommand Changes since v2: - Drop ATTRIBUTE_UNUSED from the flags Changes since v3: - Add a flag to priv so we only print out monitor command warning once. Note that this has not been plumbed into qemuDomainObjPrivateXMLFormat or qemuDomainObjPrivateXMLParse, which means that if you run a monitor command, restart libvirtd, and then run another monitor command, you may get an an erroneous VIR_INFO. It's a pretty minor matter, and I didn't think it warranted the additional code. - Add BeginJob/EndJob calls around EnterMonitor/ExitMonitor Signed-off-by: Chris Lalancette --- src/qemu/qemu_driver.c | 56 +++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 13 +++++++++ src/qemu/qemu_monitor.h | 2 ++ src/qemu/qemu_monitor_json.c | 28 ++++++++++++++++++ src/qemu/qemu_monitor_json.h | 4 +++ src/qemu/qemu_monitor_text.c | 21 ++++++++++++++ src/qemu/qemu_monitor_text.h | 3 ++ 7 files changed, 126 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index aae4e002cc..875fc42f24 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -121,6 +121,7 @@ struct _qemuDomainObjPrivate { qemuMonitorPtr mon; virDomainChrDefPtr monConfig; int monJSON; + int monitor_warned; int nvcpupids; int *vcpupids; @@ -3716,6 +3717,8 @@ static int qemudStartVMDaemon(virConnectPtr conn, #endif priv->monJSON = 0; + priv->monitor_warned = 0; + if ((ret = virFileDeletePid(driver->stateDir, vm->def->name)) != 0) { virReportSystemError(ret, _("Cannot remove stale PID file for %s"), @@ -12561,6 +12564,57 @@ cleanup: return ret; } +static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd, + char **result, unsigned int flags) +{ + struct qemud_driver *driver = domain->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + qemuDomainObjPrivatePtr priv; + + virCheckFlags(0, -1); + + 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; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (!priv->monitor_warned) { + VIR_INFO("Qemu monitor command '%s' executed; libvirt results may be unpredictable!", + cmd); + priv->monitor_warned = 1; + } + + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) + goto cleanup; + qemuDomainObjEnterMonitorWithDriver(driver, vm); + ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (qemuDomainObjEndJob(vm) == 0) { + vm = NULL; + goto cleanup; + } + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -12660,7 +12714,7 @@ static virDriver qemuDriver = { qemuDomainSnapshotCurrent, /* domainSnapshotCurrent */ qemuDomainRevertToSnapshot, /* domainRevertToSnapshot */ qemuDomainSnapshotDelete, /* domainSnapshotDelete */ - NULL, /* qemuDomainMonitorCommand */ + qemuDomainMonitorCommand, /* qemuDomainMonitorCommand */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index b05032aea6..f1494ff87b 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1918,3 +1918,16 @@ int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name) ret = qemuMonitorTextDeleteSnapshot(mon, name); return ret; } + +int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply) +{ + int ret; + + DEBUG("mon=%p, cmd=%s, reply=%p", mon, cmd, reply); + + if (mon->json) + ret = qemuMonitorJSONArbitraryCommand(mon, cmd, reply); + else + ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply); + return ret; +} diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 459ccb70bd..48f4c20beb 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -389,4 +389,6 @@ int qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name); +int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply); + #endif /* QEMU_MONITOR_H */ diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 4487ff54dd..e8609aa718 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2345,3 +2345,31 @@ int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name) virJSONValueFree(reply); return ret; } + +int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, + const char *cmd_str, + char **reply_str) +{ + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + int ret = -1; + + cmd = virJSONValueFromString(cmd_str); + if (!cmd) + return -1; + + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + *reply_str = virJSONValueToString(reply); + if (!(*reply_str)) + goto cleanup; + + ret = 0; + +cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + + return ret; +} diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 6fa8d83549..94806c1063 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -196,4 +196,8 @@ int qemuMonitorJSONCreateSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorJSONLoadSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name); +int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, + const char *cmd_str, + char **reply_str); + #endif /* QEMU_MONITOR_JSON_H */ diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index 569742a42d..69971a656e 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -2567,3 +2567,24 @@ cleanup: VIR_FREE(reply); return ret; } + +int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, + char **reply) +{ + char *safecmd = NULL; + int ret; + + if (!(safecmd = qemuMonitorEscapeArg(cmd))) { + virReportOOMError(); + return -1; + } + + ret = qemuMonitorCommand(mon, safecmd, reply); + if (ret != 0) + qemuReportError(VIR_ERR_OPERATION_FAILED, + _("failed to run cmd '%s'"), safecmd); + + VIR_FREE(safecmd); + + return ret; +} diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 9926d34723..c017509298 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -194,4 +194,7 @@ int qemuMonitorTextCreateSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorTextLoadSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name); +int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd, + char **reply); + #endif /* QEMU_MONITOR_TEXT_H */