diff --git a/app/services/prepatch_check_service.py b/app/services/prepatch_check_service.py index 45b2bc0..611c57d 100644 --- a/app/services/prepatch_check_service.py +++ b/app/services/prepatch_check_service.py @@ -131,12 +131,40 @@ def check_ssh(ctx: Dict[str, Any]) -> Dict[str, Any]: "message": "Pas de cible (DNS KO en amont)", "details": "", } + err = (ctx.get("ssh_error") or "").strip() + target = ctx.get("target") or "?" + + # Classification du type d'erreur (pour message actionnable) + err_low = err.lower() + if "no route to host" in err_low or "network is unreachable" in err_low: + msg = f"Réseau injoignable ({target}) — vérifier routage/firewall" + elif "connection timed out" in err_low or "timed out" in err_low: + msg = f"Timeout connexion vers {target} — port SSH 22 filtré ou hôte down" + elif "connection refused" in err_low: + msg = f"Port 22 refusé sur {target} — sshd arrêté ou bloqué" + elif "no matching" in err_low and ("kex" in err_low or "key exchange" in err_low or "host key" in err_low): + msg = f"Algos KEX incompatibles avec {target} — durcissement SSH" + elif "host key" in err_low or "hostkey" in err_low: + msg = f"Host key inconnue/changée pour {target} — known_hosts ?" + elif "permission denied" in err_low or "authentication failed" in err_low: + msg = f"Authentification refusée par {target} — vérifier user/clé/password" + elif "no authentication methods" in err_low: + msg = f"Aucune méthode d'auth acceptée par {target}" + elif "name or service not known" in err_low or "could not resolve" in err_low: + msg = f"DNS échoué côté SSH ({target})" + elif err: + msg = f"Échec SSH vers {target}" + else: + msg = f"Échec connexion SSH vers {target} (raison inconnue)" + + details = (err or "Pas d'exception capturée") + \ + "\nVérifier ssh_method/clé/PSMP/mot de passe dans Settings (section SSH)." return { "name": "ssh", "label": "Connexion SSH", "status": "ko", - "message": "Échec connexion SSH", - "details": "Vérifier ssh_method/clé/PSMP/mot de passe dans Settings.", + "message": msg, + "details": details, } @@ -315,14 +343,22 @@ def run_all_checks(hostname: str, row: Dict[str, Any] | None = None, only_set = set(only) if only else None target = _resolve(hostname) client = None + ssh_error = None + ssh_method = None if target and PARAMIKO_OK: try: client = _connect(target, hostname) + # _connect peut renvoyer un tuple (client, method) selon implem ; fallback : + if isinstance(client, tuple) and len(client) >= 1: + ssh_method = client[1] if len(client) > 1 else None + client = client[0] except Exception as e: log.warning(f"_connect raised on {hostname}: {e}") + ssh_error = f"{type(e).__name__}: {e}" client = None - ctx = {"hostname": hostname, "target": target, "client": client, "row": row or {}} + ctx = {"hostname": hostname, "target": target, "client": client, + "row": row or {}, "ssh_error": ssh_error, "ssh_method": ssh_method} results = [] for name, fn in CHECKS.items(): if only_set is not None and name not in only_set: