Add migration for new logfile paths
Update all logfile paths in the database and migrate the referenced log
files to the new directory structure.
Issue: HIC-238
Change-Id: I69b53993e77079258e12ec995cbf85d3eb0a780b
diff --git a/.gitignore b/.gitignore
index f90cfcd..c19350f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -120,5 +120,6 @@
documentation/api-endpoints.adoc
documentation/api-endpoints.html
-# Crashreports uploads directory
+# Crashreport uploads directories
crashreport_uploads/
+crashreport_uploads_legacy/
diff --git a/crashreports/migrations/0004_update_logfile_paths.py b/crashreports/migrations/0004_update_logfile_paths.py
new file mode 100644
index 0000000..fe6afac
--- /dev/null
+++ b/crashreports/migrations/0004_update_logfile_paths.py
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+
+"""Migrations to update the path where logfiles are stored."""
+# pylint: disable=invalid-name
+
+import logging
+import os
+import shutil
+
+from django.db import migrations
+from django.conf import settings
+
+from crashreports.models import LogFile, crashreport_file_name
+
+
+def get_django_logger():
+ """Get the Django logger instance."""
+ logger_name = next(iter(settings.LOGGING["loggers"].keys()))
+ return logging.getLogger(logger_name)
+
+
+def migrate_logfiles(apps, schema_editor):
+ """Migrate the logfiles and update the logfile paths in the database."""
+ # pylint: disable=unused-argument
+
+ logger = get_django_logger()
+
+ crashreport_uploads_dir = "crashreport_uploads"
+ crashreport_uploads_legacy_dir = "crashreport_uploads_legacy"
+ if not os.path.isdir(crashreport_uploads_dir):
+ logger.info(
+ "%s directory not found. Assuming this is a new installation and "
+ "the migration does not need to be applied.",
+ os.path.join(settings.BASE_DIR, crashreport_uploads_dir),
+ )
+ return
+
+ shutil.move(crashreport_uploads_dir, crashreport_uploads_legacy_dir)
+
+ for logfile in LogFile.objects.all():
+ migrate_logfile_instance(
+ logfile, crashreport_uploads_dir, crashreport_uploads_legacy_dir
+ )
+
+
+def migrate_logfile_instance(
+ logfile, crashreport_uploads_dir, crashreport_uploads_legacy_dir
+):
+ """Migrate a single logfile instance."""
+ logger = get_django_logger()
+
+ original_path = logfile.logfile.name
+ old_logfile_path = original_path.replace(
+ crashreport_uploads_dir, crashreport_uploads_legacy_dir, 1
+ )
+ new_logfile_path = crashreport_file_name(
+ logfile, os.path.basename(original_path)
+ )
+ logger.info("Migrating %s", old_logfile_path)
+ if os.path.isfile(old_logfile_path):
+ update_logfile_path(logfile, new_logfile_path)
+ move_logfile_file(old_logfile_path, new_logfile_path)
+ else:
+ logger.warning("Logfile does not exist: %s", old_logfile_path)
+
+
+def move_logfile_file(old_logfile_path, new_logfile_path):
+ """Move a logfile to a new path and delete empty directories."""
+ logger = get_django_logger()
+
+ logger.debug("Creating directories for %s", new_logfile_path)
+ os.makedirs(os.path.dirname(new_logfile_path), exist_ok=True)
+
+ logger.debug("Moving %s to %s", old_logfile_path, new_logfile_path)
+ shutil.move(old_logfile_path, new_logfile_path)
+
+ logger.debug("Deleting empty directories from %s", old_logfile_path)
+ os.removedirs(os.path.dirname(old_logfile_path))
+
+
+def update_logfile_path(logfile, new_logfile_path):
+ """Update the path of a logfile database instance."""
+ logger = get_django_logger()
+ logger.debug(
+ "Changing logfile path in database from %s to %s",
+ logfile.logfile,
+ new_logfile_path,
+ )
+
+ logfile.logfile = new_logfile_path
+ logfile.save()
+
+
+class Migration(migrations.Migration):
+ """Run the migration script."""
+
+ dependencies = [
+ ("crashreports", "0003_crashreport_and_heartbeat_with_radio_version")
+ ]
+
+ operations = [migrations.RunPython(migrate_logfiles)]