From 87e2bc7b5144f48d18ea2558b31774c13ac80cf6 Mon Sep 17 00:00:00 2001 From: Michel Date: Mon, 8 Jun 2026 10:44:38 +0200 Subject: [PATCH] Refonte sauvegarde MariaDB NAS => VPS2 --- .env | 12 ++-- app/Test_MariaDB.py | 13 ++++ app/supervisor_watchdog.py | 114 +++++++++++++++++++++++++++------- scripts/check_backup_mysql.py | 62 ++++++++++++++++++ scripts/dump_mysql_local.sh | 21 +++++++ scripts/test_mail.py | 93 +++++++++++++++++++++++++++ 6 files changed, 289 insertions(+), 26 deletions(-) create mode 100644 scripts/test_mail.py diff --git a/.env b/.env index cfb3bd0..0787a70 100644 --- a/.env +++ b/.env @@ -58,15 +58,19 @@ ALERT_LOOKBACK_MINUTES=120 # Logs LOGLEVEL=INFO -# paramètres mail -SMTP_HOST=ssl0.ovh.net +# paramètres mail Synology MailPlus +SMTP_HOST=mail.mj91.fr SMTP_PORT=465 SMTP_SECURITY=SSL -SMTP_USER=services@domo91.fr -SMTP_PASS=VHq3278YA#sGV*bh#mR + +SMTP_USER=services +SMTP_PASS=NOUVEAU_MOT_DE_PASSE_SERVICES + MAIL_FROM=services@domo91.fr MAIL_TO=robots@domo91.fr + MAIL_TO_SACLAY=robots@domo91.fr,nicolas.thibaut@bw-paris-saclay.com MAIL_FROM_SACLAY="DOMO91 Saclay " + MAIL_TO_MEUDON=robots@domo91.fr,chef@parismeudonermitage.com MAIL_FROM_MEUDON="DOMO91 Meudon " \ No newline at end of file diff --git a/app/Test_MariaDB.py b/app/Test_MariaDB.py index e69de29..a947a4a 100644 --- a/app/Test_MariaDB.py +++ b/app/Test_MariaDB.py @@ -0,0 +1,13 @@ +import mysql.connector + +conn = mysql.connector.connect( + host="10.9.0.1", + port=3306, + user="Michel", + password="wuP^wu&6xjx61bh*kjS^", + database="Sondes" +) + +print("Connexion MariaDB OK via WireGuard") + +conn.close() \ No newline at end of file diff --git a/app/supervisor_watchdog.py b/app/supervisor_watchdog.py index 60e0b4e..eecc617 100644 --- a/app/supervisor_watchdog.py +++ b/app/supervisor_watchdog.py @@ -1,45 +1,115 @@ #!/home/debian/Gestion_sondes/myenv/bin/python +import os import subprocess import smtplib from email.mime.text import MIMEText from datetime import datetime +from pathlib import Path -heure_actuelle = datetime.now().strftime("%H:%M") +BASE_DIR = Path('/home/debian/Gestion_sondes') +ENV_FILE = BASE_DIR / '.env' + + +def charger_env(path: Path) -> None: + """Charge simplement les variables d'un fichier .env sans dépendance externe.""" + if not path.exists(): + return + + with path.open('r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line or line.startswith('#') or '=' not in line: + continue + + key, value = line.split('=', 1) + key = key.strip() + value = value.strip().strip('"').strip("'") + os.environ.setdefault(key, value) + + +def lire_liste_mails(valeur: str) -> list[str]: + return [mail.strip() for mail in valeur.split(',') if mail.strip()] + + +charger_env(ENV_FILE) + +SMTP_HOST = os.getenv('SMTP_HOST', 'mail.mj91.fr') +SMTP_PORT = int(os.getenv('SMTP_PORT', '465')) +SMTP_SECURITY = os.getenv('SMTP_SECURITY', 'SSL').upper() +SMTP_USER = os.getenv('SMTP_USER', 'services') +SMTP_PASS = os.getenv('SMTP_PASS', '') +MAIL_FROM = os.getenv('MAIL_FROM', 'services@domo91.fr') +MAIL_TO = lire_liste_mails(os.getenv('MAIL_TO', 'services@domo91.fr')) + +heure_actuelle = datetime.now().strftime('%H:%M') etat_services = [] anomalies = [] try: - output = subprocess.check_output("sudo /usr/bin/supervisorctl status", shell=True, text=True) + output = subprocess.check_output( + 'sudo /usr/bin/supervisorctl status', + shell=True, + text=True, + stderr=subprocess.STDOUT, + ) + for line in output.splitlines(): parts = line.split() if len(parts) >= 2: nom, statut = parts[0], parts[1] - etat_services.append(f"{nom} ➤ {statut}") - if statut != "RUNNING": - anomalies.append(f"{nom} ➤ {statut}") + etat_services.append(f'{nom} ➤ {statut}') + if statut != 'RUNNING': + anomalies.append(f'{nom} ➤ {statut}') + except Exception as e: etat_services.append("❌ Impossible d'exécuter supervisorctl") - anomalies.append(f"Erreur : {e}") + anomalies.append(f'Erreur : {e}') -# Déclenchement mail si anomalie ou à 07:00 -envoyer_mail = bool(anomalies) or heure_actuelle == "07:00" +# Déclenchement mail si anomalie ou rapport quotidien à 07:00 +envoyer_mail = bool(anomalies) or heure_actuelle == '07:00' if envoyer_mail: - sujet = "⚠️ Alerte Supervisor" if anomalies else "✅ Rapport quotidien Supervisor" - intro = "🛑 Les services suivants ne sont pas en RUNNING :" if anomalies else "✅ Tous les services supervisés sont en RUNNING." - contenu = f"{intro}\n\n" + "\n".join(etat_services) + sujet = "Rapport Supervisor - anomalie detectee" if anomalies else "Rapport quotidien Supervisor" + intro = ( + '🛑 Les services suivants ne sont pas en RUNNING :' + if anomalies + else '✅ Tous les services supervisés sont en RUNNING.' + ) - msg = MIMEText(contenu) - msg["Subject"] = sujet - msg["From"] = "supervisor@domo91.fr" - msg["To"] = "services@domo91.fr" + contenu = ( + f'{intro}\n\n' + f'Date contrôle : {datetime.now().strftime("%d/%m/%Y %H:%M:%S")}\n\n' + + '\n'.join(etat_services) + ) - try: - with smtplib.SMTP_SSL("smtp.mail.ovh.net", 465) as server: - server.login("services@domo91.fr", "VHq3278YA#sGV*bh#mR") - server.sendmail(msg["From"], [msg["To"]], msg.as_string()) - print("📧 Mail envoyé.") - except Exception as e: - print(f"Erreur envoi mail : {e}") + msg = MIMEText(contenu, _charset='utf-8') + msg['Subject'] = sujet + msg['From'] = MAIL_FROM + msg['To'] = ', '.join(MAIL_TO) + + if not SMTP_PASS: + print('Erreur envoi mail : SMTP_PASS est vide dans le fichier .env') + else: + try: + if SMTP_SECURITY == 'SSL': + with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as server: + server.login(SMTP_USER, SMTP_PASS) + server.send_message(msg) + elif SMTP_SECURITY == 'STARTTLS': + with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server: + server.ehlo() + server.starttls() + server.ehlo() + server.login(SMTP_USER, SMTP_PASS) + server.send_message(msg) + else: + with smtplib.SMTP(SMTP_HOST, SMTP_PORT) as server: + server.login(SMTP_USER, SMTP_PASS) + server.send_message(msg) + + print('📧 Mail envoyé.') + + except Exception as e: + print(f'Erreur envoi mail : {e}') else: print("🕖 Aucun mail envoyé (tout est OK et ce n’est pas l’heure du rapport).") diff --git a/scripts/check_backup_mysql.py b/scripts/check_backup_mysql.py index e69de29..1196f99 100644 --- a/scripts/check_backup_mysql.py +++ b/scripts/check_backup_mysql.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# A mettre dans le dossier /home/debian/Gestion_sondes/scripts du VPS + + +from pathlib import Path +from datetime import datetime, timedelta +import sys + +BACKUP_DIR = Path("/home/debian/backup") +LOG_FILE = BACKUP_DIR / "check_backup_mysql.log" + +MAX_AGE_HOURS = 30 +MIN_SIZE_MB = 50 + + +def log(message): + ligne = f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {message}" + print(ligne) + with LOG_FILE.open("a", encoding="utf-8") as f: + f.write(ligne + "\n") + + +def main(): + if not BACKUP_DIR.exists(): + log(f"❌ Dossier introuvable : {BACKUP_DIR}") + sys.exit(1) + + fichiers = sorted( + BACKUP_DIR.glob("mysql_backup_*.sql"), + key=lambda p: p.stat().st_mtime, + reverse=True + ) + + if not fichiers: + log("❌ Aucun fichier de sauvegarde trouvé") + sys.exit(1) + + dernier = fichiers[0] + stat = dernier.stat() + + date_modif = datetime.fromtimestamp(stat.st_mtime) + age = datetime.now() - date_modif + taille_mb = stat.st_size / 1024 / 1024 + + log(f"🔎 Dernière sauvegarde : {dernier.name}") + log(f"🔎 Date : {date_modif.strftime('%Y-%m-%d %H:%M:%S')}") + log(f"🔎 Taille : {taille_mb:.1f} Mo") + + if age > timedelta(hours=MAX_AGE_HOURS): + log(f"❌ Sauvegarde trop ancienne : {age}") + sys.exit(1) + + if taille_mb < MIN_SIZE_MB: + log(f"❌ Sauvegarde trop petite : {taille_mb:.1f} Mo") + sys.exit(1) + + log("✅ Contrôle sauvegarde OK") + sys.exit(0) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/scripts/dump_mysql_local.sh b/scripts/dump_mysql_local.sh index e69de29..ab878e5 100644 --- a/scripts/dump_mysql_local.sh +++ b/scripts/dump_mysql_local.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# A mettre dans le dossier /home/debian/Gestion_sondes/scripts du VPS + +set -e + +BACKUP_DIR="/home/debian/backup" +DATE=$(date +"%Y-%m-%d_%H-%M") +FICHIER="mysql_backup_${DATE}.sql" + +mkdir -p "$BACKUP_DIR" + +echo "🔷 Démarrage dump MySQL : $(date)" +echo "🔷 Destination locale : $BACKUP_DIR/$FICHIER" + +mysqldump --all-databases > "$BACKUP_DIR/$FICHIER" + +echo "✅ Dump OK : $BACKUP_DIR/$FICHIER" + +python3 /home/debian/Gestion_sondes/scripts/check_backup_mysql.py + +find "$BACKUP_DIR" -name "mysql_backup_*.sql" -type f -mtime +30 -delete \ No newline at end of file diff --git a/scripts/test_mail.py b/scripts/test_mail.py new file mode 100644 index 0000000..5c165a6 --- /dev/null +++ b/scripts/test_mail.py @@ -0,0 +1,93 @@ +import smtplib +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart + +SMTP_SERVER = "mail.mj91.fr" # ou ton serveur SMTP Synology / OVH +SMTP_PORT = 587 # 587 avec STARTTLS, ou 465 en SSL +SMTP_USER = "services" # adresse expéditrice +SMTP_PASSWORD ="84Bf&c$$1Mx953s8!L2" +import smtplib +from email.mime.text import MIMEText +from email.mime.multipart import MIMEMultipart + +FROM_EMAIL = "services@domo91.fr" +TO_EMAIL = "robots@domo91.fr" + +msg = MIMEMultipart() +msg["From"] = FROM_EMAIL +msg["To"] = TO_EMAIL +msg["Subject"] = "Test mail depuis la VM" + +body = """ +Bonjour, + +Ceci est un test d'envoi de mail depuis la VM en SSH. + +Si tu reçois ce message, l'envoi SMTP fonctionne. + +Michel +""" + +msg.attach(MIMEText(body, "plain")) + +try: + print("Connexion au serveur SMTP...") + server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=20) + server.set_debuglevel(1) + + print("Démarrage TLS...") + server.starttls() + + print("Authentification...") + server.login(SMTP_USER, SMTP_PASSWORD) + + print("Envoi du message...") + server.sendmail(FROM_EMAIL, TO_EMAIL, msg.as_string()) + + server.quit() + print("✅ Mail envoyé avec succès") + +except Exception as e: + print("❌ Erreur lors de l'envoi :") + print(e) + +FROM_EMAIL = "services@domo91.fr" +TO_EMAIL = "robots@domo91.fr" + +msg = MIMEMultipart() +msg["From"] = FROM_EMAIL +msg["To"] = TO_EMAIL +msg["Subject"] = "Test mail depuis la VM" + +body = """ +Bonjour, + +Ceci est un test d'envoi de mail depuis la VM en SSH. + +Si tu reçois ce message, l'envoi SMTP fonctionne. + +Michel +""" + +msg.attach(MIMEText(body, "plain")) + +try: + print("Connexion au serveur SMTP...") + server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=20) + server.set_debuglevel(1) + + print("Démarrage TLS...") + server.starttls() + + print("Authentification...") + server.login(SMTP_USER, SMTP_PASSWORD) + + print("Envoi du message...") + server.sendmail(FROM_EMAIL, TO_EMAIL, msg.as_string()) + + server.quit() + print("✅ Mail envoyé avec succès") + +except Exception as e: + print("❌ Erreur lors de l'envoi :") + print(e)