""" Utilitaire : vérification et application des mises à jour git pour les agents. Fonctions appelées directement depuis agent1.py (pas de trigger LLM). check_update(name, install_path, branch, ssh_host, ssh_user) do_upgrade(name, install_path, service, branch, ssh_host, ssh_user, self_upgrade) Si ssh_host est défini, les commandes sont exécutées via SSH sur la machine distante. """ import subprocess import shlex from pathlib import Path def _run_local(cmd: str, cwd: str = None, timeout: int = 30) -> tuple: """Lance une commande locale, retourne (stdout, stderr, returncode).""" try: result = subprocess.run( shlex.split(cmd), cwd=cwd, capture_output=True, text=True, timeout=timeout ) return result.stdout.strip(), result.stderr.strip(), result.returncode except subprocess.TimeoutExpired: return "", "Timeout ({} s)".format(timeout), -1 except Exception as e: return "", str(e), -1 def _run_ssh(cmd: str, ssh_host: str, ssh_user: str = "root", cwd: str = None, timeout: int = 30) -> tuple: """Lance une commande via SSH, retourne (stdout, stderr, returncode).""" if cwd: cmd = "cd {} && {}".format(cwd, cmd) ssh_cmd = "sshpass -p 'Matador3721' ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 {}@{} {}".format( ssh_user, ssh_host, shlex.quote(cmd)) try: result = subprocess.run( shlex.split(ssh_cmd), capture_output=True, text=True, timeout=timeout ) return result.stdout.strip(), result.stderr.strip(), result.returncode except subprocess.TimeoutExpired: return "", "Timeout SSH ({} s)".format(timeout), -1 except Exception as e: return "", str(e), -1 def _run(cmd: str, cwd: str = None, timeout: int = 30, ssh_host: str = None, ssh_user: str = "root") -> tuple: """Dispatche local ou SSH selon ssh_host.""" if ssh_host: return _run_ssh(cmd, ssh_host, ssh_user, cwd=cwd, timeout=timeout) return _run_local(cmd, cwd=cwd, timeout=timeout) def check_update(agent_name: str, install_path: str, branch: str = "main", ssh_host: str = None, ssh_user: str = "root") -> str: """ Vérifie si une mise à jour est disponible sur le dépôt distant. Effectue un git fetch puis compare HEAD avec origin/. """ remote = " [{}]".format(ssh_host) if ssh_host else "" # Vérifier que le répertoire existe if ssh_host: out, _, rc = _run("test -d {}".format(install_path), ssh_host=ssh_host, ssh_user=ssh_user) if rc != 0: return "[{}{}] Répertoire introuvable : {}".format( agent_name, remote, install_path) else: if not Path(install_path).is_dir(): return "[{}] Répertoire introuvable : {}".format(agent_name, install_path) # git fetch out, err, rc = _run("git fetch origin {}".format(branch), cwd=install_path, timeout=20, ssh_host=ssh_host, ssh_user=ssh_user) if rc != 0: return "[{}{}] Erreur git fetch : {}".format(agent_name, remote, err or out) # Compter les commits disponibles out, err, rc = _run( "git log HEAD..origin/{} --oneline".format(branch), cwd=install_path, ssh_host=ssh_host, ssh_user=ssh_user) if rc != 0: return "[{}{}] Erreur git log : {}".format(agent_name, remote, err or out) commits = [l for l in out.splitlines() if l.strip()] if not commits: return "[{}{}] Déjà à jour.".format(agent_name, remote) lines = ["[{}{}] {} commit(s) disponible(s) :".format( agent_name, remote, len(commits))] for c in commits[:10]: lines.append(" {}".format(c)) if len(commits) > 10: lines.append(" ... et {} autre(s)".format(len(commits) - 10)) lines.append("Lancez !agentUPGRADE {} pour appliquer.".format(agent_name)) return "\n".join(lines) def do_upgrade(agent_name: str, install_path: str, service_name: str, branch: str = "main", self_upgrade: bool = False, ssh_host: str = None, ssh_user: str = "root") -> str: """ Applique la mise à jour : git pull + systemctl restart. Pour agent1 (self_upgrade=True), retourne le message AVANT le restart. """ remote = " [{}]".format(ssh_host) if ssh_host else "" # Vérifier que le répertoire existe if ssh_host: _, _, rc = _run("test -d {}".format(install_path), ssh_host=ssh_host, ssh_user=ssh_user) if rc != 0: return "[{}{}] Répertoire introuvable : {}".format( agent_name, remote, install_path) else: if not Path(install_path).is_dir(): return "[{}] Répertoire introuvable : {}".format(agent_name, install_path) # git pull out, err, rc = _run( "git pull origin {}".format(branch), cwd=install_path, timeout=60, ssh_host=ssh_host, ssh_user=ssh_user) if rc != 0: return "[{}{}] Erreur git pull : {}".format(agent_name, remote, err or out) pull_msg = out or "Déjà à jour." if self_upgrade: return "[{}] {}\nRedémarrage en cours...".format(agent_name, pull_msg) # systemctl restart _, err, rc = _run("systemctl restart {}".format(service_name), timeout=15, ssh_host=ssh_host, ssh_user=ssh_user) if rc != 0: return "[{}{}] Pull OK mais restart échoué : {}".format( agent_name, remote, err) # Vérifier que le service est bien remonté out, _, _ = _run("systemctl is-active {}".format(service_name), timeout=5, ssh_host=ssh_host, ssh_user=ssh_user) state = out.strip() if state == "active": return "[{}{}] Mise à jour appliquée. Service actif.\n{}".format( agent_name, remote, pull_msg) else: return "[{}{}] Pull OK, service état : {}. Vérifiez les logs.".format( agent_name, remote, state)