[libvirt] [PATCH 0/4] new APIs/commands for managed core dump

This patch series added new APIs and virsh commands for 'managed core dump' functionality. Existing functionalities are intact. The 'managed core dump' functionality is in line with 'managed save', there can be at most 1 managed core dump per domain. In addition to the generate/check-existence/remove APIs/commands, there's also a download API/command to get the managed core dump of a domain for local use. Currently the new functionality has only been implemented for qemu hypervisor driver. Hong Xiang (4): new public APIs for managed core dump remote driver implementation qemu driver implementation New virsh commands for managed core dump include/libvirt/libvirt.h.in | 13 +++ src/driver.h | 18 ++++ src/libvirt.c | 187 +++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 8 ++ src/qemu/qemu_conf.h | 2 + src/qemu/qemu_driver.c | 176 ++++++++++++++++++++++++++++++++++++- src/remote/remote_driver.c | 4 + src/remote/remote_protocol.x | 31 ++++++- tools/virsh.c | 200 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 636 insertions(+), 3 deletions(-)

Added new public APIs for managed-core-dump. In line with managed-save functionality, there's at most one managed core-dump per domain. New APIs: . virDomainManagedCoreDump . virDomainHasManagedCoreDump . virDomainManagedCoreDumpRemove . virDomainManagedCoreDumpDownload * include/libvirt/libvirt.h.in: API declarations. * src/driver.h: driver data structure extension. * src/libvirt.c: API implementation. * src/libvirt_public.syms: public symbols. Signed-off-by: Hong Xiang <hxiang@linux.vnet.ibm.com> --- include/libvirt/libvirt.h.in | 13 +++ src/driver.h | 18 ++++ src/libvirt.c | 187 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 8 ++ 4 files changed, 226 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 7181f62..2abbbf0 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1168,6 +1168,19 @@ int virDomainCoreDump (virDomainPtr domain, unsigned int flags); /* + * Managed domain core dump + */ +int virDomainManagedCoreDump (virDomainPtr dom, + unsigned int flags); +int virDomainHasManagedCoreDump(virDomainPtr dom, + unsigned int flags); +int virDomainManagedCoreDumpRemove(virDomainPtr dom, + unsigned int flags); +int virDomainManagedCoreDumpDownload(virDomainPtr dom, + virStreamPtr stream, + unsigned int flags); + +/* * Screenshot of current domain console */ char * virDomainScreenshot (virDomainPtr domain, diff --git a/src/driver.h b/src/driver.h index 4c14aaa..25f2edf 100644 --- a/src/driver.h +++ b/src/driver.h @@ -740,6 +740,20 @@ typedef int (*virDrvDomainBlockPull)(virDomainPtr dom, const char *path, unsigned long bandwidth, unsigned int flags); +typedef int + (*virDrvDomainManagedCoreDump)(virDomainPtr domain, unsigned int flags); + +typedef int + (*virDrvDomainHasManagedCoreDump)(virDomainPtr domain, unsigned int flags); + +typedef int + (*virDrvDomainManagedCoreDumpRemove)(virDomainPtr domain, + unsigned int flags); + +typedef int + (*virDrvDomainManagedCoreDumpDownload)(virDomainPtr domain, + virStreamPtr stream, + unsigned int flags); /** * _virDriver: @@ -899,6 +913,10 @@ struct _virDriver { virDrvDomainGetBlockJobInfo domainGetBlockJobInfo; virDrvDomainBlockJobSetSpeed domainBlockJobSetSpeed; virDrvDomainBlockPull domainBlockPull; + virDrvDomainManagedCoreDump domainManagedCoreDump; + virDrvDomainHasManagedCoreDump domainHasManagedCoreDump; + virDrvDomainManagedCoreDumpRemove domainManagedCoreDumpRemove; + virDrvDomainManagedCoreDumpDownload domainManagedCoreDumpDownload; }; typedef int diff --git a/src/libvirt.c b/src/libvirt.c index b0d1e01..b7b17f4 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -17083,3 +17083,190 @@ error: virDispatchError(dom->conn); return -1; } + +/** + * virDomainManagedCoreDump: + * @dom: pointer to the domain + * @flags: bitwise-OR of virDomainCoreDumpFlags + * + * This method differs from virDomainCoreDump only in that caller can not + * control where the generated core dump file is stored, it's determined by + * the driver. + * + * Returns 0 in case of success or -1 in case of failure + */ +int virDomainManagedCoreDump(virDomainPtr dom, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "flags=%x", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(dom)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + conn = dom->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_LIVE)) { + virLibDomainError(VIR_ERR_INVALID_ARG, + _("crash and live flags are mutually exclusive")); + goto error; + } + + if (conn->driver->domainManagedCoreDump) { + int ret; + + ret = conn->driver->domainManagedCoreDump(dom, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** + * virDomainHasManagedCoreDump: + * @dom: pointer to the domain + * @flags: optional flags currently unused + * + * Check if a domain has a managed core dump as created by + * virDomainManagedCoreDump(). + * + * Returns 0 if no core dump is present, 1 if a core dump is present, and + * -1 in case of error + */ +int virDomainHasManagedCoreDump(virDomainPtr dom, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "flags=%x", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(dom)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + conn = dom->conn; + + if (conn->driver->domainHasManagedCoreDump) { + int ret; + + ret = conn->driver->domainHasManagedCoreDump(dom, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** + * virDomainManagedCoreDumpRemove: + * @dom: pointer to the domain + * @flags: optional flags currently unused + * + * Remove managed core dump of this domain. + * + * Returns 0 in case of success, and -1 in case of error + */ +int virDomainManagedCoreDumpRemove(virDomainPtr dom, unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "flags=%x", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(dom)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + conn = dom->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (conn->driver->domainManagedCoreDumpRemove) { + int ret; + + ret = conn->driver->domainManagedCoreDumpRemove(dom, flags); + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} + +/** + * virDomainManagedCoreDumpDownload: + * @dom: pointer to the domain + * @stream: stream to use as output + * @flags: optional flags currently unused + * + * Download managed core dump of this domain. + * + * Returns 0 on success and -1 on failure. + */ +int +virDomainManagedCoreDumpDownload(virDomainPtr dom, + virStreamPtr stream, + unsigned int flags) +{ + virConnectPtr conn; + + VIR_DOMAIN_DEBUG(dom, "flags=%x", flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(dom)) { + virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + conn = dom->conn; + + if (conn->driver->domainManagedCoreDumpDownload) { + int ret; + + ret = conn->driver->domainManagedCoreDumpDownload(dom, stream, flags); + + if (ret < 0) + goto error; + return ret; + } + + virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index bcefb10..dc9cd5d 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -498,4 +498,12 @@ LIBVIRT_0.9.7 { virDomainSnapshotNumChildren; } LIBVIRT_0.9.5; +LIBVIRT_0.9.8 { + global: + virDomainManagedCoreDump; + virDomainHasManagedCoreDump; + virDomainManagedCoreDumpRemove; + virDomainManagedCoreDumpDownload; +} LIBVIRT_0.9.7; + # .... define new API here using predicted next version number .... -- 1.7.1

* src/remote/remote_driver.c: remote_driver data structure extension. * src/remote/remote_protocol.x: remote protocol extension. Signed-off-by: Hong Xiang <hxiang@linux.vnet.ibm.com> --- src/remote/remote_driver.c | 4 ++++ src/remote/remote_protocol.x | 31 ++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index ea7fb24..0272c91 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -4526,6 +4526,10 @@ static virDriver remote_driver = { .domainGetBlockJobInfo = remoteDomainGetBlockJobInfo, /* 0.9.4 */ .domainBlockJobSetSpeed = remoteDomainBlockJobSetSpeed, /* 0.9.4 */ .domainBlockPull = remoteDomainBlockPull, /* 0.9.4 */ + .domainManagedCoreDump = remoteDomainManagedCoreDump, /* 0.9.8 */ + .domainHasManagedCoreDump = remoteDomainHasManagedCoreDump, /* 0.9.8 */ + .domainManagedCoreDumpRemove = remoteDomainManagedCoreDumpRemove, /* 0.9.8 */ + .domainManagedCoreDumpDownload = remoteDomainManagedCoreDumpDownload, /* 0.9.8 */ }; static virNetworkDriver network_driver = { diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index a174af8..df485e6 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -2267,6 +2267,30 @@ struct remote_domain_open_graphics_args { unsigned int flags; }; +struct remote_domain_managed_core_dump_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_has_managed_core_dump_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_has_managed_core_dump_ret { + int result; +}; + +struct remote_domain_managed_core_dump_remove_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + +struct remote_domain_managed_core_dump_download_args { + remote_nonnull_domain dom; + unsigned int flags; +}; + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -2562,7 +2586,12 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN = 246, /* autogen autogen priority:high */ REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247, /* autogen autogen priority:high */ REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248, /* skipgen skipgen */ - REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249 /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249, /* skipgen skipgen */ + REMOTE_PROC_DOMAIN_MANAGED_CORE_DUMP = 250, /* autogen autogen */ + + REMOTE_PROC_DOMAIN_HAS_MANAGED_CORE_DUMP = 251, /* autogen autogen */ + REMOTE_PROC_DOMAIN_MANAGED_CORE_DUMP_REMOVE = 252, /* autogen autogen */ + REMOTE_PROC_DOMAIN_MANAGED_CORE_DUMP_DOWNLOAD = 253 /* autogen autogen | readstream@1 */ /* * Notice how the entries are grouped in sets of 10 ? -- 1.7.1

* src/qemu/qemu_conf.h: qemud_driver data structure extension. * src/qemu/qemu_driver.c: qemu driver API extension. Signed-off-by: Hong Xiang <hxiang@linux.vnet.ibm.com> --- src/qemu/qemu_conf.h | 2 + src/qemu/qemu_driver.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index ff5cf23..56e9972 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -138,6 +138,8 @@ struct qemud_driver { * of guests which will be automatically killed * when the virConnectPtr is closed*/ virHashTablePtr autodestroy; + + char *managedCoreDumpDir; }; typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5e49ff4..cccfc92 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -472,6 +472,9 @@ qemudStartup(int privileged) { if (virAsprintf(&qemu_driver->autoDumpPath, "%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) == -1) goto out_of_memory; + if (virAsprintf(&qemu_driver->managedCoreDumpDir, + "%s/lib/libvirt/qemu/managed-core-dump", LOCALSTATEDIR) == -1) + goto out_of_memory; } else { uid_t uid = geteuid(); char *userdir = virGetUserDirectory(uid); @@ -502,6 +505,9 @@ qemudStartup(int privileged) { goto out_of_memory; if (virAsprintf(&qemu_driver->autoDumpPath, "%s/qemu/dump", base) == -1) goto out_of_memory; + if (virAsprintf(&qemu_driver->managedCoreDumpDir, + "%s/lib/libvirt/qemu/managed-core-dump", base) == -1) + goto out_of_memory; } if (virFileMakePath(qemu_driver->stateDir) < 0) { @@ -540,6 +546,13 @@ qemudStartup(int privileged) { qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof ebuf)); goto error; } + if (virFileMakePath(qemu_driver->managedCoreDumpDir) < 0) { + char ebuf[1024]; + VIR_ERROR(_("Failed to create managed-core-dump dir '%s': %s"), + qemu_driver->managedCoreDumpDir, + virStrerror(errno, ebuf, sizeof ebuf)); + goto error; + } /* Configuration paths are either ~/.libvirt/qemu/... (session) or * /etc/libvirt/qemu/... (system). @@ -606,6 +619,13 @@ qemudStartup(int privileged) { qemu_driver->snapshotDir, qemu_driver->user, qemu_driver->group); goto error; } + if (chown(qemu_driver->managedCoreDumpDir, qemu_driver->user, qemu_driver->group) < 0) { + virReportSystemError(errno, + _("unable to set ownership of '%s' to %d:%d"), + qemu_driver->managedCoreDumpDir, + qemu_driver->user, qemu_driver->group); + goto error; + } } /* If hugetlbfs is present, then we need to create a sub-directory within @@ -801,6 +821,7 @@ qemudShutdown(void) { VIR_FREE(qemu_driver->hugepage_path); VIR_FREE(qemu_driver->saveImageFormat); VIR_FREE(qemu_driver->dumpImageFormat); + VIR_FREE(qemu_driver->managedCoreDumpDir); virSecurityManagerFree(qemu_driver->securityManager); @@ -2843,6 +2864,19 @@ cleanup: return ret; } +static char * +qemuDomainManagedCoreDumpPath(struct qemud_driver *driver, virDomainObjPtr vm) { + char *ret; + + if (virAsprintf(&ret, "%s/%s.core", driver->managedCoreDumpDir, + vm->def->name) < 0) { + virReportOOMError(); + return(NULL); + } + + return(ret); +} + static int doCoreDump(struct qemud_driver *driver, virDomainObjPtr vm, @@ -2928,7 +2962,7 @@ getCompressionType(struct qemud_driver *driver) return compress; } -static int qemudDomainCoreDump(virDomainPtr dom, +static int qemudDomainCoreDumpInternal(virDomainPtr dom, const char *path, unsigned int flags) { @@ -2938,6 +2972,7 @@ static int qemudDomainCoreDump(virDomainPtr dom, int resume = 0, paused = 0; int ret = -1; virDomainEventPtr event = NULL; + char * real_path = NULL; virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH | VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET, -1); @@ -2952,6 +2987,13 @@ static int qemudDomainCoreDump(virDomainPtr dom, _("no domain with matching uuid '%s'"), uuidstr); goto cleanup; } + if (NULL == path) { + real_path = qemuDomainManagedCoreDumpPath(driver, vm); + if(NULL == real_path) + goto cleanup; + } else { + real_path = (char *)path; + } if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm, QEMU_ASYNC_JOB_DUMP) < 0) @@ -2982,7 +3024,7 @@ static int qemudDomainCoreDump(virDomainPtr dom, } } - ret = doCoreDump(driver, vm, path, getCompressionType(driver), + ret = doCoreDump(driver, vm, real_path, getCompressionType(driver), (flags & VIR_DUMP_BYPASS_CACHE) != 0); if (ret < 0) goto endjob; @@ -3027,6 +3069,8 @@ endjob: } cleanup: + if(NULL == path) + VIR_FREE(real_path); if (vm) virDomainObjUnlock(vm); if (event) @@ -3035,6 +3079,130 @@ cleanup: return ret; } +static int qemudDomainCoreDump(virDomainPtr dom, + const char *path, + unsigned int flags) +{ + return qemudDomainCoreDumpInternal(dom, path, flags); +} + +static int +qemuDomainManagedCoreDump(virDomainPtr dom, unsigned int flags) +{ + return qemudDomainCoreDumpInternal(dom, NULL, flags); +} + +static int +qemuDomainHasManagedCoreDump(virDomainPtr dom, unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + char *name = NULL; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + 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; + } + + name = qemuDomainManagedCoreDumpPath(driver, vm); + if (name == NULL) + goto cleanup; + + ret = virFileExists(name); + +cleanup: + VIR_FREE(name); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + +static int +qemuDomainManagedCoreDumpRemove(virDomainPtr dom, unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm = NULL; + int ret = -1; + char *name = NULL; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + 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; + } + + name = qemuDomainManagedCoreDumpPath(driver, vm); + if (name == NULL) + goto cleanup; + + ret = unlink(name); + +cleanup: + VIR_FREE(name); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + +static int +qemuDomainManagedCoreDumpDownload(virDomainPtr dom, + virStreamPtr st, + unsigned int flags) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + int ret = -1; + char *name = NULL; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain matching uuid '%s'"), uuidstr); + goto cleanup; + } + + name = qemuDomainManagedCoreDumpPath(driver, vm); + if (NULL == name) + goto cleanup; + + if (virFDStreamOpenFile(st, name, 0, 0, O_RDONLY) < 0) { + qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("unable to open stream")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(name); + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + static char * qemuDomainScreenshot(virDomainPtr dom, virStreamPtr st, @@ -10904,6 +11072,10 @@ static virDriver qemuDriver = { .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */ .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */ .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */ + .domainManagedCoreDump = qemuDomainManagedCoreDump, /* 0.9.8 */ + .domainHasManagedCoreDump = qemuDomainHasManagedCoreDump, /* 0.9.8 */ + .domainManagedCoreDumpRemove = qemuDomainManagedCoreDumpRemove, /* 0.9.8 */ + .domainManagedCoreDumpDownload = qemuDomainManagedCoreDumpDownload, /* 0.9.8 */ }; -- 1.7.1

New commands: . manageddump . manageddump-remove . manageddump-download * tools/virsh.c: new commands. Signed-off-by: Hong Xiang <hxiang@linux.vnet.ibm.com> --- tools/virsh.c | 200 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 200 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 5544a41..13f9e73 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -14006,6 +14006,201 @@ cleanup: return ret; } +/* + * "manageddump" command + */ +static const vshCmdInfo info_manageddump[] = { + {"help", N_("managed core dump a domain")}, + {"desc", N_("Managed core dump a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_manageddump[] = { + {"live", VSH_OT_BOOL, 0, N_("perform a live core dump if supported")}, + {"crash", VSH_OT_BOOL, 0, N_("crash the domain after core dump")}, + {"bypass-cache", VSH_OT_BOOL, 0, N_("avoid file system cache when saving")}, + {"reset", VSH_OT_BOOL, 0, N_("reset the domain after core dump")}, + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdManagedDump(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name; + bool ret = false; + unsigned int flags = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + if (vshCommandOptBool (cmd, "live")) + flags |= VIR_DUMP_LIVE; + if (vshCommandOptBool (cmd, "crash")) + flags |= VIR_DUMP_CRASH; + if (vshCommandOptBool(cmd, "bypass-cache")) + flags |= VIR_DUMP_BYPASS_CACHE; + if (vshCommandOptBool(cmd, "reset")) + flags |= VIR_DUMP_RESET; + + if (virDomainManagedCoreDump(dom, flags) < 0) { + vshError(ctl, _("Failed to core dump domain %s"), name); + goto cleanup; + } + + vshPrint(ctl, _("Domain %s dumped\n"), name); + ret = true; + +cleanup: + virDomainFree(dom); + return ret; +} + +/* + * "manageddump-remove" command + */ +static const vshCmdInfo info_manageddumpremove[] = { + {"help", N_("Remove managed core dump of a domain")}, + {"desc", N_("Remove an existing managed core dump from a domain")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_manageddumpremove[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdManagedDumpRemove(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name; + bool ret = false; + int hascoredump; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + hascoredump = virDomainHasManagedCoreDump(dom, 0); + if (hascoredump < 0) { + vshError(ctl, "%s", _("Failed to check for domain managed core dump")); + goto cleanup; + } + + if (hascoredump) { + if (virDomainManagedCoreDumpRemove(dom, 0) < 0) { + vshError(ctl, _("Failed to remove managed core dump for domain %s"), + name); + goto cleanup; + } + else + vshPrint(ctl, _("Removed managed core dump for domain %s"), name); + } + else + vshPrint(ctl, _("Domain %s has no managed core dump; removal skipped"), + name); + + ret = true; + +cleanup: + virDomainFree(dom); + return ret; +} + +/* + * "manageddump-download" command + */ +static const vshCmdInfo info_manageddumpdownload[] = { + {"help", N_("Download managed core dump of a domain")}, + {"desc", N_("Download an existing managed core dump of a domain")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_manageddumpdownload[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"file", VSH_OT_DATA, VSH_OFLAG_NONE, + N_("where to store the downloaded core dump")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdManagedDumpDownload(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name = NULL; + char *file = NULL; + int fd = -1; + virStreamPtr st = NULL; + int ret = false; + int hascoredump; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + hascoredump = virDomainHasManagedCoreDump(dom, 0); + if (hascoredump < 0) { + vshError(ctl, "%s", _("Failed to check for domain managed core dump")); + goto cleanup; + } else if(0 == hascoredump) { + vshPrint(ctl, _("Domain %s has no managed core dump"), name); + goto cleanup; + } + + if (vshCommandOptString(cmd, "file", (const char **) &file) < 0) { + vshError(ctl, "%s", _("file must not be empty")); + goto cleanup; + } + + st = virStreamNew(ctl->conn, 0); + + if(virDomainManagedCoreDumpDownload(dom, st, 0)) { + vshError(ctl, _("could not download managed core dump of %s"), name); + goto cleanup; + } + + if ((fd = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { + vshError(ctl, _("cannot create file %s"), file); + goto cleanup; + } + + if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) { + vshError(ctl, _("could not receive data from domain %s"), name); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + vshError(ctl, _("cannot close file %s"), file); + goto cleanup; + } + + if (virStreamFinish(st) < 0) { + vshError(ctl, _("cannot close stream on domain %s"), name); + goto cleanup; + } + + vshPrint(ctl, _("Managed core dump saved to %s"), file); + ret = true; + +cleanup: + if (!ret) + unlink(file); + virDomainFree(dom); + if (st) + virStreamFree(st); + VIR_FORCE_CLOSE(fd); + return ret; +} + static const vshCmdDef domManagementCmds[] = { {"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device, 0}, @@ -14085,6 +14280,11 @@ static const vshCmdDef domManagementCmds[] = { {"vcpupin", cmdVcpuPin, opts_vcpupin, info_vcpupin, 0}, {"version", cmdVersion, opts_version, info_version, 0}, {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay, 0}, + {"manageddump", cmdManagedDump, opts_manageddump, info_manageddump, 0}, + {"manageddump-remove", cmdManagedDumpRemove, opts_manageddumpremove, + info_manageddumpremove, 0}, + {"manageddump-download", cmdManagedDumpDownload, opts_manageddumpdownload, + info_manageddumpdownload, 0}, {NULL, NULL, NULL, NULL, 0} }; -- 1.7.1
participants (1)
-
Hong Xiang