Files
Nexus/server/utils/psutil_install.py
T
Nexus Agent 8092000880
Nexus CI/CD / test (push) Waiting to run
Nexus CI/CD / e2e (push) Blocked by required conditions
Nexus CI/CD / deploy (push) Blocked by required conditions
Nexus Pre-commit Checks / quick-check (push) Waiting to run
fix(watch): psutil SSH 安装 apt 走 sudo
非 root 用户 apt-get 未加 sudo 导致 Permission denied;补充 run_root 与中文错误提示。
2026-06-12 04:09:10 +08:00

124 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Install psutil on managed servers via SSH (system Python for watch probe)."""
from __future__ import annotations
import re
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
# pip --user first (no root); package managers and system pip via run_root (sudo when non-root).
PSUTIL_INSTALL_SHELL = r"""
run_root() {
if [ "$(id -u)" -eq 0 ]; then
"$@"
else
sudo "$@"
fi
}
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 && exit 0
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
if run_root apt-get update -qq \
&& run_root env DEBIAN_FRONTEND=noninteractive apt-get install -y -qq python3-psutil; then
verify_psutil && exit 0
fi
fi
if command -v dnf >/dev/null 2>&1; then
if run_root dnf install -y -q python3-psutil; then
verify_psutil && exit 0
fi
fi
if command -v yum >/dev/null 2>&1; then
if run_root yum install -y -q python3-psutil; then
verify_psutil && exit 0
fi
fi
for py in python3 python3.12 python3.11 python3.10; do
command -v "$py" >/dev/null 2>&1 || continue
if run_root "$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
"""
_APT_PERM_RE = re.compile(
r"lock file|permission denied|unable to lock|not allowed to execute",
re.I,
)
def _psutil_install_error_zh(stderr: str, stdout: str) -> str:
text = f"{stderr}\n{stdout}"
if _APT_PERM_RE.search(text):
return (
"安装 psutil 需要 root 或免密 sudoapt/pip)。"
"请改用 root SSH,或在子机配置免密 sudo 后重试;也可手动执行:"
"sudo apt-get install -y python3-psutil"
)
if "sudo requires a password" in text.lower():
return "sudo 需要密码,请配置免密 sudo 或使用 root SSH 登录"
line = ""
for chunk in (stderr, stdout):
for raw in reversed(chunk.splitlines()):
raw = raw.strip()
if raw and not raw.startswith("W:"):
line = raw[:300]
break
if line:
break
return line or "psutil 安装失败"
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 = 120) -> dict[str, str | int | bool]:
"""Run remote install; returns success, message, stdout/stderr."""
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 已就绪",
}
return {
"success": False,
"exit_code": exit_code,
"stdout": stdout[:2000],
"stderr": stderr[:500],
"message": _psutil_install_error_zh(stderr, stdout),
}