Spaces:
Sleeping
Sleeping
| import socket | |
| import paramiko | |
| from config import settings | |
| from utils.logger import logger | |
| def execute_ssh_command(command: str, timeout: int = 15) -> dict: | |
| """ | |
| Execute a shell command on the configured SSH Lab Node. | |
| Returns a dict with stdout, stderr, exit_code, and a formatted result string. | |
| """ | |
| if not settings.SSH_HOST or not settings.SSH_USER: | |
| return { | |
| "stdout": "", | |
| "stderr": "SSH Lab Node not configured. Set SSH_HOST and SSH_USER in Settings.", | |
| "exit_code": -1, | |
| "result": "[SSH ERROR] Lab node credentials are not configured." | |
| } | |
| client = paramiko.SSHClient() | |
| client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) | |
| try: | |
| client.connect( | |
| hostname=settings.SSH_HOST, | |
| port=settings.SSH_PORT, | |
| username=settings.SSH_USER, | |
| password=settings.SSH_PASSWORD, | |
| timeout=timeout, | |
| look_for_keys=False, | |
| allow_agent=False | |
| ) | |
| _, stdout, stderr = client.exec_command(command, timeout=timeout) | |
| exit_code = stdout.channel.recv_exit_status() | |
| out = stdout.read().decode("utf-8", errors="replace").strip() | |
| err = stderr.read().decode("utf-8", errors="replace").strip() | |
| result_parts = [] | |
| if out: | |
| result_parts.append(f"stdout:\n{out}") | |
| if err: | |
| result_parts.append(f"stderr:\n{err}") | |
| result_parts.append(f"exit_code: {exit_code}") | |
| return { | |
| "stdout": out, | |
| "stderr": err, | |
| "exit_code": exit_code, | |
| "result": "\n".join(result_parts) if result_parts else "(no output)" | |
| } | |
| except (paramiko.AuthenticationException, paramiko.SSHException) as e: | |
| msg = f"[SSH AUTH ERROR] {e}" | |
| logger.error(msg) | |
| return {"stdout": "", "stderr": str(e), "exit_code": -1, "result": msg} | |
| except socket.timeout: | |
| msg = f"[SSH TIMEOUT] Connection to {settings.SSH_HOST}:{settings.SSH_PORT} timed out." | |
| logger.error(msg) | |
| return {"stdout": "", "stderr": "timeout", "exit_code": -1, "result": msg} | |
| except Exception as e: | |
| msg = f"[SSH ERROR] {e}" | |
| logger.error(msg) | |
| return {"stdout": "", "stderr": str(e), "exit_code": -1, "result": msg} | |
| finally: | |
| client.close() | |