diff --git a/authentik/admin/apps.py b/authentik/admin/apps.py index 91d087365b..d151a6f953 100644 --- a/authentik/admin/apps.py +++ b/authentik/admin/apps.py @@ -15,7 +15,3 @@ class AuthentikAdminConfig(ManagedAppConfig): label = "authentik_admin" verbose_name = "authentik Admin" default = True - - def reconcile_global_load_admin_signals(self): - """Load admin signals""" - self.import_module("authentik.admin.signals") diff --git a/authentik/blueprints/apps.py b/authentik/blueprints/apps.py index 0d31f42335..695bc68ce1 100644 --- a/authentik/blueprints/apps.py +++ b/authentik/blueprints/apps.py @@ -21,10 +21,27 @@ class ManagedAppConfig(AppConfig): self.logger = get_logger().bind(app_name=app_name) def ready(self) -> None: + self.import_related() self.reconcile_global() self.reconcile_tenant() return super().ready() + def import_related(self): + """Automatically import related modules which rely on just being imported + to register themselves (mainly django signals and celery tasks)""" + + def import_relative(rel_module: str): + try: + module_name = f"{self.name}.{rel_module}" + import_module(module_name) + self.logger.info("Imported related module", module=module_name) + except ModuleNotFoundError: + pass + + import_relative("checks") + import_relative("tasks") + import_relative("signals") + def import_module(self, path: str): """Load module""" import_module(path) diff --git a/authentik/core/apps.py b/authentik/core/apps.py index b0b8595b6a..866405327c 100644 --- a/authentik/core/apps.py +++ b/authentik/core/apps.py @@ -14,10 +14,6 @@ class AuthentikCoreConfig(ManagedAppConfig): mountpoint = "" default = True - def reconcile_global_load_core_signals(self): - """Load core signals""" - self.import_module("authentik.core.signals") - def reconcile_global_debug_worker_hook(self): """Dispatch startup tasks inline when debugging""" if settings.DEBUG: diff --git a/authentik/crypto/apps.py b/authentik/crypto/apps.py index f919ca600f..d80076657c 100644 --- a/authentik/crypto/apps.py +++ b/authentik/crypto/apps.py @@ -17,10 +17,6 @@ class AuthentikCryptoConfig(ManagedAppConfig): verbose_name = "authentik Crypto" default = True - def reconcile_global_load_crypto_tasks(self): - """Load crypto tasks""" - self.import_module("authentik.crypto.tasks") - def _create_update_cert(self): from authentik.crypto.builder import CertificateBuilder from authentik.crypto.models import CertificateKeyPair diff --git a/authentik/enterprise/apps.py b/authentik/enterprise/apps.py index ae979dac77..0b1057ac9a 100644 --- a/authentik/enterprise/apps.py +++ b/authentik/enterprise/apps.py @@ -17,10 +17,6 @@ class AuthentikEnterpriseConfig(EnterpriseConfig): verbose_name = "authentik Enterprise" default = True - def reconcile_global_load_enterprise_signals(self): - """Load enterprise signals""" - self.import_module("authentik.enterprise.signals") - def enabled(self): """Return true if enterprise is enabled and valid""" return self.check_enabled() or settings.TEST diff --git a/authentik/enterprise/providers/rac/apps.py b/authentik/enterprise/providers/rac/apps.py index d5ad27b6d5..6359c5594b 100644 --- a/authentik/enterprise/providers/rac/apps.py +++ b/authentik/enterprise/providers/rac/apps.py @@ -12,7 +12,3 @@ class AuthentikEnterpriseProviderRAC(EnterpriseConfig): default = True mountpoint = "" ws_mountpoint = "authentik.enterprise.providers.rac.urls" - - def reconcile_global_load_rac_signals(self): - """Load rac signals""" - self.import_module("authentik.enterprise.providers.rac.signals") diff --git a/authentik/enterprise/settings.py b/authentik/enterprise/settings.py index fb91d7f444..f026c70c22 100644 --- a/authentik/enterprise/settings.py +++ b/authentik/enterprise/settings.py @@ -5,9 +5,9 @@ from celery.schedules import crontab from authentik.lib.utils.time import fqdn_rand CELERY_BEAT_SCHEDULE = { - "enterprise_calculate_license": { - "task": "authentik.enterprise.tasks.calculate_license", - "schedule": crontab(minute=fqdn_rand("calculate_license"), hour="*/2"), + "enterprise_update_usage": { + "task": "authentik.enterprise.tasks.enterprise_update_usage", + "schedule": crontab(minute=fqdn_rand("enterprise_update_usage"), hour="*/2"), "options": {"queue": "authentik_scheduled"}, } } diff --git a/authentik/enterprise/tasks.py b/authentik/enterprise/tasks.py index df0d934f89..df5fa54e7d 100644 --- a/authentik/enterprise/tasks.py +++ b/authentik/enterprise/tasks.py @@ -1,11 +1,12 @@ """Enterprise tasks""" from authentik.enterprise.models import LicenseKey -from authentik.events.system_tasks import SystemTask +from authentik.events.system_tasks import SystemTask, prefill_task from authentik.root.celery import CELERY_APP -@CELERY_APP.task(base=SystemTask) -def calculate_license(): - """Calculate licensing status""" +@CELERY_APP.task(bind=True, base=SystemTask) +@prefill_task +def enterprise_update_usage(self: SystemTask): + """Update enterprise license status""" LicenseKey.get_total().record_usage() diff --git a/authentik/events/apps.py b/authentik/events/apps.py index 1a7c060806..a5ca9375a9 100644 --- a/authentik/events/apps.py +++ b/authentik/events/apps.py @@ -35,10 +35,6 @@ class AuthentikEventsConfig(ManagedAppConfig): verbose_name = "authentik Events" default = True - def reconcile_global_load_events_signals(self): - """Load events signals""" - self.import_module("authentik.events.signals") - def reconcile_global_check_deprecations(self): """Check for config deprecations""" from authentik.events.models import Event, EventAction diff --git a/authentik/events/models.py b/authentik/events/models.py index 900536f3e6..5d78a3aa12 100644 --- a/authentik/events/models.py +++ b/authentik/events/models.py @@ -642,17 +642,16 @@ class SystemTask(SerializerModel, ExpiringModel): def update_metrics(self): """Update prometheus metrics""" - duration = max(self.finish_timestamp - self.start_timestamp, 0) # TODO: Deprecated metric - remove in 2024.2 or later GAUGE_TASKS.labels( tenant=connection.schema_name, task_name=self.name, task_uid=self.uid or "", status=self.status.lower(), - ).set(duration) + ).set(self.duration) SYSTEM_TASK_TIME.labels( tenant=connection.schema_name, - ).observe(duration) + ).observe(self.duration) SYSTEM_TASK_STATUS.labels( tenant=connection.schema_name, task_name=self.name, diff --git a/authentik/flows/apps.py b/authentik/flows/apps.py index b0ffff2c70..976dec2e28 100644 --- a/authentik/flows/apps.py +++ b/authentik/flows/apps.py @@ -31,10 +31,6 @@ class AuthentikFlowsConfig(ManagedAppConfig): verbose_name = "authentik Flows" default = True - def reconcile_global_load_flows_signals(self): - """Load flows signals""" - self.import_module("authentik.flows.signals") - def reconcile_global_load_stages(self): """Ensure all stages are loaded""" from authentik.flows.models import Stage diff --git a/authentik/outposts/apps.py b/authentik/outposts/apps.py index 8cf7874c78..f07b8297c4 100644 --- a/authentik/outposts/apps.py +++ b/authentik/outposts/apps.py @@ -30,10 +30,6 @@ class AuthentikOutpostConfig(ManagedAppConfig): verbose_name = "authentik Outpost" default = True - def reconcile_global_load_outposts_signals(self): - """Load outposts signals""" - self.import_module("authentik.outposts.signals") - def reconcile_tenant_embedded_outpost(self): """Ensure embedded outpost""" from authentik.outposts.models import ( diff --git a/authentik/policies/apps.py b/authentik/policies/apps.py index 7d70dc5a0e..107a801295 100644 --- a/authentik/policies/apps.py +++ b/authentik/policies/apps.py @@ -35,7 +35,3 @@ class AuthentikPoliciesConfig(ManagedAppConfig): label = "authentik_policies" verbose_name = "authentik Policies" default = True - - def reconcile_global_load_policies_signals(self): - """Load policies signals""" - self.import_module("authentik.policies.signals") diff --git a/authentik/policies/reputation/apps.py b/authentik/policies/reputation/apps.py index f01f85790f..60b2c77b05 100644 --- a/authentik/policies/reputation/apps.py +++ b/authentik/policies/reputation/apps.py @@ -12,11 +12,3 @@ class AuthentikPolicyReputationConfig(ManagedAppConfig): label = "authentik_policies_reputation" verbose_name = "authentik Policies.Reputation" default = True - - def reconcile_global_load_policies_reputation_signals(self): - """Load policies.reputation signals""" - self.import_module("authentik.policies.reputation.signals") - - def reconcile_global_load_policies_reputation_tasks(self): - """Load policies.reputation tasks""" - self.import_module("authentik.policies.reputation.tasks") diff --git a/authentik/providers/proxy/apps.py b/authentik/providers/proxy/apps.py index a5c0af761c..c5a384f748 100644 --- a/authentik/providers/proxy/apps.py +++ b/authentik/providers/proxy/apps.py @@ -10,7 +10,3 @@ class AuthentikProviderProxyConfig(ManagedAppConfig): label = "authentik_providers_proxy" verbose_name = "authentik Providers.Proxy" default = True - - def reconcile_global_load_providers_proxy_signals(self): - """Load proxy signals""" - self.import_module("authentik.providers.proxy.signals") diff --git a/authentik/providers/scim/apps.py b/authentik/providers/scim/apps.py index efba40a977..9e6f3836f2 100644 --- a/authentik/providers/scim/apps.py +++ b/authentik/providers/scim/apps.py @@ -10,7 +10,3 @@ class AuthentikProviderSCIMConfig(ManagedAppConfig): label = "authentik_providers_scim" verbose_name = "authentik Providers.SCIM" default = True - - def reconcile_global_load_signals(self): - """Load signals""" - self.import_module("authentik.providers.scim.signals") diff --git a/authentik/rbac/apps.py b/authentik/rbac/apps.py index e04979bce3..72424c244a 100644 --- a/authentik/rbac/apps.py +++ b/authentik/rbac/apps.py @@ -10,7 +10,3 @@ class AuthentikRBACConfig(ManagedAppConfig): label = "authentik_rbac" verbose_name = "authentik RBAC" default = True - - def reconcile_global_load_rbac_signals(self): - """Load rbac signals""" - self.import_module("authentik.rbac.signals") diff --git a/authentik/root/settings.py b/authentik/root/settings.py index 5aabaa62f5..902825f377 100644 --- a/authentik/root/settings.py +++ b/authentik/root/settings.py @@ -69,7 +69,6 @@ TENANT_APPS = [ "authentik.admin", "authentik.api", "authentik.crypto", - "authentik.events", "authentik.flows", "authentik.outposts", "authentik.policies.dummy", @@ -509,5 +508,9 @@ try: except ImportError: pass +# Import events after other apps since it relies on tasks and other things from all apps +# being imported for @prefill_task +TENANT_APPS.append("authentik.events") + SHARED_APPS = list(OrderedDict.fromkeys(SHARED_APPS + TENANT_APPS)) INSTALLED_APPS = list(OrderedDict.fromkeys(SHARED_APPS + TENANT_APPS)) diff --git a/authentik/sources/ldap/apps.py b/authentik/sources/ldap/apps.py index a7380f4f70..808a048a25 100644 --- a/authentik/sources/ldap/apps.py +++ b/authentik/sources/ldap/apps.py @@ -10,7 +10,3 @@ class AuthentikSourceLDAPConfig(ManagedAppConfig): label = "authentik_sources_ldap" verbose_name = "authentik Sources.LDAP" default = True - - def reconcile_global_load_sources_ldap_signals(self): - """Load sources.ldap signals""" - self.import_module("authentik.sources.ldap.signals") diff --git a/authentik/sources/saml/apps.py b/authentik/sources/saml/apps.py index 53d35f8eae..4d6feb54b5 100644 --- a/authentik/sources/saml/apps.py +++ b/authentik/sources/saml/apps.py @@ -11,7 +11,3 @@ class AuthentikSourceSAMLConfig(ManagedAppConfig): verbose_name = "authentik Sources.SAML" mountpoint = "source/saml/" default = True - - def reconcile_global_load_sources_saml_signals(self): - """Load sources.saml signals""" - self.import_module("authentik.sources.saml.signals") diff --git a/authentik/stages/authenticator_duo/apps.py b/authentik/stages/authenticator_duo/apps.py index 0e0e5d9271..3e9ceb3b1c 100644 --- a/authentik/stages/authenticator_duo/apps.py +++ b/authentik/stages/authenticator_duo/apps.py @@ -10,7 +10,3 @@ class AuthentikStageAuthenticatorDuoConfig(ManagedAppConfig): label = "authentik_stages_authenticator_duo" verbose_name = "authentik Stages.Authenticator.Duo" default = True - - def reconcile_global_load_tasks(self): - """Load tasks""" - self.import_module("authentik.stages.authenticator_duo.tasks") diff --git a/authentik/stages/authenticator_static/apps.py b/authentik/stages/authenticator_static/apps.py index 9cbcd5b372..02dc8af690 100644 --- a/authentik/stages/authenticator_static/apps.py +++ b/authentik/stages/authenticator_static/apps.py @@ -10,7 +10,3 @@ class AuthentikStageAuthenticatorStaticConfig(ManagedAppConfig): label = "authentik_stages_authenticator_static" verbose_name = "authentik Stages.Authenticator.Static" default = True - - def reconcile_global_load_stages_authenticator_static_signals(self): - """Load stages.authenticator_static signals""" - self.import_module("authentik.stages.authenticator_static.signals") diff --git a/authentik/stages/email/apps.py b/authentik/stages/email/apps.py index cc1c4fb97b..007ca8ac5d 100644 --- a/authentik/stages/email/apps.py +++ b/authentik/stages/email/apps.py @@ -1,11 +1,7 @@ """authentik email stage config""" -from structlog.stdlib import get_logger - from authentik.blueprints.apps import ManagedAppConfig -LOGGER = get_logger() - class AuthentikStageEmailConfig(ManagedAppConfig): """authentik email stage config""" @@ -14,7 +10,3 @@ class AuthentikStageEmailConfig(ManagedAppConfig): label = "authentik_stages_email" verbose_name = "authentik Stages.Email" default = True - - def reconcile_global_load_stages_emails_tasks(self): - """Load stages.emails tasks""" - self.import_module("authentik.stages.email.tasks") diff --git a/authentik/tenants/apps.py b/authentik/tenants/apps.py index 9322d33180..3ae4f3014a 100644 --- a/authentik/tenants/apps.py +++ b/authentik/tenants/apps.py @@ -28,10 +28,6 @@ class AuthentikTenantsConfig(ManagedAppConfig): verbose_name = "authentik Tenants" default = True - def reconcile_global_load_checks(self): - """Load tenant checks""" - self.import_module("authentik.tenants.checks") - def reconcile_global_default_tenant(self): """Make sure default tenant exists, especially after a migration""" post_migrate.connect(ensure_default_tenant)