diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 291d900a..1b29b025 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,7 @@ jobs: python3 -m py_compile clients/client-linux.py clients/client-psutil.py python3 -m unittest clients/test_client_args.py sh -n clients/entrypoint.sh + bash -n clients/install.sh bash -n status.sh node --check web/js/app.js diff --git a/README.md b/README.md index c8aead11..d4ae4b7e 100644 --- a/README.md +++ b/README.md @@ -63,12 +63,14 @@ docker run -d --restart=always --name=serverstatus-client \ ``` ```bash -# Shell Run -wget -qO client-linux.py --header='Accept: application/vnd.github.raw' \ - 'https://api.github.com/repos/cppla/ServerStatus/contents/clients/client-linux.py?ref=master' -nohup python3 client-linux.py SERVER=127.0.0.1 USER=s01 PASSWORD=USER_DEFAULT_PASSWORD >/dev/null 2>&1 & +# Shell(下载安装脚本,自动配置为 systemd 服务) +wget -qO install.sh --header='Accept: application/vnd.github.raw' \ + 'https://api.github.com/repos/jumploop/ServerStatus/contents/clients/install.sh?ref=master' +bash install.sh SERVER=127.0.0.1 USER=s01 PASSWORD=USER_DEFAULT_PASSWORD ``` +安装脚本会下载 `service/status-client.service` 与 `clients/client-linux.py`,写入客户端配置并注册为 systemd 服务 `status-client`(需 root 或 sudo)。 + `USER` 是常见的宿主机环境变量名。如果没有显式传递或传递方式错误,Compose 可能会把系统中的 `$USER` 解析成本机用户名,而不是默认的 `s01`。推荐优先级: 1. 运行命令显式传递 `USER=s01` diff --git a/clients/install.sh b/clients/install.sh new file mode 100644 index 00000000..c925f1f6 --- /dev/null +++ b/clients/install.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# ServerStatus 客户端一键安装脚本(systemd 方式) +# 自动下载 status-client.service 与 client-linux.py,注册 systemd 服务并启动。 +# 用法: bash install.sh SERVER=服务器地址 [PORT=端口] [USER=用户名] [PASSWORD=密码] +set -euo pipefail + +github_prefix="https://raw.githubusercontent.com/jumploop/ServerStatus/master" + +client_file="/usr/local/ServerStatus/clients/client-linux.py" +client_env="/usr/local/ServerStatus/clients/config.env" +client_service="/usr/lib/systemd/system/status-client.service" +client_override="/etc/systemd/system/status-client.service.d/override.conf" + +SERVER="" +PORT="35601" +USER="" +PASSWORD="" + +for arg in "$@"; do + case "${arg}" in + SERVER=*) SERVER="${arg#SERVER=}" ;; + PORT=*) PORT="${arg#PORT=}" ;; + USER=*) USER="${arg#USER=}" ;; + PASSWORD=*) PASSWORD="${arg#PASSWORD=}" ;; + *) echo "错误: 未知参数 ${arg}" >&2; exit 1 ;; + esac +done + +if [[ -z "${SERVER}" ]]; then + echo "错误: 缺少 SERVER 参数,用法: bash install.sh SERVER=服务器地址 [PORT=端口] [USER=用户名] [PASSWORD=密码]" >&2 + exit 1 +fi + +if [[ -z "${USER}" ]]; then + echo "警告: USER 为空,客户端可能无法上报,请用 USER=用户名 指定" >&2 +fi + +if [[ "$(id -u)" -ne 0 ]]; then + if command -v sudo >/dev/null 2>&1; then + exec sudo bash "$0" "$@" + fi + echo "错误: 请使用 root 权限运行(如: sudo bash install.sh ...)" >&2 + exit 1 +fi + +command -v wget >/dev/null 2>&1 || { echo "错误: 未找到 wget,请先安装 wget" >&2; exit 1; } +command -v python3 >/dev/null 2>&1 || { echo "错误: 未找到 python3,请先安装 python3" >&2; exit 1; } +command -v systemctl >/dev/null 2>&1 || { echo "错误: 未找到 systemctl,当前系统不支持 systemd" >&2; exit 1; } + +mkdir -p "$(dirname "${client_file}")" +wget -qN --no-check-certificate "${github_prefix}/clients/client-linux.py" -O "${client_file}" +wget -qN --no-check-certificate "${github_prefix}/service/status-client.service" -O "${client_service}" +chmod +x "${client_file}" + +printf 'SERVER=%s\nPORT=%s\nUSER=%s\nPASSWORD=%s\n' "${SERVER}" "${PORT}" "${USER}" "${PASSWORD}" > "${client_env}" + +mkdir -p "$(dirname "${client_override}")" +cat > "${client_override}" <<'EOF' +[Service] +EnvironmentFile=/usr/local/ServerStatus/clients/config.env +EOF + +systemctl daemon-reload +systemctl enable status-client >/dev/null 2>&1 || true +if ! systemctl restart status-client; then + echo "错误: status-client 启动失败,最近日志:" >&2 + journalctl -u status-client -n 20 --no-pager >&2 || true + exit 1 +fi + +echo "ServerStatus 客户端安装完成:" +echo " SERVER: ${SERVER}" +echo " PORT: ${PORT}" +echo " USER: ${USER}" +echo " 配置: ${client_env}" +echo " 查看状态: systemctl status status-client" +echo " 查看日志: journalctl -u status-client -f" diff --git a/web/css/app.css b/web/css/app.css index bfd7e2ad..b3138efd 100644 --- a/web/css/app.css +++ b/web/css/app.css @@ -367,6 +367,16 @@ th[data-sort].sorted-desc:after{border-top-color:var(--accent);opacity:1} .config-form input[name=password],.config-form textarea[name=rule]{font-family:ui-monospace,SFMono-Regular,Menlo,monospace} .config-form button:disabled{opacity:.5;cursor:not-allowed} .config-editor-card{scroll-margin-top:70px} +.client-cmd{display:flex;flex-direction:column;gap:.6rem;border:1px dashed var(--border);border-radius:8px;background:var(--bg);padding:.75rem} +.client-cmd-head{display:flex;align-items:center;justify-content:space-between;gap:.5rem} +.client-cmd-head strong{font-size:13px} +.client-cmd-head .icon-text{width:auto;flex:none} +.client-cmd-addr{display:flex;flex-direction:column;gap:.3rem;color:var(--text-dim);font-size:12px} +.client-cmd-addr input{height:36px;border:1px solid var(--border);background:var(--bg-alt);color:var(--text);border-radius:6px;padding:0 .65rem;outline:none;font-family:ui-monospace,SFMono-Regular,Menlo,monospace} +.client-cmd-addr input:focus{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 18%,transparent)} +.client-cmd-text{margin:0;padding:.6rem .7rem;border-radius:6px;background:var(--bg-alt);color:var(--text);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.55;white-space:pre-wrap;word-break:break-all;max-height:220px;overflow-y:auto} +.client-cmd-methods{width:100%} +.client-cmd-methods button{flex:1;padding:0 .4rem;white-space:nowrap} @media (min-width:981px){ .config-editor-card{position:sticky;top:70px;max-height:calc(100dvh - 86px);overflow-y:auto;scrollbar-gutter:stable} diff --git a/web/index.html b/web/index.html index fa844a5c..2a45d8bb 100644 --- a/web/index.html +++ b/web/index.html @@ -6,7 +6,7 @@
保存后会写入 config.json,并由服务热重载。
- + @@ -207,6 +208,6 @@