diff --git a/apps/jumpserver/settings/base.py b/apps/jumpserver/settings/base.py index 3c929e97a..7f9b88118 100644 --- a/apps/jumpserver/settings/base.py +++ b/apps/jumpserver/settings/base.py @@ -19,6 +19,16 @@ def exist_or_default(path, default): return path +def parse_sentinels_host(sentinels_host): + service_name, sentinels = None, None + try: + service_name, hosts = sentinels_host.split('/', 1) + sentinels = [tuple(h.split(':', 1)) for h in hosts.split(',')] + except Exception: + pass + return service_name, sentinels + + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) VERSION = const.VERSION BASE_DIR = const.BASE_DIR @@ -276,26 +286,44 @@ REDIS_SSL_CA = exist_or_default(os.path.join(CERTS_DIR, 'redis_ca.pem'), None) REDIS_SSL_CA = exist_or_default(os.path.join(CERTS_DIR, 'redis_ca.crt'), REDIS_SSL_CA) REDIS_SSL_REQUIRED = 'none' REDIS_USE_SSL = CONFIG.REDIS_USE_SSL - -REDIS_LOCATION_NO_DB = '%(protocol)s://:%(password)s@%(host)s:%(port)s/{}' % { - 'protocol': 'rediss' if REDIS_USE_SSL else 'redis', - 'password': CONFIG.REDIS_PASSWORD, - 'host': CONFIG.REDIS_HOST, - 'port': CONFIG.REDIS_PORT, +REDIS_PROTOCOL = 'rediss' if REDIS_USE_SSL else 'redis' +# Cache use sentinel +REDIS_SENTINELS_HOST = CONFIG.REDIS_SENTINELS_HOST +REDIS_SENTINEL_SERVICE_NAME, REDIS_SENTINELS = parse_sentinels_host(REDIS_SENTINELS_HOST) + +# Cache config +REDIS_OPTIONS = { + "REDIS_CLIENT_KWARGS": { + "health_check_interval": 30 + }, + "CONNECTION_POOL_KWARGS": { + 'ssl_cert_reqs': REDIS_SSL_REQUIRED, + "ssl_keyfile": REDIS_SSL_KEY, + "ssl_certfile": REDIS_SSL_CERT, + "ssl_ca_certs": REDIS_SSL_CA + } if REDIS_USE_SSL else {} } +if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: + REDIS_LOCATION_NO_DB = "%(protocol)s://%(service_name)s/{}" % { + 'protocol': REDIS_PROTOCOL, 'service_name': REDIS_SENTINEL_SERVICE_NAME, + } + REDIS_OPTIONS.update({ + 'CLIENT_CLASS': 'django_redis.client.SentinelClient', + 'SENTINELS': REDIS_SENTINELS, 'PASSWORD': CONFIG.REDIS_PASSWORD + }) + DJANGO_REDIS_CONNECTION_FACTORY = 'django_redis.pool.SentinelConnectionFactory' +else: + REDIS_LOCATION_NO_DB = '%(protocol)s://:%(password)s@%(host)s:%(port)s/{}' % { + 'protocol': REDIS_PROTOCOL, 'password': CONFIG.REDIS_PASSWORD, + 'host': CONFIG.REDIS_HOST, 'port': CONFIG.REDIS_PORT, + } + + REDIS_CACHE_DEFAULT = { 'BACKEND': 'redis_lock.django_cache.RedisCache', 'LOCATION': REDIS_LOCATION_NO_DB.format(CONFIG.REDIS_DB_CACHE), - 'OPTIONS': { - "REDIS_CLIENT_KWARGS": {"health_check_interval": 30}, - "CONNECTION_POOL_KWARGS": { - 'ssl_cert_reqs': REDIS_SSL_REQUIRED, - "ssl_keyfile": REDIS_SSL_KEY, - "ssl_certfile": REDIS_SSL_CERT, - "ssl_ca_certs": REDIS_SSL_CA - } if REDIS_USE_SSL else {} - } + 'OPTIONS': REDIS_OPTIONS } REDIS_CACHE_SESSION = dict(REDIS_CACHE_DEFAULT) REDIS_CACHE_SESSION['LOCATION'] = REDIS_LOCATION_NO_DB.format(CONFIG.REDIS_DB_SESSION) diff --git a/apps/jumpserver/settings/libs.py b/apps/jumpserver/settings/libs.py index 10f69cffd..bccd9ebb9 100644 --- a/apps/jumpserver/settings/libs.py +++ b/apps/jumpserver/settings/libs.py @@ -5,7 +5,8 @@ import ssl from .base import ( REDIS_SSL_CA, REDIS_SSL_CERT, REDIS_SSL_KEY, - REDIS_SSL_REQUIRED, REDIS_USE_SSL + REDIS_SSL_REQUIRED, REDIS_USE_SSL, + REDIS_SENTINEL_SERVICE_NAME, REDIS_SENTINELS, ) from ..const import CONFIG, PROJECT_DIR @@ -90,16 +91,24 @@ else: if REDIS_SSL_CERT and REDIS_SSL_KEY: redis_ssl.load_cert_chain(REDIS_SSL_CERT, REDIS_SSL_KEY) +REDIS_HOST = { + 'db': CONFIG.REDIS_DB_WS, + 'password': CONFIG.REDIS_PASSWORD or None, + 'ssl': redis_ssl, +} + +if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: + REDIS_HOST['sentinels'] = REDIS_SENTINELS + REDIS_HOST['master_name'] = REDIS_SENTINEL_SERVICE_NAME +else: + REDIS_HOST['address'] = (CONFIG.REDIS_HOST, CONFIG.REDIS_PORT) + + CHANNEL_LAYERS = { 'default': { 'BACKEND': 'common.cache.RedisChannelLayer', 'CONFIG': { - "hosts": [{ - 'address': (CONFIG.REDIS_HOST, CONFIG.REDIS_PORT), - 'db': CONFIG.REDIS_DB_WS, - 'password': CONFIG.REDIS_PASSWORD or None, - 'ssl': redis_ssl - }], + "hosts": [REDIS_HOST], }, }, } @@ -109,13 +118,22 @@ ASGI_APPLICATION = 'jumpserver.routing.application' CELERY_LOG_DIR = os.path.join(PROJECT_DIR, 'data', 'celery') # Celery using redis as broker -CELERY_BROKER_URL = '%(protocol)s://:%(password)s@%(host)s:%(port)s/%(db)s' % { - 'protocol': 'rediss' if REDIS_USE_SSL else 'redis', - 'password': CONFIG.REDIS_PASSWORD, - 'host': CONFIG.REDIS_HOST, - 'port': CONFIG.REDIS_PORT, - 'db': CONFIG.REDIS_DB_CELERY, -} +CELERY_BROKER_URL_FORMAT = '%(protocol)s://:%(password)s@%(host)s:%(port)s/%(db)s' +if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: + CELERY_BROKER_URL = ';'.join([CELERY_BROKER_URL_FORMAT % { + 'protocol': 'sentinel', 'password': CONFIG.REDIS_PASSWORD, + 'host': item[0], 'port': item[1], 'db': CONFIG.REDIS_DB_CELERY + } for item in REDIS_SENTINELS]) + CELERY_BROKER_TRANSPORT_OPTIONS = {"master_name": REDIS_SENTINEL_SERVICE_NAME} + CELERY_RESULT_BACKEND_TRANSPORT_OPTIONS = {"master_name": REDIS_SENTINEL_SERVICE_NAME} +else: + CELERY_BROKER_URL = CELERY_BROKER_URL_FORMAT % { + 'protocol': 'rediss' if REDIS_USE_SSL else 'redis', + 'password': CONFIG.REDIS_PASSWORD, + 'host': CONFIG.REDIS_HOST, + 'port': CONFIG.REDIS_PORT, + 'db': CONFIG.REDIS_DB_CELERY, + } CELERY_TASK_SERIALIZER = 'pickle' CELERY_RESULT_SERIALIZER = 'pickle' CELERY_RESULT_BACKEND = CELERY_BROKER_URL diff --git a/utils/start_celery_beat.py b/utils/start_celery_beat.py index f6259ddcc..eabc0812b 100644 --- a/utils/start_celery_beat.py +++ b/utils/start_celery_beat.py @@ -6,7 +6,8 @@ import signal import subprocess import redis_lock -from redis import Redis + +from redis import Redis, Sentinel BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) APPS_DIR = os.path.join(BASE_DIR, 'apps') @@ -19,18 +20,29 @@ os.environ.setdefault('PYTHONOPTIMIZE', '1') if os.getuid() == 0: os.environ.setdefault('C_FORCE_ROOT', '1') -params = { - 'host': settings.REDIS_HOST, - 'port': settings.REDIS_PORT, +connection_params = { 'password': settings.REDIS_PASSWORD, - 'ssl': settings.REDIS_USE_SSL, - 'ssl_cert_reqs': settings.REDIS_SSL_REQUIRED, - 'ssl_keyfile': settings.REDIS_SSL_KEY, - 'ssl_certfile': settings.REDIS_SSL_CERT, - 'ssl_ca_certs': settings.REDIS_SSL_CA } -print("Pamras: ", params) -redis = Redis(**params) + +if settings.REDIS_USE_SSL: + connection_params['ssl'] = settings.REDIS_USE_SSL + connection_params['ssl_cert_reqs'] = settings.REDIS_SSL_REQUIRED + connection_params['ssl_keyfile'] = settings.REDIS_SSL_KEY + connection_params['ssl_certfile'] = settings.REDIS_SSL_CERT + connection_params['ssl_ca_certs'] = settings.REDIS_SSL_CA + +REDIS_SENTINEL_SERVICE_NAME = settings.REDIS_SENTINEL_SERVICE_NAME +REDIS_SENTINELS = settings.REDIS_SENTINELS +if REDIS_SENTINEL_SERVICE_NAME and REDIS_SENTINELS: + connection_params['sentinels'] = REDIS_SENTINELS + sentinel_client = Sentinel(**connection_params) + redis_client = sentinel_client.master_for(REDIS_SENTINEL_SERVICE_NAME) +else: + connection_params['host'] = settings.REDIS_HOST + connection_params['port'] = settings.REDIS_PORT + redis_client = Redis(**connection_params) +print("Connection params: ", connection_params) + scheduler = "django_celery_beat.schedulers:DatabaseScheduler" processes = [] cmd = [ @@ -52,7 +64,7 @@ def main(): # 父进程结束通知子进程结束 signal.signal(signal.SIGTERM, stop_beat_process) - with redis_lock.Lock(redis, name="beat-distribute-start-lock", expire=60, auto_renewal=True): + with redis_lock.Lock(redis_client, name="beat-distribute-start-lock", expire=60, auto_renewal=True): print("Get beat lock start to run it") process = subprocess.Popen(cmd, cwd=APPS_DIR) processes.append(process)