Files
session_redis_public/session_redis/http.py
T
Atte IsopuroandGitHub 750bc4dcf8 [MIG] session_redis: Migration to 19.0 (#499)
* lazy_property is deprecated
* Since https://github.com/odoo/odoo/commit/cea66be976c6d0746a972da8a16b7a239d12a462, Session
  must be used as a dictionary when setting custom values
* Session default lifetime is now defined in odoo.http, so we can just reuse that
* Handle new session rotation logic (sessions must be findable by the first 42 chars of they key)
* Handle new session key generation for rotation (keys must be longer than 42 chars to handle devices)
2025-11-24 15:37:51 +01:00

121 lines
3.8 KiB
Python

# Copyright 2016-2024 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
import functools
import logging
import os
from odoo import http
from odoo.tools import config
from .session import RedisSessionStore
from .strtobool import strtobool
_logger = logging.getLogger(__name__)
try:
import redis
from redis.sentinel import Sentinel
except ImportError:
redis = None # noqa
_logger.debug("Cannot 'import redis'.")
def is_true(strval):
return bool(strtobool(strval or "0".lower()))
sentinel_host = os.getenv("ODOO_SESSION_REDIS_SENTINEL_HOST")
sentinel_master_name = os.getenv("ODOO_SESSION_REDIS_SENTINEL_MASTER_NAME")
if sentinel_host and not sentinel_master_name:
raise Exception(
"ODOO_SESSION_REDIS_SENTINEL_MASTER_NAME must be defined "
"when using session_redis"
)
sentinel_port = int(os.getenv("ODOO_SESSION_REDIS_SENTINEL_PORT", 26379))
host = os.getenv("ODOO_SESSION_REDIS_HOST", "localhost")
port = int(os.getenv("ODOO_SESSION_REDIS_PORT", 6379))
prefix = os.getenv("ODOO_SESSION_REDIS_PREFIX")
url = os.getenv("ODOO_SESSION_REDIS_URL")
password = os.getenv("ODOO_SESSION_REDIS_PASSWORD")
expiration = os.getenv("ODOO_SESSION_REDIS_EXPIRATION")
anon_expiration = os.getenv("ODOO_SESSION_REDIS_EXPIRATION_ANONYMOUS")
# For non url connections
ssl = os.getenv("ODOO_SESSION_REDIS_SSL", "1")
ssl_cert_reqs = os.getenv("ODOO_SESSION_REDIS_SSL_CERT_REQS", "1")
redis_cluster = os.getenv("ODOO_SESSION_REDIS_CLUSTER", "0")
@functools.cached_property
def session_store(self):
if sentinel_host:
sentinel = Sentinel([(sentinel_host, sentinel_port)], password=password)
redis_client = sentinel.master_for(sentinel_master_name)
elif url:
redis_client = redis.from_url(url)
elif is_true(redis_cluster):
redis_client = redis.RedisCluster(
host=host,
port=port,
password=password,
ssl=is_true(ssl),
ssl_cert_reqs=is_true(ssl_cert_reqs),
)
else:
redis_client = redis.Redis(
host=host,
port=port,
password=password,
ssl=is_true(ssl),
ssl_cert_reqs=is_true(ssl_cert_reqs),
)
return RedisSessionStore(
redis=redis_client,
prefix=prefix,
expiration=expiration,
anon_expiration=anon_expiration,
session_class=http.Session,
)
def purge_fs_sessions(path):
if not os.path.isdir(path):
_logger.warning(f"Session directory '{path}' does not exist.")
return
for fname in os.listdir(path):
path = os.path.join(path, fname)
try:
os.unlink(path)
except OSError:
_logger.warning("OS Error during purge of redis sessions.")
if is_true(os.getenv("ODOO_SESSION_REDIS")):
if sentinel_host:
_logger.debug(
"HTTP sessions stored in Redis with prefix '%s'. "
"Using Sentinel on %s:%s",
prefix or "",
sentinel_host,
sentinel_port,
)
else:
_logger.debug(
"HTTP sessions stored in Redis with prefix '%s' on " "%s:%s",
prefix or "",
host,
port,
)
http.Application.session_store = session_store
# cached_property needs __set_name__ to be called, but it is not called
# automatically since we are attaching the property after instance creation.
# So we have to do it manually
# See: https://docs.python.org/3/reference/datamodel.html#object.__set_name__
# Credit: https://stackoverflow.com/a/62161136
http.Application.session_store.__set_name__(
http.Application,
"session_store",
)
# clean the existing sessions on the file system
purge_fs_sessions(config.session_dir)