Skip to content

Commit 1d42ea7

Browse files
pedro-psbmdellweg
authored andcommitted
Fix dynaconf's django integration code
Thre should be no settings activity after dyanconf's instantiation. Assisted-by: Claude (Claude Code) (cherry picked from commit 0a06d30)
1 parent d0d8c55 commit 1d42ea7

1 file changed

Lines changed: 82 additions & 55 deletions

File tree

pulpcore/app/settings.py

Lines changed: 82 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
import sys
1212
from contextlib import suppress
1313
from importlib import import_module
14-
from logging import getLogger
1514
from pathlib import Path
1615

1716
from cryptography.fernet import Fernet
1817
from django.conf import global_settings
1918
from django.core.exceptions import ImproperlyConfigured
2019
from django.core.files.storage import storages
20+
from dynaconf import DjangoDynaconf, Dynaconf, Validator
2121

2222
from pulpcore import constants
2323

@@ -35,6 +35,24 @@
3535
else:
3636
from importlib.metadata import entry_points
3737

38+
# Load settings first pass before applying all the defaults to get a grip on ENABLED_PLUGINS.
39+
enabled_plugins_validator = Validator(
40+
"ENABLED_PLUGINS",
41+
is_type_of=list,
42+
len_min=1,
43+
when=Validator("ENABLED_PLUGINS", must_exist=True),
44+
)
45+
46+
preload_settings = Dynaconf(
47+
ENVVAR_PREFIX_FOR_DYNACONF="PULP",
48+
ENV_SWITCHER_FOR_DYNACONF="PULP_ENV",
49+
ENVVAR_FOR_DYNACONF="PULP_SETTINGS",
50+
load_dotenv=False,
51+
validators=[
52+
enabled_plugins_validator,
53+
],
54+
)
55+
3856
# Build paths inside the project like this: BASE_DIR / ...
3957
BASE_DIR = Path(__file__).absolute().parent
4058

@@ -129,6 +147,15 @@
129147
import_module(app)
130148
INSTALLED_APPS.append(app)
131149

150+
# Select enabled plugins and prepare to load their settings.
151+
enabled_plugins = preload_settings.get("ENABLED_PLUGINS", None)
152+
plugin_settings = []
153+
for entry_point in entry_points(group="pulpcore.plugin"):
154+
if enabled_plugins is None or entry_point.name in enabled_plugins:
155+
plugin_app = entry_point.load()
156+
plugin_settings.append(f"{entry_point.module}.app.settings")
157+
INSTALLED_APPS += [plugin_app]
158+
132159
MIDDLEWARE = [
133160
"django_guid.middleware.guid_middleware",
134161
"django.middleware.security.SecurityMiddleware",
@@ -383,17 +410,9 @@
383410

384411
# HERE STARTS DYNACONF EXTENSION LOAD (Keep at the very bottom of settings.py)
385412
# Read more at https://www.dynaconf.com/django/
386-
from dynaconf import DjangoDynaconf, Dynaconf, Validator # noqa
387413

388414
# Validators
389415

390-
enabled_plugins_validator = Validator(
391-
"ENABLED_PLUGINS",
392-
is_type_of=list,
393-
len_min=1,
394-
when=Validator("ENABLED_PLUGINS", must_exist=True),
395-
)
396-
397416
storage_keys = ("STORAGES.default.BACKEND", "DEFAULT_FILE_STORAGE")
398417
storage_validator = (
399418
Validator("REDIRECT_TO_OBJECT_STORAGE", eq=False)
@@ -490,39 +509,76 @@ def otel_middleware_hook(settings):
490509
return data
491510

492511

512+
def api_root_hook(settings):
513+
# protocol://host:port/{API_ROOT}{domain}/api/{version}/
514+
# All of the below are DEPRECATED, and should be replaced by calling
515+
# pulpcore.plugin.find_url.find_api_root() (q.v.)
516+
if settings.API_ROOT_REWRITE_HEADER:
517+
api_root = "/<path:api_root>/"
518+
else:
519+
api_root = settings.API_ROOT
520+
return {
521+
"V3_API_ROOT": api_root + "api/v3/",
522+
"V3_DOMAIN_API_ROOT": api_root + "<slug:pulp_domain>/api/v3/",
523+
"V3_API_ROOT_NO_FRONT_SLASH": (api_root + "api/v3/").lstrip("/"),
524+
"V3_DOMAIN_API_ROOT_NO_FRONT_SLASH": (api_root + "<slug:pulp_domain>/api/v3/").lstrip("/"),
525+
}
526+
527+
528+
def forbidden_checksums_hook(settings):
529+
return {
530+
"FORBIDDEN_CHECKSUMS": sorted(
531+
set(constants.ALL_KNOWN_CONTENT_CHECKSUMS).difference(
532+
settings.ALLOWED_CONTENT_CHECKSUMS
533+
)
534+
),
535+
}
536+
537+
538+
def validate_db_encryption_key_hook(settings):
539+
if Path(sys.argv[0]).name in ["pytest", "sphinx-build"] or (
540+
len(sys.argv) >= 2 and sys.argv[1] in ["collectstatic", "openapi"]
541+
):
542+
return {}
543+
try:
544+
with open(settings.DB_ENCRYPTION_KEY, "rb") as key_file:
545+
Fernet(key_file.read())
546+
except Exception as ex:
547+
raise ImproperlyConfigured(
548+
"Could not load DB_ENCRYPTION_KEY file '{file}': {err}".format(
549+
file=settings.DB_ENCRYPTION_KEY, err=ex
550+
)
551+
)
552+
return {}
553+
554+
555+
del preload_settings
556+
493557
settings = DjangoDynaconf(
494558
__name__,
495559
ENVVAR_PREFIX_FOR_DYNACONF="PULP",
496560
ENV_SWITCHER_FOR_DYNACONF="PULP_ENV",
497561
ENVVAR_FOR_DYNACONF="PULP_SETTINGS",
562+
# Ensure the plugin defaults are loaded before user configs.
563+
PRELOAD_FOR_DYNACONF=plugin_settings,
498564
load_dotenv=False,
499565
validators=[
500566
api_root_validator,
501567
cache_validator,
502-
enabled_plugins_validator,
503568
sha256_validator,
504569
storage_validator,
505570
unknown_algs_validator,
506571
json_header_auth_validator,
507572
authentication_json_header_openapi_security_scheme_validator,
508573
],
509-
post_hooks=(otel_middleware_hook,),
574+
post_hooks=(
575+
otel_middleware_hook,
576+
api_root_hook,
577+
forbidden_checksums_hook,
578+
validate_db_encryption_key_hook,
579+
),
510580
)
511581

512-
# Select enabled plugins and load their settings.
513-
enabled_plugins = settings.get("ENABLED_PLUGINS", None)
514-
plugin_settings = []
515-
for entry_point in entry_points(group="pulpcore.plugin"):
516-
if enabled_plugins and entry_point.name not in enabled_plugins:
517-
continue
518-
if (plugin_app := entry_point.load()) not in settings.INSTALLED_APPS:
519-
plugin_settings.append(f"{entry_point.module}.app.settings")
520-
settings.INSTALLED_APPS += [plugin_app]
521-
# Ensure the plugin defaults are loaded before user configs
522-
settings.PRELOAD_FOR_DYNACONF = plugin_settings
523-
settings.reload()
524-
INSTALLED_APPS = settings.INSTALLED_APPS
525-
526582
# begin compatibility layer for DEFAULT_FILE_STORAGE
527583
# Remove on pulpcore=3.85 or pulpcore=4.0
528584

@@ -531,33 +587,4 @@ def otel_middleware_hook(settings):
531587
storages.backends
532588
# end compatibility layer
533589

534-
_logger = getLogger(__name__)
535-
536-
537-
if not (
538-
Path(sys.argv[0]).name in ["pytest", "sphinx-build"]
539-
or (len(sys.argv) >= 2 and sys.argv[1] in ["collectstatic", "openapi"])
540-
):
541-
try:
542-
with open(DB_ENCRYPTION_KEY, "rb") as key_file:
543-
Fernet(key_file.read())
544-
except Exception as ex:
545-
raise ImproperlyConfigured(
546-
("Could not load DB_ENCRYPTION_KEY file '{file}': {err}").format(
547-
file=DB_ENCRYPTION_KEY, err=ex
548-
)
549-
)
550-
551-
552-
FORBIDDEN_CHECKSUMS = set(constants.ALL_KNOWN_CONTENT_CHECKSUMS).difference(
553-
ALLOWED_CONTENT_CHECKSUMS
554-
)
555-
556-
if settings.API_ROOT_REWRITE_HEADER:
557-
api_root = "/<path:api_root>/"
558-
else:
559-
api_root = settings.API_ROOT
560-
settings.set("V3_API_ROOT", api_root + "api/v3/") # Not user configurable
561-
settings.set("V3_DOMAIN_API_ROOT", api_root + "<slug:pulp_domain>/api/v3/")
562-
settings.set("V3_API_ROOT_NO_FRONT_SLASH", settings.V3_API_ROOT.lstrip("/"))
563-
settings.set("V3_DOMAIN_API_ROOT_NO_FRONT_SLASH", settings.V3_DOMAIN_API_ROOT.lstrip("/"))
590+
# HERE ENDS DYNACONF EXTENSION LOAD (No more code below this line)

0 commit comments

Comments
 (0)