feat: implement /update in BaseAgent (git pull + systemctl restart)

- _do_self_update(): git pull, skip restart if already up to date,
  send result back via MQTT reply_to before restarting (2s delay)
- _get_install_dir(): derive from config path
- _get_service_name(): from config or install dir basename

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-15 19:19:11 +00:00
parent f714e8ae8a
commit 88c963a28c
+72
View File
@@ -511,9 +511,81 @@ class BaseAgent(ABC):
all_agents = [a.agent_id for a in self.registry.all_agents()]
return f"Agents en ligne : {online}\nAgents connus : {all_agents}"
if cmd == "update":
return self._do_self_update(source_msg)
# Commandes custom de l'agent
return self.handle_custom_command(cmd, args, source_msg)
# ──────────────────────────────────────────────
# Mise à jour self
# ──────────────────────────────────────────────
def _get_install_dir(self) -> str:
"""Répertoire d'installation : parent du dossier config."""
return os.path.dirname(os.path.dirname(os.path.abspath(self._config_path)))
def _get_service_name(self) -> str:
"""Nom du service systemd : depuis config ou nom du répertoire d'install."""
return self.config.get("service_name") or os.path.basename(self._get_install_dir())
def _do_self_update(self, source_msg: Optional[Message] = None) -> str:
"""git pull → systemctl restart si des changements sont détectés."""
import subprocess
install_dir = self._get_install_dir()
service_name = self._get_service_name()
logger.info(f"[Update] git pull dans {install_dir} (service : {service_name})")
try:
result = subprocess.run(
["git", "pull"],
cwd=install_dir,
capture_output=True, text=True, timeout=60,
)
except Exception as e:
msg = f"[{self.agent_id}] ❌ git pull impossible : {e}"
self._send_update_reply(source_msg, msg)
return msg
if result.returncode != 0:
msg = f"[{self.agent_id}] ❌ git pull échoué :\n{result.stderr.strip()}"
self._send_update_reply(source_msg, msg)
return msg
stdout = result.stdout.strip()
if "Already up to date" in stdout:
msg = f"[{self.agent_id}] ✓ Déjà à jour — pas de redémarrage."
self._send_update_reply(source_msg, msg)
return msg
msg = (
f"[{self.agent_id}] ✓ Mis à jour :\n{stdout}\n"
f"Redémarrage du service {service_name}..."
)
self._send_update_reply(source_msg, msg)
# Restart différé pour laisser le temps au message MQTT d'être envoyé
def _restart():
import time
time.sleep(2)
try:
subprocess.run(["systemctl", "restart", service_name], timeout=30, check=True)
except Exception as e:
logger.error(f"[Update] Erreur restart {service_name} : {e}")
threading.Thread(target=_restart, daemon=True, name="update-restart").start()
return msg
def _send_update_reply(self, source_msg: Optional[Message], body: str):
"""Renvoie la réponse d'update à Nexus via MQTT si possible."""
if source_msg and source_msg.reply_to:
try:
self.mqtt.reply(source_msg, body)
except Exception as e:
logger.debug(f"[Update] Impossible d'envoyer la réponse : {e}")
# ──────────────────────────────────────────────
# Capacités
# ──────────────────────────────────────────────