diff --git a/agent1.py b/agent1.py index ca2fc24..4bc0537 100644 --- a/agent1.py +++ b/agent1.py @@ -226,12 +226,15 @@ def _get_agent_git_info(name: str) -> dict: "install_path": agent.get("install_path", default_path), "service_name": agent.get("service_name", default_service), "git_branch" : agent.get("git_branch", "main"), + "ssh_host" : agent.get("ssh_host"), + "ssh_user" : agent.get("ssh_user", "root"), } def _handle_update_one(name: str) -> str: from skills.agent_update import check_update info = _get_agent_git_info(name) - return check_update(name, info["install_path"], info["git_branch"]) + return check_update(name, info["install_path"], info["git_branch"], + info["ssh_host"], info["ssh_user"]) def _handle_update_all() -> str: from skills.agent_update import check_update @@ -242,7 +245,8 @@ def _handle_update_all() -> str: results = [] for name in registry: info = _get_agent_git_info(name) - results.append(check_update(name, info["install_path"], info["git_branch"])) + results.append(check_update(name, info["install_path"], info["git_branch"], + info["ssh_host"], info["ssh_user"])) return "\n\n".join(results) if results else "Aucun agent dans le registre." def _handle_upgrade_one(name: str) -> str: @@ -250,7 +254,8 @@ def _handle_upgrade_one(name: str) -> str: info = _get_agent_git_info(name) self_upgrade = (name == "agent1") msg = do_upgrade(name, info["install_path"], info["service_name"], - info["git_branch"], self_upgrade=self_upgrade) + info["git_branch"], self_upgrade=self_upgrade, + ssh_host=info["ssh_host"], ssh_user=info["ssh_user"]) if self_upgrade and "Redémarrage en cours" in msg: # Envoyer le message XMPP avant le restart if xmpp_bot: @@ -276,7 +281,8 @@ def _handle_upgrade_all() -> str: agent1_info = (name, info) # traiter en dernier continue msg = do_upgrade(name, info["install_path"], - info["service_name"], info["git_branch"]) + info["service_name"], info["git_branch"], + ssh_host=info["ssh_host"], ssh_user=info["ssh_user"]) results.append(msg) summary = "\n\n".join(results) if results else "Aucun agent mis à jour." diff --git a/config/agents_registry.json b/config/agents_registry.json index d36408a..329e4bb 100644 --- a/config/agents_registry.json +++ b/config/agents_registry.json @@ -4,7 +4,20 @@ "mqtt_inbox": "agents/agent2_debian13/inbox", "mqtt_outbox": "agents/agent1/inbox", "speciality": "Administration Debian : apt, dpkg, systemd, conteneurs LXC/Docker, KVM, réseau, sécurité système", - "work_hours": { "start": "07:00", "end": "23:00", "days": ["mon","tue","wed","thu","fri","sat","sun"], "enabled": true }, + "work_hours": { + "start": "07:00", + "end": "23:00", + "days": [ + "mon", + "tue", + "wed", + "thu", + "fri", + "sat", + "sun" + ], + "enabled": true + }, "install_path": "/opt/agent2_debian13", "service_name": "agent2_debian13", "git_branch": "main" @@ -14,7 +27,20 @@ "mqtt_inbox": "agents/agent2_ansible/inbox", "mqtt_outbox": "agents/agent1/inbox", "speciality": "Automatisation infrastructure via Ansible : playbooks, commandes ad-hoc, déploiement multi-hôtes, gestion de configuration sur le réseau local", - "work_hours": { "start": "07:00", "end": "23:00", "days": ["mon","tue","wed","thu","fri","sat","sun"], "enabled": true }, + "work_hours": { + "start": "07:00", + "end": "23:00", + "days": [ + "mon", + "tue", + "wed", + "thu", + "fri", + "sat", + "sun" + ], + "enabled": true + }, "install_path": "/opt/agent2_ansible", "service_name": "agent2_ansible", "git_branch": "main" @@ -24,7 +50,18 @@ "mqtt_inbox": "agents/agent2_deploy/inbox", "mqtt_outbox": "agents/agent1/inbox", "speciality": "Déploiement d'agents : installe et configure d'autres agents sur des machines distantes ou locales via SSH", - "work_hours": { "start": "08:00", "end": "20:00", "days": ["mon","tue","wed","thu","fri"], "enabled": true }, + "work_hours": { + "start": "08:00", + "end": "20:00", + "days": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "enabled": true + }, "install_path": "/opt/agent2_deploy", "service_name": "agent2_deploy", "git_branch": "main" @@ -33,7 +70,12 @@ "jid": "agent2_test@xmpp.ovh", "mqtt_inbox": "agents/agent2_test/inbox", "mqtt_outbox": "agents/agent1/inbox", - "speciality": "Spécialiste Debian : apt, systemd, conteneurs LXC/Docker, KVM, réseau, sécurité" + "speciality": "Administration Debian : apt, dpkg, systemd, conteneurs LXC/Docker, KVM, réseau, sécurité système", + "install_path": "/opt/agent2_test", + "service_name": "agent2_test", + "git_branch": "main", + "ssh_host": "192.168.7.13", + "ssh_user": "root" }, "agent1": { "jid": "agent1@xmpp.ovh", @@ -44,4 +86,4 @@ "service_name": "agent", "git_branch": "main" } -} +} \ No newline at end of file diff --git a/skills/agent_update.py b/skills/agent_update.py index 02f9ff7..2f00b6c 100644 --- a/skills/agent_update.py +++ b/skills/agent_update.py @@ -3,16 +3,18 @@ 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) → rapport git fetch - do_upgrade(name, install_path, service, branch) → git pull + systemctl restart + 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(cmd: str, cwd: str = None, timeout: int = 30) -> tuple: - """Lance une commande shell, retourne (stdout, stderr, returncode).""" +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), @@ -28,32 +30,74 @@ def _run(cmd: str, cwd: str = None, timeout: int = 30) -> tuple: return "", str(e), -1 -def check_update(agent_name: str, install_path: str, branch: str = "main") -> str: +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/. """ - path = install_path + remote = " [{}]".format(ssh_host) if ssh_host else "" - if not Path(path).is_dir(): - return "[{}] Répertoire introuvable : {}".format(agent_name, path) + # 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=path, timeout=20) + 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, err or out) + 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=path) + "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, err or out) + 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) + return "[{}{}] Déjà à jour.".format(agent_name, remote) - lines = ["[{}] {} commit(s) disponible(s) :".format(agent_name, len(commits))] + lines = ["[{}{}] {} commit(s) disponible(s) :".format( + agent_name, remote, len(commits))] for c in commits[:10]: lines.append(" {}".format(c)) if len(commits) > 10: @@ -64,38 +108,52 @@ def check_update(agent_name: str, install_path: str, branch: str = "main") -> st def do_upgrade(agent_name: str, install_path: str, service_name: str, branch: str = "main", - self_upgrade: bool = False) -> str: + 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), envoie la réponse AVANT le restart. + Pour agent1 (self_upgrade=True), retourne le message AVANT le restart. """ - path = install_path + remote = " [{}]".format(ssh_host) if ssh_host else "" - if not Path(path).is_dir(): - return "[{}] Répertoire introuvable : {}".format(agent_name, path) + # 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=path, timeout=60) + "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, err or out) + return "[{}{}] Erreur git pull : {}".format(agent_name, remote, err or out) pull_msg = out or "Déjà à jour." if self_upgrade: - # On retourne le message AVANT le restart (agent1 l'envoie puis se redémarre) - return "[{}] {} \nRedémarrage en cours...".format(agent_name, pull_msg) + return "[{}] {}\nRedémarrage en cours...".format(agent_name, pull_msg) # systemctl restart - _, err, rc = _run("systemctl restart {}".format(service_name), timeout=15) + _, 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, err) + 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) + 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, pull_msg) + 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, state) + return "[{}{}] Pull OK, service état : {}. Vérifiez les logs.".format( + agent_name, remote, state)