"""Shared Agent install/upgrade paths and shell fragments (aligned with web/agent/install.sh).""" from __future__ import annotations from server.application.server_batch_common import agent_files_curl_cmds, sudo_wrap # Must match web/agent/install.sh AGENT_INSTALL_DIR = "/opt/nexus-agent" AGENT_PIP_PACKAGES = ( "fastapi==0.115.6", "uvicorn==0.34.0", "httpx==0.28.1", "psutil", "python-multipart==0.0.19", ) def agent_venv_python(install_dir: str = AGENT_INSTALL_DIR) -> str: return f"{install_dir}/.venv/bin/python" def agent_pip_install_cmd(venv_python: str | None = None) -> str: py = venv_python or agent_venv_python() pkgs = " ".join(AGENT_PIP_PACKAGES) return f"{py} -m pip install -q {pkgs}" def agent_python_version_check_cmd(venv_python: str | None = None) -> str: py = venv_python or agent_venv_python() return ( f"{py} -c '" "import sys; v=sys.version_info; " "print(f\"py_ok_{v.major}.{v.minor}.{v.micro}\") " "if v.major==3 and v.minor>=10 else sys.exit(1)'" ) def agent_rsync_install_cmd() -> str: return ( "(command -v rsync >/dev/null 2>&1 || " "(apt-get update -qq && apt-get install -y -qq rsync) || " "(yum install -y -q rsync) || (dnf install -y -q rsync))" ) def agent_kill_port_cmd(agent_port: int) -> str: return f"fuser -k {int(agent_port)}/tcp 2>/dev/null || true; " def build_agent_upgrade_cmd( *, base_url: str, ssh_user: str, install_dir: str = AGENT_INSTALL_DIR, agent_port: int = 8601, ) -> str: """Shell pipeline: rsync → py check → pip → backup → download → restart → verify.""" venv_python = agent_venv_python(install_dir) systemctl_prefix = "sudo " if ssh_user != "root" else "" return sudo_wrap( f"{agent_rsync_install_cmd()} " f"&& {agent_python_version_check_cmd(venv_python)} " f"&& {agent_pip_install_cmd(venv_python)} " f"&& cp {install_dir}/agent.py {install_dir}/agent.py.bak " f"&& {agent_files_curl_cmds(base_url, install_dir)} " f"&& {agent_kill_port_cmd(agent_port)}{systemctl_prefix}systemctl restart nexus-agent " f"&& sleep 2 " f"&& {systemctl_prefix}systemctl is-active nexus-agent " f"&& echo 'upgrade_ok'", ssh_user, ) def build_agent_upgrade_rollback_cmd( *, ssh_user: str, install_dir: str = AGENT_INSTALL_DIR, ) -> str: systemctl_prefix = "sudo " if ssh_user != "root" else "" return sudo_wrap( f"cp {install_dir}/agent.py.bak {install_dir}/agent.py " f"&& {systemctl_prefix}systemctl restart nexus-agent", ssh_user, )