From a414cb76e37db4c1c79bde63f7ebd2d014253ae8 Mon Sep 17 00:00:00 2001 From: Nikolay Shirokovskiy Date: Mon, 14 Feb 2022 15:19:52 +0300 Subject: [PATCH] qemu: support VIR_DOMAIN_DESTROY_REMOVE_LOGS flag Note that we attempt to remove logs only if virtlogd is in use. Otherwise we do not know the pattern for rotated files. For example for VM named "foo" we can not use "foo.log*" pattern to remove rotated logs as we can have VM named "foo.log" with log "foo.log.log". We can add extra check that filename does not end with ".log" but for VM "foo.log" we can have rotated log "foo.log.log.1". Ok let's check we don't have "log" in filename part corresponging to * but what if someone will use logrotate with "%Y.log-%m-%d" 'dateformat' option. In this case the check will exclude proper rotated files. Yes, the last example if quite artificial but it shows it is difficult to find out correctly rotated files when rotated files pattern is not known. Thus the above decision only to support case with virtlogd when we know the pattern. Another reason for not removing log files when logrotate is present is that due to races some files can escape deletion. For example foo.log.3 will be rotated to foo.log.4 after removing function will read directory files and thus foo.log.4 will not be deleted. Signed-off-by: Nikolay Shirokovskiy Reviewed-by: Michal Privoznik --- src/qemu/qemu_domain.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_domain.h | 4 ++++ src/qemu/qemu_driver.c | 8 +++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index fe00c6f25b..c35e5c09a3 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -11820,3 +11820,44 @@ qemuDomainDeviceBackendChardevForeach(virDomainDef *def, DOMAIN_DEVICE_ITERATE_MISSING_INFO, &data); } + + +int +qemuDomainRemoveLogs(virQEMUDriver *driver, + const char *name) +{ + g_autoptr(virQEMUDriverConfig) cfg = NULL; + g_autofree char *format = NULL; + g_autofree char *main = NULL; + g_autoptr(DIR) dir = NULL; + struct dirent *entry; + int rc; + + cfg = virQEMUDriverGetConfig(driver); + if (!cfg->stdioLogD) + return 0; + + if (virDirOpen(&dir, cfg->logDir) < 0) + return -1; + + main = g_strdup_printf("%s.log", name); + format = g_strdup_printf("%s.log.%%u", name); + + while ((rc = virDirRead(dir, &entry, cfg->logDir)) > 0) { + unsigned int u; + + if (STREQ(entry->d_name, main) || + sscanf(entry->d_name, format, &u) == 1) { + g_autofree char *path = NULL; + + path = g_strdup_printf("%s/%s", cfg->logDir, entry->d_name); + if (unlink(path) && errno != ENOENT) + VIR_WARN("unlink(%s) error: %s", path, g_strerror(errno)); + } + } + + if (rc < 0) + return -1; + + return 0; +} diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index a41d8308e3..f4d84ca43a 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -1084,3 +1084,7 @@ int qemuDomainDeviceBackendChardevForeach(virDomainDef *def, qemuDomainDeviceBackendChardevForeachCallback cb, void *opaque); + +int +qemuDomainRemoveLogs(virQEMUDriver *driver, + const char *name); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 77012eb527..26647a9ae3 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2072,7 +2072,8 @@ qemuDomainDestroyFlags(virDomainPtr dom, int reason; bool starting; - virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1); + virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL | + VIR_DOMAIN_DESTROY_REMOVE_LOGS, -1); if (!(vm = qemuDomainObjFromDomain(dom))) return -1; @@ -2112,6 +2113,11 @@ qemuDomainDestroyFlags(virDomainPtr dom, qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED, VIR_ASYNC_JOB_NONE, stopFlags); + + if ((flags & VIR_DOMAIN_DESTROY_REMOVE_LOGS) && + qemuDomainRemoveLogs(driver, vm->def->name) < 0) + VIR_WARN("Failed to remove logs for VM '%s'", vm->def->name); + event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED, VIR_DOMAIN_EVENT_STOPPED_DESTROYED);