From 4e3f48a0ffffd38daa3cad6929c37d750d74e1ad Mon Sep 17 00:00:00 2001 From: Matthias Dellweg Date: Thu, 3 Sep 2026 18:30:15 +0200 Subject: [PATCH] Fix post-migrate hooks Post migrate hooks are called after every migration. So they must be resilient against missing or differently looking models. Either they take the models from the passed apps and suppress LookupError or they should suppress both LookupError and ProgrammingError. --- CHANGES/+fix_post_migrate_hooks.bugfix | 1 + pulpcore/app/apps.py | 49 ++++++++++++++------------ 2 files changed, 28 insertions(+), 22 deletions(-) create mode 100644 CHANGES/+fix_post_migrate_hooks.bugfix diff --git a/CHANGES/+fix_post_migrate_hooks.bugfix b/CHANGES/+fix_post_migrate_hooks.bugfix new file mode 100644 index 00000000000..97c19b32e3d --- /dev/null +++ b/CHANGES/+fix_post_migrate_hooks.bugfix @@ -0,0 +1 @@ +Fixed post-migrate hooks to prevent failing on incomplete or rolled back migrations. diff --git a/pulpcore/app/apps.py b/pulpcore/app/apps.py index eb80e452d74..adc28a18ac0 100644 --- a/pulpcore/app/apps.py +++ b/pulpcore/app/apps.py @@ -1,12 +1,13 @@ import random from collections import defaultdict +from contextlib import suppress from gettext import gettext as _ from importlib import import_module from django import apps from django.conf import settings from django.core.exceptions import ImproperlyConfigured -from django.db import connection, transaction +from django.db import ProgrammingError, connection, transaction from django.db.models.signals import post_migrate, pre_migrate from django.utils.module_loading import module_has_submodule @@ -320,27 +321,31 @@ def _populate_access_policies(sender, apps, verbosity, **kwargs): def _populate_system_id(sender, apps, verbosity, **kwargs): - SystemID = apps.get_model("core", "SystemID") - if not SystemID.objects.exists(): - SystemID().save() - - -def _ensure_default_domain(sender, **kwargs): - table_names = connection.introspection.table_names() - if "core_domain" in table_names: - from pulpcore.app.util import get_default_domain - - default = get_default_domain() # Cache the default domain - # Match the Pulp settings - if ( - settings.HIDE_GUARDED_DISTRIBUTIONS != default.hide_guarded_distributions - or settings.REDIRECT_TO_OBJECT_STORAGE != default.redirect_to_object_storage - or settings.STORAGES["default"]["BACKEND"] != default.storage_class - ): - default.hide_guarded_distributions = settings.HIDE_GUARDED_DISTRIBUTIONS - default.redirect_to_object_storage = settings.REDIRECT_TO_OBJECT_STORAGE - default.storage_class = settings.STORAGES["default"]["BACKEND"] - default.save(skip_hooks=True) + with suppress(LookupError): + SystemID = apps.get_model("core", "SystemID") + if not SystemID.objects.exists(): + SystemID().save() + + +def _ensure_default_domain(sender, apps, **kwargs): + # This is a post migrate hook. + # But on rolling back the database may not match what this function expects. + with suppress(LookupError, ProgrammingError): + table_names = connection.introspection.table_names() + if "core_domain" in table_names: + from pulpcore.app.util import get_default_domain + + default = get_default_domain() # Cache the default domain + # Match the Pulp settings + if ( + settings.HIDE_GUARDED_DISTRIBUTIONS != default.hide_guarded_distributions + or settings.REDIRECT_TO_OBJECT_STORAGE != default.redirect_to_object_storage + or settings.STORAGES["default"]["BACKEND"] != default.storage_class + ): + default.hide_guarded_distributions = settings.HIDE_GUARDED_DISTRIBUTIONS + default.redirect_to_object_storage = settings.REDIRECT_TO_OBJECT_STORAGE + default.storage_class = settings.STORAGES["default"]["BACKEND"] + default.save(skip_hooks=True) def _populate_roles(sender, apps, verbosity, **kwargs):