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 <nshirokovskiy(a)virtuozzo.com>
---
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 a8401bac30..d1531bd77a 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -11592,3 +11592,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 e5046367e3..5a5d6daf71 100644
--- a/src/qemu/qemu_domain.h
+++ b/src/qemu/qemu_domain.h
@@ -1057,3 +1057,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 65ac5ef367..c1cf30639a 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -2071,7 +2071,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;
@@ -2111,6 +2112,11 @@ qemuDomainDestroyFlags(virDomainPtr dom,
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED,
QEMU_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);
--
2.31.1