From f08da8f295a6550478b06b403b19008ac1214d2e Mon Sep 17 00:00:00 2001 From: Marc 'risson' Schmitt Date: Thu, 6 Mar 2025 14:53:09 +0100 Subject: [PATCH] lib/config: fix conn_max_age parsing (#13370) Signed-off-by: Marc 'risson' Schmitt --- authentik/lib/config.py | 16 ++++++-------- authentik/lib/tests/test_config.py | 22 +++++++++++++++++++ .../configuration/configuration.mdx | 6 ++--- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/authentik/lib/config.py b/authentik/lib/config.py index 88e9f09752..2581dd038a 100644 --- a/authentik/lib/config.py +++ b/authentik/lib/config.py @@ -282,16 +282,14 @@ class ConfigLoader: def get_optional_int(self, path: str, default=None) -> int | None: """Wrapper for get that converts value into int or None if set""" - value = self.get(path, default) + value = self.get(path, UNSET) if value is UNSET: return default try: return int(value) except (ValueError, TypeError) as exc: if value is None or (isinstance(value, str) and value.lower() == "null"): - return default - if value is UNSET: - return default + return None self.log("warning", "Failed to parse config as int", path=path, exc=str(exc)) return default @@ -372,9 +370,9 @@ def django_db_config(config: ConfigLoader | None = None) -> dict: "sslcert": config.get("postgresql.sslcert"), "sslkey": config.get("postgresql.sslkey"), }, - "CONN_MAX_AGE": CONFIG.get_optional_int("postgresql.conn_max_age", 0), - "CONN_HEALTH_CHECKS": CONFIG.get_bool("postgresql.conn_health_checks", False), - "DISABLE_SERVER_SIDE_CURSORS": CONFIG.get_bool( + "CONN_MAX_AGE": config.get_optional_int("postgresql.conn_max_age", 0), + "CONN_HEALTH_CHECKS": config.get_bool("postgresql.conn_health_checks", False), + "DISABLE_SERVER_SIDE_CURSORS": config.get_bool( "postgresql.disable_server_side_cursors", False ), "TEST": { @@ -383,8 +381,8 @@ def django_db_config(config: ConfigLoader | None = None) -> dict: } } - conn_max_age = CONFIG.get_optional_int("postgresql.conn_max_age", UNSET) - disable_server_side_cursors = CONFIG.get_bool("postgresql.disable_server_side_cursors", UNSET) + conn_max_age = config.get_optional_int("postgresql.conn_max_age", UNSET) + disable_server_side_cursors = config.get_bool("postgresql.disable_server_side_cursors", UNSET) if config.get_bool("postgresql.use_pgpool", False): db["default"]["DISABLE_SERVER_SIDE_CURSORS"] = True if disable_server_side_cursors is not UNSET: diff --git a/authentik/lib/tests/test_config.py b/authentik/lib/tests/test_config.py index bbe286db46..df0ec526aa 100644 --- a/authentik/lib/tests/test_config.py +++ b/authentik/lib/tests/test_config.py @@ -158,6 +158,18 @@ class TestConfig(TestCase): test_obj = Test() dumps(test_obj, indent=4, cls=AttrEncoder) + def test_get_optional_int(self): + config = ConfigLoader() + self.assertEqual(config.get_optional_int("foo", 21), 21) + self.assertEqual(config.get_optional_int("foo"), None) + config.set("foo", "21") + self.assertEqual(config.get_optional_int("foo"), 21) + self.assertEqual(config.get_optional_int("foo", 0), 21) + self.assertEqual(config.get_optional_int("foo", "null"), 21) + config.set("foo", "null") + self.assertEqual(config.get_optional_int("foo"), None) + self.assertEqual(config.get_optional_int("foo", 21), None) + @mock.patch.dict(environ, check_deprecations_env_vars) def test_check_deprecations(self): """Test config key re-write for deprecated env vars""" @@ -221,6 +233,16 @@ class TestConfig(TestCase): }, ) + def test_db_conn_max_age(self): + """Test DB conn_max_age Config""" + config = ConfigLoader() + config.set("postgresql.conn_max_age", "null") + conf = django_db_config(config) + self.assertEqual( + conf["default"]["CONN_MAX_AGE"], + None, + ) + def test_db_read_replicas(self): """Test read replicas""" config = ConfigLoader() diff --git a/website/docs/install-config/configuration/configuration.mdx b/website/docs/install-config/configuration/configuration.mdx index a102860e2c..8f81b1681c 100644 --- a/website/docs/install-config/configuration/configuration.mdx +++ b/website/docs/install-config/configuration/configuration.mdx @@ -77,7 +77,7 @@ To check if your config has been applied correctly, you can run the following co - `AUTHENTIK_POSTGRESQL__SSLCERT`: Path to x509 client certificate to authenticate to server - `AUTHENTIK_POSTGRESQL__SSLKEY`: Path to private key of `SSLCERT` certificate - `AUTHENTIK_POSTGRESQL__CONN_MAX_AGE`: Database connection lifetime. Defaults to `0` (no persistent connections). Can be set to `null` for unlimited persistent connections. See [Django's documentation](https://docs.djangoproject.com/en/stable/ref/settings/#conn-max-age) for more details. -- `AUTHENTIK_POSTGRESQL__CONN_HEALTH_CHECK`: Existing persistent database connections will be health checked before they are reused if set to `true`. Defaults to `false`. See [Django's documentation](https://docs.djangoproject.com/en/stable/ref/settings/#conn-health-checks) for more details. +- `AUTHENTIK_POSTGRESQL__CONN_HEALTH_CHECKS`: Existing persistent database connections will be health checked before they are reused if set to `true`. Defaults to `false`. See [Django's documentation](https://docs.djangoproject.com/en/stable/ref/settings/#conn-health-checks) for more details. - `AUTHENTIK_POSTGRESQL__DISABLE_SERVER_SIDE_CURSORS`: Disable server side cursors when set to `true`. Defaults to `false`. See [Django's documentation](https://docs.djangoproject.com/en/stable/ref/settings/#disable-server-side-cursors) for more details. The PostgreSQL settings `HOST`, `PORT`, `USER`, and `PASSWORD` support hot-reloading. Adding and removing read replicas doesn't support hot-reloading. @@ -108,7 +108,7 @@ The same PostgreSQL settings as described above are used for each read replica. - `AUTHENTIK_POSTGRESQL__READ_REPLICAS__0__SSLCERT` - `AUTHENTIK_POSTGRESQL__READ_REPLICAS__0__SSLKEY` - `AUTHENTIK_POSTGRESQL__READ_REPLICAS__0__CONN_MAX_AGE` -- `AUTHENTIK_POSTGRESQL__READ_REPLICAS__0__CONN_HEALTH_CHECK` +- `AUTHENTIK_POSTGRESQL__READ_REPLICAS__0__CONN_HEALTH_CHECKS` - `AUTHENTIK_POSTGRESQL__READ_REPLICAS__0__DISABLE_SERVER_SIDE_CURSORS` ### Using a PostgreSQL connection pooler (PgBouncer or PgPool) @@ -125,7 +125,7 @@ When your PostgreSQL database(s) are running behind a connection pooler, like Pg Using a connection pooler in transaction pool mode (e.g. PgPool, or PgBouncer in transaction or statement pool mode) requires disabling server-side cursors, so this setting must be set to `false`. -Additionally, you can set `AUTHENTIK_POSTGRESQL__CONN_HEALTH_CHECK` to perform health checks on persistent database connections before they are reused. +Additionally, you can set `AUTHENTIK_POSTGRESQL__CONN_HEALTH_CHECKS` to perform health checks on persistent database connections before they are reused. ## Redis Settings