Gate watchdogs on integration configuration
This commit is contained in:
parent
947225fe0d
commit
4b62583937
6 changed files with 129 additions and 18 deletions
|
|
@ -50,6 +50,21 @@ def _check_database():
|
|||
return {'connected': False, 'error': str(e)}
|
||||
|
||||
|
||||
def _check_integration_watchdog(process_name, integration, start_time_threshold=None):
|
||||
"""Un watchdog non configure est volontairement arrete et reste sain."""
|
||||
try:
|
||||
from watchdog_gate import integration_is_configured
|
||||
|
||||
if not integration_is_configured(integration):
|
||||
return {'running': False, 'enabled': False}
|
||||
except Exception as exc:
|
||||
return {'running': False, 'enabled': False, 'configuration_error': str(exc)}
|
||||
|
||||
status = _check_watchdog(process_name, start_time_threshold=start_time_threshold)
|
||||
status['enabled'] = True
|
||||
return status
|
||||
|
||||
|
||||
@health_bp.route('/')
|
||||
def health():
|
||||
"""Endpoint public de healthcheck."""
|
||||
|
|
@ -58,14 +73,18 @@ def health():
|
|||
# Le watchdog pronote met parfois plus de temps a demarrer (connexion ENT)
|
||||
watchdogs = {
|
||||
'flask': _check_watchdog('gunicorn'),
|
||||
'gmao_watchdog': _check_watchdog('gmao_watchdog.py'),
|
||||
'ent_watchdog': _check_watchdog('ent_watchdog.py'),
|
||||
'pronote_watchdog': _check_watchdog('pronote_watchdog.py', start_time_threshold=WATCHDOG_STARTUP_GRACE_SECONDS),
|
||||
'watchdog_dnd': _check_watchdog('watchdog_dnd.py'),
|
||||
'gmao_watchdog': _check_integration_watchdog('gmao_watchdog.py', 'outlook'),
|
||||
'ent_watchdog': _check_integration_watchdog('ent_watchdog.py', 'ent'),
|
||||
'pronote_watchdog': _check_integration_watchdog(
|
||||
'pronote_watchdog.py',
|
||||
'pronote',
|
||||
start_time_threshold=WATCHDOG_STARTUP_GRACE_SECONDS,
|
||||
),
|
||||
'watchdog_dnd': _check_integration_watchdog('watchdog_dnd.py', 'yeastar'),
|
||||
}
|
||||
|
||||
all_watchdogs_ok = all(
|
||||
w.get('running') or w.get('starting')
|
||||
w.get('enabled') is False or w.get('running') or w.get('starting')
|
||||
for w in watchdogs.values()
|
||||
)
|
||||
healthy = db_status.get('connected') and all_watchdogs_ok and not any(w.get('starting') for w in watchdogs.values())
|
||||
|
|
|
|||
|
|
@ -722,13 +722,13 @@ def api_save_auto_interpret():
|
|||
if gmao_context.auto_interpret_enabled:
|
||||
# Relancer GMAO watchdog
|
||||
gmao_script = '/app/gmao_watchdog.py'
|
||||
subprocess.Popen(['python3', gmao_script],
|
||||
subprocess.Popen(['python3', '/app/watchdog_gate.py', 'outlook', gmao_script],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
# Relancer ENT watchdog
|
||||
ent_script = '/app/ent_watchdog.py'
|
||||
subprocess.Popen(['python3', ent_script],
|
||||
subprocess.Popen(['python3', '/app/watchdog_gate.py', 'ent', ent_script],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
|
|
@ -913,7 +913,7 @@ def api_pronote_watchdog_restart():
|
|||
|
||||
# Démarrer le nouveau
|
||||
subprocess.Popen(
|
||||
['python3', 'pronote_watchdog.py'],
|
||||
['python3', '/app/watchdog_gate.py', 'pronote', '/app/pronote_watchdog.py'],
|
||||
cwd=workdir,
|
||||
stdout=open('/tmp/pronote_watchdog.out', 'a'),
|
||||
stderr=open('/tmp/pronote_watchdog.err', 'a')
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ def dnd_config_page():
|
|||
pass
|
||||
if config.is_enabled:
|
||||
script_path = '/app/watchdog_dnd.py'
|
||||
subprocess.Popen(['python3', script_path],
|
||||
subprocess.Popen(['python3', '/app/watchdog_gate.py', 'yeastar', script_path],
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
|
||||
flash("Configuration DND sauvegardée", "success")
|
||||
|
|
@ -330,7 +330,7 @@ def api_watchdog_restart():
|
|||
|
||||
# Relancer
|
||||
script_path = '/app/watchdog_dnd.py'
|
||||
subprocess.Popen(['python3', script_path],
|
||||
subprocess.Popen(['python3', '/app/watchdog_gate.py', 'yeastar', script_path],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ services:
|
|||
- ./ent_watchdog.py:/app/ent_watchdog.py
|
||||
- ./pronote_watchdog.py:/app/pronote_watchdog.py
|
||||
- ./watchdog_dnd.py:/app/watchdog_dnd.py
|
||||
- ./watchdog_gate.py:/app/watchdog_gate.py:ro
|
||||
- ./run_app_new.py:/app/run_app_new.py
|
||||
- ./wsgi.py:/app/wsgi.py
|
||||
- ./VERSION:/app/VERSION:ro
|
||||
|
|
|
|||
|
|
@ -17,36 +17,36 @@ stderr_logfile=/dev/fd/2
|
|||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:gmao_watchdog]
|
||||
command=python3 /app/gmao_watchdog.py
|
||||
command=python3 /app/watchdog_gate.py outlook /app/gmao_watchdog.py
|
||||
environment=DOCKER_GMAO_WORKDIR="/app",DOCKER_GMAO_ENVFILE="/app/.env.docker",PYTHONPATH="/app",HOME="/home/gmao"
|
||||
directory=/app
|
||||
user=gmao
|
||||
autostart=true
|
||||
autorestart=true
|
||||
autorestart=false
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:ent_watchdog]
|
||||
command=python3 /app/ent_watchdog.py
|
||||
command=python3 /app/watchdog_gate.py ent /app/ent_watchdog.py
|
||||
environment=DOCKER_GMAO_WORKDIR="/app",DOCKER_GMAO_ENVFILE="/app/.env.docker",PYTHONPATH="/app",HOME="/home/gmao"
|
||||
directory=/app
|
||||
user=gmao
|
||||
autostart=true
|
||||
autorestart=true
|
||||
autorestart=false
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:pronote_watchdog]
|
||||
command=python3 /app/pronote_watchdog.py
|
||||
command=python3 /app/watchdog_gate.py pronote /app/pronote_watchdog.py
|
||||
environment=DOCKER_GMAO_WORKDIR="/app",DOCKER_GMAO_ENVFILE="/app/.env.docker",PYTHONPATH="/app",HOME="/home/gmao"
|
||||
directory=/app
|
||||
user=gmao
|
||||
autostart=true
|
||||
autorestart=true
|
||||
autorestart=false
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
|
|
@ -65,12 +65,12 @@ stderr_logfile=/dev/fd/2
|
|||
stderr_logfile_maxbytes=0
|
||||
|
||||
[program:watchdog_dnd]
|
||||
command=python3 /app/watchdog_dnd.py
|
||||
command=python3 /app/watchdog_gate.py yeastar /app/watchdog_dnd.py
|
||||
environment=PYTHONPATH="/app",HOME="/home/gmao"
|
||||
directory=/app
|
||||
user=gmao
|
||||
autostart=true
|
||||
autorestart=true
|
||||
autorestart=false
|
||||
stdout_logfile=/dev/fd/1
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/fd/2
|
||||
|
|
|
|||
91
watchdog_gate.py
Normal file
91
watchdog_gate.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Start an integration watchdog only when its configuration is usable."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def integration_is_configured(name):
|
||||
import pymysql
|
||||
from sqlalchemy.engine import make_url
|
||||
|
||||
database_url = make_url(os.environ['DATABASE_URL'])
|
||||
connection = pymysql.connect(
|
||||
host=database_url.host,
|
||||
port=database_url.port or 3306,
|
||||
user=database_url.username,
|
||||
password=database_url.password,
|
||||
database=database_url.database,
|
||||
connect_timeout=5,
|
||||
)
|
||||
checks = {
|
||||
"outlook": """
|
||||
SELECT EXISTS(SELECT 1 FROM gmao_context WHERE auto_interpret_enabled = 1)
|
||||
AND EXISTS(SELECT 1 FROM outlook_accounts WHERE is_active = 1)
|
||||
""",
|
||||
"ent": """
|
||||
SELECT EXISTS(SELECT 1 FROM gmao_context WHERE auto_interpret_enabled = 1)
|
||||
AND EXISTS(SELECT 1 FROM ent_credentials WHERE is_active = 1)
|
||||
""",
|
||||
"pronote": """
|
||||
SELECT EXISTS(SELECT 1 FROM gmao_context WHERE pronote_sync_enabled = 1)
|
||||
AND EXISTS(
|
||||
SELECT 1 FROM pronote_session
|
||||
WHERE session_token IS NOT NULL AND session_token != ''
|
||||
)
|
||||
""",
|
||||
"yeastar": """
|
||||
SELECT username_encrypted, password_encrypted
|
||||
FROM yeastar_config
|
||||
WHERE is_active = 1 AND base_url != ''
|
||||
AND EXISTS(SELECT 1 FROM yeastar_dnd_config WHERE is_enabled = 1)
|
||||
LIMIT 1
|
||||
""",
|
||||
}
|
||||
if name not in checks:
|
||||
raise ValueError(f"Integration inconnue: {name}")
|
||||
try:
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute(checks[name])
|
||||
result = cursor.fetchone()
|
||||
if name != "yeastar":
|
||||
return bool(result and result[0])
|
||||
if not result:
|
||||
return False
|
||||
from cryptography.fernet import Fernet
|
||||
|
||||
key = os.environ.get('YEASTAR_ENCRYPTION_KEY') or os.environ.get(
|
||||
'OUTLOOK_ENCRYPTION_KEY'
|
||||
)
|
||||
if not key:
|
||||
return False
|
||||
try:
|
||||
cipher = Fernet(key.encode())
|
||||
return bool(cipher.decrypt(result[0]) and cipher.decrypt(result[1]))
|
||||
except Exception:
|
||||
return False
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
raise SystemExit("usage: watchdog_gate.py INTEGRATION SCRIPT")
|
||||
|
||||
integration, script = sys.argv[1:]
|
||||
try:
|
||||
configured = integration_is_configured(integration)
|
||||
except Exception as exc:
|
||||
print(f"[{integration}] watchdog non lance: configuration illisible ({exc})")
|
||||
return 0
|
||||
|
||||
if not configured:
|
||||
print(f"[{integration}] watchdog non lance: integration non configuree")
|
||||
return 0
|
||||
|
||||
print(f"[{integration}] configuration valide, lancement de {script}")
|
||||
os.execv(sys.executable, [sys.executable, script])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Reference in a new issue