From 886b41a6c1d3056ecd8168f3bd0114f5ba4dff37 Mon Sep 17 00:00:00 2001 From: Evelyn Alicke Date: Sat, 30 Mar 2024 12:33:06 +0100 Subject: [PATCH] Allow configuring redis to use unix sockets related: https://github.com/netbox-community/netbox/issues/4377 --- docs/configuration/required-parameters.md | 36 +++++++++++++++++++++-- netbox/netbox/settings.py | 33 ++++++++++++++++----- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/docs/configuration/required-parameters.md b/docs/configuration/required-parameters.md index bda365995..c7e61d356 100644 --- a/docs/configuration/required-parameters.md +++ b/docs/configuration/required-parameters.md @@ -105,11 +105,11 @@ REDIS = { ### Using Redis Sentinel -If you are using [Redis Sentinel](https://redis.io/topics/sentinel) for high-availability purposes, there is minimal -configuration necessary to convert NetBox to recognize it. It requires the removal of the `HOST` and `PORT` keys from +If you are using [Redis Sentinel](https://redis.io/topics/sentinel) for high-availability purposes, there is minimal +configuration necessary to convert NetBox to recognize it. It requires the removal of the `HOST` and `PORT` keys from above and the addition of three new keys. -* `SENTINELS`: List of tuples or tuple of tuples with each inner tuple containing the name or IP address +* `SENTINELS`: List of tuples or tuple of tuples with each inner tuple containing the name or IP address of the Redis server and port for each sentinel instance to connect to * `SENTINEL_SERVICE`: Name of the master / service to connect to * `SENTINEL_TIMEOUT`: Connection timeout, in seconds @@ -142,6 +142,36 @@ REDIS = { !!! note It is permissible to use Sentinel for only one database and not the other. + +### Using Redis with Unix Sockets + +If you'd like to configure NetBox to access Redis over unix sockets, set `PROTO: 'unix'` + +Example: + +```python +REDIS = { + 'tasks': { + 'PROTO': 'unix', + 'HOST': '/var/run/redis/redis.sock', + 'PASSWORD': '', + 'USERNAME': '', + } +} +``` +Alternatively, you may specify the location string yourself: +```python +REDIS = { + 'tasks': { + 'LOCATION': 'unix://netbox@/var/run/redis/redis.sock?db=0' + 'PASSWORD': '', + } +} + +!!! note + the `PASSWORD` option is still provided even when using `LOCATION` directly so you don't have to url-encode your password yourself. + + --- ## SECRET_KEY diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index e662561ee..6f7dca952 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -277,11 +277,14 @@ TASKS_REDIS_DATABASE = TASKS_REDIS.get('DATABASE', 0) TASKS_REDIS_SSL = TASKS_REDIS.get('SSL', False) TASKS_REDIS_SKIP_TLS_VERIFY = TASKS_REDIS.get('INSECURE_SKIP_TLS_VERIFY', False) TASKS_REDIS_CA_CERT_PATH = TASKS_REDIS.get('CA_CERT_PATH', False) +TASKS_REDIS_PROTO = 'rediss' if TASKS_REDIS_SSL else TASKS_REDIS.get('PROTO', 'redis') +TASKS_REDIS_LOCATION_FROM_KEYS = f'unix://{TASKS_REDIS_USERNAME_HOST}?db={TASKS_REDIS_DATABASE}' +TASKS_REDIS_LOCATION = TASKS_REDIS.get('LOCATION', TASKS_REDIS_LOCATION_FROM_KEYS) # Caching if 'caching' not in REDIS: raise ImproperlyConfigured( - "REDIS section in configuration.py is missing caching subsection." + "REDIS section in configuration.py is missing 'caching' subsection." ) CACHING_REDIS_HOST = REDIS['caching'].get('HOST', 'localhost') CACHING_REDIS_PORT = REDIS['caching'].get('PORT', 6379) @@ -291,18 +294,30 @@ CACHING_REDIS_USERNAME_HOST = '@'.join(filter(None, [CACHING_REDIS_USERNAME, CAC CACHING_REDIS_PASSWORD = REDIS['caching'].get('PASSWORD', '') CACHING_REDIS_SENTINELS = REDIS['caching'].get('SENTINELS', []) CACHING_REDIS_SENTINEL_SERVICE = REDIS['caching'].get('SENTINEL_SERVICE', 'default') -CACHING_REDIS_PROTO = 'rediss' if REDIS['caching'].get('SSL', False) else 'redis' +CACHING_REDIS_PROTO = 'rediss' if REDIS['caching'].get('SSL', False) else REDIS['caching'].get('PROTO', 'redis') CACHING_REDIS_SKIP_TLS_VERIFY = REDIS['caching'].get('INSECURE_SKIP_TLS_VERIFY', False) CACHING_REDIS_CA_CERT_PATH = REDIS['caching'].get('CA_CERT_PATH', False) +if CACHING_REDIS_PROTO == 'unix': + CACHING_REDIS_LOCATION_FROM_KEYS = f'unix://{CACHING_REDIS_USERNAME_HOST}?db={CACHING_REDIS_DATABASE}' +elif CACHING_REDIS_PROTO == 'rediss' or CACHING_REDIS_PROTO == 'redis': + CACHING_REDIS_LOCATION_FROM_KEYS = f'{CACHING_REDIS_PROTO}://{CACHING_REDIS_USERNAME_HOST}:{CACHING_REDIS_PORT}/CACHING_REDIS_DATABASE}' +else: + raise ImproperlyConfigured( + "Unknown PROTO for REDIS 'caching' subsection in configuration.py" + ) + +CACHING_REDIS_LOCATION = REDIS['caching'].get('LOCATION', CACHING_REDIS_LOCATION_FROM_KEYS) +CACHING_REDIS_OPTIONS = { + 'CLIENT_CLASS': 'django_redis.client.DefaultClient', + 'PASSWORD': CACHING_REDIS_PASSWORD, +} + CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache', - 'LOCATION': f'{CACHING_REDIS_PROTO}://{CACHING_REDIS_USERNAME_HOST}:{CACHING_REDIS_PORT}/{CACHING_REDIS_DATABASE}', - 'OPTIONS': { - 'CLIENT_CLASS': 'django_redis.client.DefaultClient', - 'PASSWORD': CACHING_REDIS_PASSWORD, - } + 'LOCATION': CACHING_REDIS_LOCATION, + 'OPTIONS': CACHING_REDIS_OPTIONS, } } @@ -687,6 +702,10 @@ if TASKS_REDIS_USING_SENTINEL: 'socket_connect_timeout': TASKS_REDIS_SENTINEL_TIMEOUT }, } +elif TASKS_REDIS_LOCATION: + RQ_PARAMS = { + 'URL': TASKS_REDIS_LOCATION, + } else: RQ_PARAMS = { 'HOST': TASKS_REDIS_HOST,