310 lines
7.5 KiB
Python
Executable File
310 lines
7.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
#KAN: 29/09/2026
|
|
#KOI: permettre de lancer des actions pour les orga depuis paheko
|
|
#KI: fab
|
|
|
|
#structure:
|
|
#
|
|
#/kaz/
|
|
#├── bin/
|
|
#│ ├── worker.py
|
|
#│ └── worker_actions/
|
|
#│ ├── __init__.py
|
|
#│ ├── modifier_services.py
|
|
#│ └── definir_quota.py
|
|
#└── jobs/
|
|
# ├── job-123-ABCD.json
|
|
# ├── job-789-HIJS.json.encours
|
|
# ├── job-456-EFGH.json.OK
|
|
# ├── job-089-LMNO.json.KO
|
|
# └── ...
|
|
|
|
import glob
|
|
import importlib
|
|
import json
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import urllib.request
|
|
|
|
|
|
BASE_DIR = "/kaz/bin"
|
|
JOBS_DIR = "/kaz/jobs"
|
|
|
|
if BASE_DIR not in sys.path:
|
|
sys.path.insert(0, BASE_DIR)
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
# LOG
|
|
# ----------------------------------------------------------------------
|
|
|
|
LOG_DIR = "/kaz/log"
|
|
LOG_FILE = os.path.join(LOG_DIR, "worker.log")
|
|
|
|
os.makedirs(LOG_DIR, exist_ok=True)
|
|
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format="%(asctime)s %(levelname)s %(message)s",
|
|
datefmt="%Y-%m-%d %H:%M:%S",
|
|
handlers=[
|
|
logging.FileHandler(LOG_FILE, encoding="utf-8"),
|
|
logging.StreamHandler(sys.stdout),
|
|
],
|
|
)
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
# ----------------------------------------------------------------------
|
|
# ENVOI D'UN MESSAGE MATTERMOST
|
|
# ----------------------------------------------------------------------
|
|
|
|
def send_mattermost(message):
|
|
|
|
url_agora = "agora.kaz.bzh"
|
|
|
|
result = subprocess.run(
|
|
[
|
|
"bash",
|
|
"-c",
|
|
". /kaz/secret/env-mattermostAdmin && "
|
|
"printf '%s' \"$token_webhook\""
|
|
],
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
|
|
token_webhook = result.stdout
|
|
|
|
url = f"https://{url_agora}/hooks/{token_webhook}"
|
|
|
|
payload = json.dumps({
|
|
"channel": "creation-comptes",
|
|
"text": message,
|
|
}).encode("utf-8")
|
|
|
|
request = urllib.request.Request(
|
|
url,
|
|
data=payload,
|
|
headers={
|
|
"Content-Type": "application/json",
|
|
},
|
|
method="POST",
|
|
)
|
|
|
|
with urllib.request.urlopen(request) as response:
|
|
|
|
if response.status < 200 or response.status >= 300:
|
|
raise RuntimeError(
|
|
f"Erreur Mattermost : HTTP {response.status}"
|
|
)
|
|
|
|
# ----------------------------------------------------------------------
|
|
# ENVOI DU MAIL
|
|
# ----------------------------------------------------------------------
|
|
|
|
def send_mail(mail_file, emails):
|
|
|
|
if not emails:
|
|
log.info("Aucun destinataire de mail.")
|
|
return
|
|
|
|
if not os.path.isfile(mail_file):
|
|
log.info(f"Aucun mail à envoyer : {mail_file}")
|
|
return
|
|
|
|
with open(mail_file, "r", encoding="utf-8") as f:
|
|
mail = f.read()
|
|
|
|
if not mail.strip():
|
|
log.info(f"Le fichier mail est vide : {mail_file}")
|
|
return
|
|
|
|
#PROD
|
|
#recipients = [email.strip() for email in emails if email.strip()]
|
|
#TEST
|
|
recipients = ["fab@kaz.bzh"]
|
|
|
|
if not recipients:
|
|
log.info("Aucun destinataire de mail valide.")
|
|
return
|
|
|
|
#TEST
|
|
annonce = (
|
|
"#################################################\n"
|
|
"Pendant quelques temps, contact@kaz.bzh va recevoir les mails de modification des services.\n"
|
|
"Vérifier le contenu du mail et si OK, le transférer à :\n"
|
|
+ "\n".join(emails)
|
|
+ "\n"
|
|
"En supprimant bien sûr cette annonce.\n"
|
|
"Plus tard, le mail partira directement, aussi, il faut bien le valider.\n"
|
|
"#################################################\n"
|
|
"\n"
|
|
)
|
|
mail = annonce + mail
|
|
#FIN TEST
|
|
|
|
message = (
|
|
"From: contact@kaz.bzh\n"
|
|
f"To: {', '.join(recipients)}\n"
|
|
"Subject: KAZ - informations\n"
|
|
"Content-Type: text/plain; charset=UTF-8\n"
|
|
"\n"
|
|
+ mail
|
|
)
|
|
|
|
log.info(f"Envoi du mail à : {', '.join(recipients)}")
|
|
|
|
result = subprocess.run(
|
|
["/usr/sbin/sendmail", "-t", "-i"],
|
|
input=message,
|
|
text=True,
|
|
capture_output=True,
|
|
)
|
|
|
|
if result.returncode != 0:
|
|
raise RuntimeError(
|
|
f"sendmail a échoué avec le code {result.returncode}: "
|
|
f"{result.stderr}"
|
|
)
|
|
|
|
log.info("Mail envoyé avec succès.")
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
# RECHERCHE D'UN JOB
|
|
# ----------------------------------------------------------------------
|
|
|
|
jobs = sorted(
|
|
glob.glob(
|
|
os.path.join(JOBS_DIR, "job-*.json")
|
|
)
|
|
)
|
|
|
|
if not jobs:
|
|
log.info("Aucun job à traiter.")
|
|
sys.exit(0)
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
# UN SEUL JOB
|
|
# ----------------------------------------------------------------------
|
|
|
|
job = jobs[0]
|
|
|
|
encours = job + ".encours"
|
|
ok = job + ".OK"
|
|
ko = job + ".KO"
|
|
mail_file = job + ".mail"
|
|
|
|
log.info(f"Job trouvé : {job}")
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
# PRISE EN CHARGE DU JOB
|
|
# ----------------------------------------------------------------------
|
|
|
|
try:
|
|
os.rename(job, encours)
|
|
|
|
except FileNotFoundError:
|
|
# Le fichier a disparu entre le glob() et le rename().
|
|
log.info(f"Job disparu entre temps : {job}")
|
|
sys.exit(0)
|
|
|
|
except OSError as e:
|
|
log.error(f"Impossible de prendre le job en charge : {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
log.info(f"Job en cours : {encours}")
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
# LECTURE DU JSON
|
|
# ----------------------------------------------------------------------
|
|
|
|
try:
|
|
|
|
with open(encours, "r", encoding="utf-8") as f:
|
|
message = json.load(f)
|
|
|
|
log.info(f"Message : {message}")
|
|
|
|
action = message.get("action")
|
|
|
|
if not action:
|
|
raise ValueError("Le champ 'action' est absent du JSON")
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
# CHARGEMENT ET EXECUTION DE L'ACTION
|
|
# ------------------------------------------------------------------
|
|
|
|
log.info(f"Action demandée : {action}")
|
|
|
|
module = importlib.import_module(
|
|
f"worker_actions.{action}"
|
|
)
|
|
|
|
module.run(message, encours)
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
# ENVOI DU MAIL
|
|
# ------------------------------------------------------------------
|
|
|
|
send_mail(
|
|
mail_file,
|
|
message.get("emails", [])
|
|
)
|
|
|
|
# if os.path.isfile(mail_file):
|
|
# os.remove(mail_file)
|
|
# log.info(f"Fichier mail supprimé : {mail_file}")
|
|
|
|
# ------------------------------------------------------------------
|
|
# ENVOI DU MSG MM
|
|
# ------------------------------------------------------------------
|
|
|
|
message_mattermost = json.dumps(
|
|
message,
|
|
indent=2,
|
|
ensure_ascii=False
|
|
)
|
|
send_mattermost(message_mattermost)
|
|
|
|
# ------------------------------------------------------------------
|
|
# SUCCES
|
|
# ------------------------------------------------------------------
|
|
|
|
os.rename(encours, ok)
|
|
|
|
log.info(f"Job terminé avec succès : {ok}")
|
|
|
|
|
|
# ----------------------------------------------------------------------
|
|
# ERREUR
|
|
# ----------------------------------------------------------------------
|
|
|
|
except Exception as e:
|
|
|
|
log.exception(
|
|
f"Erreur lors du traitement du job : {e}"
|
|
)
|
|
|
|
try:
|
|
os.rename(encours, ko)
|
|
log.info(f"Job marqué KO : {ko}")
|
|
|
|
except OSError as rename_error:
|
|
log.error(
|
|
f"Impossible de renommer le job en .KO : {rename_error}"
|
|
)
|
|
|
|
sys.exit(1)
|