Files
Nexus/server/utils/psutil_install.py
T

82 lines
2.6 KiB
Python
Raw Normal View History

"""Install psutil on managed servers via SSH (system Python for watch probe)."""
from __future__ import annotations
from server.application.server_batch_common import sudo_wrap
from server.domain.models import Server
from server.infrastructure.ssh.asyncssh_pool import exec_ssh_command
# Try --user pip, then distro packages, then system pip. Verify with same python3 as watch probe.
PSUTIL_INSTALL_SHELL = r"""
set -e
verify_psutil() {
for py in python3 python3.12 python3.11 python3.10; do
if command -v "$py" >/dev/null 2>&1 && "$py" -c "import psutil" 2>/dev/null; then
echo psutil_ok
exit 0
fi
done
return 1
}
verify_psutil || true
for py in python3 python3.12 python3.11 python3.10; do
command -v "$py" >/dev/null 2>&1 || continue
if "$py" -m pip install --user -q psutil 2>/dev/null; then
verify_psutil && exit 0
fi
done
if command -v apt-get >/dev/null 2>&1; then
apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq python3-psutil \
&& verify_psutil && exit 0
fi
if command -v dnf >/dev/null 2>&1; then
dnf install -y -q python3-psutil && verify_psutil && exit 0
fi
if command -v yum >/dev/null 2>&1; then
yum install -y -q python3-psutil && verify_psutil && exit 0
fi
for py in python3 python3.12 python3.11 python3.10; do
command -v "$py" >/dev/null 2>&1 || continue
if "$py" -m pip install -q psutil 2>/dev/null; then
verify_psutil && exit 0
fi
done
echo "ERROR: psutil install failed — pip/apt unavailable or permission denied" >&2
exit 1
"""
def build_psutil_install_cmd(*, ssh_user: str) -> str:
return sudo_wrap(PSUTIL_INSTALL_SHELL.strip(), ssh_user)
async def install_psutil_via_ssh(server: Server, *, timeout: int = 90) -> dict[str, str | int]:
"""Run remote install; returns {exit_code, stdout, stderr, already_installed?}."""
ssh_user = (server.username or "root").strip()
cmd = build_psutil_install_cmd(ssh_user=ssh_user)
result = await exec_ssh_command(server, cmd, timeout=timeout)
stdout = (result.get("stdout") or "").strip()
stderr = (result.get("stderr") or "").strip()
raw_exit = result.get("exit_code")
exit_code = int(raw_exit) if raw_exit is not None else 1
if exit_code == 0 and "psutil_ok" in stdout:
return {
"success": True,
"exit_code": 0,
"stdout": stdout[:2000],
"stderr": stderr[:500],
"message": "psutil 已就绪",
}
detail = stderr or stdout or f"exit {exit_code}"
return {
"success": False,
"exit_code": exit_code,
"stdout": stdout[:2000],
"stderr": stderr[:500],
"message": detail[:300],
}