Просмотр исходного кода

Merge pull request #4161 from dstarner/issue-3984-redis-sentinel-conn

Fixes #3984: Allow for Redis Sentinel Connection Configuration
Jeremy Stretch 6 лет назад
Родитель
Сommit
fafcdf7def

+ 42 - 0
docs/configuration/required-settings.md

@@ -88,6 +88,48 @@ REDIS = {
     It is highly recommended to keep the webhook and cache databases separate. Using the same database number on the
     same Redis instance for both may result in webhook processing data being lost during cache flushing events.
 
+### 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 
+above and the addition of two new keys.
+
+* `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
+
+Example:
+
+```python
+REDIS = {
+    'webhooks': {
+        'SENTINELS': [('mysentinel.redis.example.com', 6379)],
+        'SENTINEL_SERVICE': 'netbox',
+        'PASSWORD': '',
+        'DATABASE': 0,
+        'DEFAULT_TIMEOUT': 300,
+        'SSL': False,
+    },
+    'caching': {
+        'SENTINELS': [
+            ('mysentinel.redis.example.com', 6379),
+            ('othersentinel.redis.example.com', 6379)
+        ],
+        'SENTINEL_SERVICE': 'netbox',
+        'PASSWORD': '',
+        'DATABASE': 1,
+        'DEFAULT_TIMEOUT': 300,
+        'SSL': False,
+    }
+}
+```
+
+!!! note:
+    It is possible to have only one or the other Redis configurations to use Sentinel functionality. It is possible
+    for example to have the webhook use sentinel via `HOST`/`PORT` and for caching to use Sentinel via 
+    `SENTINELS`/`SENTINEL_SERVICE`.
+
+
 ---
 
 ## SECRET_KEY

+ 6 - 0
netbox/netbox/configuration.example.py

@@ -28,6 +28,9 @@ REDIS = {
     'webhooks': {
         'HOST': 'localhost',
         'PORT': 6379,
+        # Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
+        # 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
+        # 'SENTINEL_SERVICE': 'netbox',
         'PASSWORD': '',
         'DATABASE': 0,
         'DEFAULT_TIMEOUT': 300,
@@ -36,6 +39,9 @@ REDIS = {
     'caching': {
         'HOST': 'localhost',
         'PORT': 6379,
+        # Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
+        # 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
+        # 'SENTINEL_SERVICE': 'netbox',
         'PASSWORD': '',
         'DATABASE': 1,
         'DEFAULT_TIMEOUT': 300,

+ 44 - 15
netbox/netbox/settings.py

@@ -170,14 +170,27 @@ if 'caching' not in REDIS:
 WEBHOOKS_REDIS = REDIS.get('webhooks', {})
 WEBHOOKS_REDIS_HOST = WEBHOOKS_REDIS.get('HOST', 'localhost')
 WEBHOOKS_REDIS_PORT = WEBHOOKS_REDIS.get('PORT', 6379)
+WEBHOOKS_REDIS_SENTINELS = WEBHOOKS_REDIS.get('SENTINELS', [])
+WEBHOOKS_REDIS_USING_SENTINEL = all([
+    isinstance(WEBHOOKS_REDIS_SENTINELS, (list, tuple)),
+    len(WEBHOOKS_REDIS_SENTINELS) > 0
+])
+WEBHOOKS_REDIS_SENTINEL_SERVICE = WEBHOOKS_REDIS.get('SENTINEL_SERVICE', 'default')
 WEBHOOKS_REDIS_PASSWORD = WEBHOOKS_REDIS.get('PASSWORD', '')
 WEBHOOKS_REDIS_DATABASE = WEBHOOKS_REDIS.get('DATABASE', 0)
 WEBHOOKS_REDIS_DEFAULT_TIMEOUT = WEBHOOKS_REDIS.get('DEFAULT_TIMEOUT', 300)
 WEBHOOKS_REDIS_SSL = WEBHOOKS_REDIS.get('SSL', False)
 
+
 CACHING_REDIS = REDIS.get('caching', {})
 CACHING_REDIS_HOST = CACHING_REDIS.get('HOST', 'localhost')
 CACHING_REDIS_PORT = CACHING_REDIS.get('PORT', 6379)
+CACHING_REDIS_SENTINELS = CACHING_REDIS.get('SENTINELS', [])
+CACHING_REDIS_USING_SENTINEL = all([
+    isinstance(CACHING_REDIS_SENTINELS, (list, tuple)),
+    len(CACHING_REDIS_SENTINELS) > 0
+])
+CACHING_REDIS_SENTINEL_SERVICE = CACHING_REDIS.get('SENTINEL_SERVICE', 'default')
 CACHING_REDIS_PASSWORD = CACHING_REDIS.get('PASSWORD', '')
 CACHING_REDIS_DATABASE = CACHING_REDIS.get('DATABASE', 0)
 CACHING_REDIS_DEFAULT_TIMEOUT = CACHING_REDIS.get('DEFAULT_TIMEOUT', 300)
@@ -394,28 +407,35 @@ if LDAP_CONFIG is not None:
 #
 # Caching
 #
-
-if CACHING_REDIS_SSL:
-    REDIS_CACHE_CON_STRING = 'rediss://'
+if CACHING_REDIS_USING_SENTINEL:
+    CACHEOPS_SENTINEL = {
+        'locations': CACHING_REDIS_SENTINELS,
+        'service_name': CACHING_REDIS_SENTINEL_SERVICE,
+        'db': CACHING_REDIS_DATABASE,
+    }
 else:
-    REDIS_CACHE_CON_STRING = 'redis://'
-
-if CACHING_REDIS_PASSWORD:
-    REDIS_CACHE_CON_STRING = '{}:{}@'.format(REDIS_CACHE_CON_STRING, CACHING_REDIS_PASSWORD)
-
-REDIS_CACHE_CON_STRING = '{}{}:{}/{}'.format(
-    REDIS_CACHE_CON_STRING,
-    CACHING_REDIS_HOST,
-    CACHING_REDIS_PORT,
-    CACHING_REDIS_DATABASE
-)
+    if CACHING_REDIS_SSL:
+        REDIS_CACHE_CON_STRING = 'rediss://'
+    else:
+        REDIS_CACHE_CON_STRING = 'redis://'
+
+    if CACHING_REDIS_PASSWORD:
+        REDIS_CACHE_CON_STRING = '{}:{}@'.format(REDIS_CACHE_CON_STRING, CACHING_REDIS_PASSWORD)
+
+    REDIS_CACHE_CON_STRING = '{}{}:{}/{}'.format(
+        REDIS_CACHE_CON_STRING,
+        CACHING_REDIS_HOST,
+        CACHING_REDIS_PORT,
+        CACHING_REDIS_DATABASE
+    )
+    CACHEOPS_REDIS = REDIS_CACHE_CON_STRING
 
 if not CACHE_TIMEOUT:
     CACHEOPS_ENABLED = False
 else:
     CACHEOPS_ENABLED = True
 
-CACHEOPS_REDIS = REDIS_CACHE_CON_STRING
+
 CACHEOPS_DEFAULTS = {
     'timeout': CACHE_TIMEOUT
 }
@@ -534,6 +554,15 @@ RQ_QUEUES = {
         'PASSWORD': WEBHOOKS_REDIS_PASSWORD,
         'DEFAULT_TIMEOUT': WEBHOOKS_REDIS_DEFAULT_TIMEOUT,
         'SSL': WEBHOOKS_REDIS_SSL,
+    } if not WEBHOOKS_REDIS_USING_SENTINEL else {
+        'SENTINELS': WEBHOOKS_REDIS_SENTINELS,
+        'MASTER_NAME': WEBHOOKS_REDIS_SENTINEL_SERVICE,
+        'DB': WEBHOOKS_REDIS_DATABASE,
+        'PASSWORD': WEBHOOKS_REDIS_PASSWORD,
+        'SOCKET_TIMEOUT': None,
+        'CONNECTION_KWARGS': {
+            'socket_connect_timeout': WEBHOOKS_REDIS_DEFAULT_TIMEOUT
+        },
     }
 }