From c51ba43fa92b21f3751bb507ed0e3771d20e7dd1 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 15 Jun 2026 16:13:30 +0800 Subject: [PATCH] =?UTF-8?q?deploy(M00-E):=20=E5=AE=8C=E5=96=84=E8=8F=9C?= =?UTF-8?q?=E5=8D=95=E5=BC=8F=E9=83=A8=E7=BD=B2=E9=AA=A8=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deploy/README.md | 13 +- deploy/VERSION | 3 +- docs/deployment-changelog.md | 6 +- docs/deployment-status.md | 24 ++-- docs/devlogs/2026-06-15-M00-A-单仓库基线.md | 4 +- docs/feature-status.md | 8 +- docs/release-manifest.md | 4 +- scripts/setup/README.md | 15 ++- scripts/setup/backup.sh | 30 +++++ scripts/setup/deploy-business.sh | 50 ++++++++ scripts/setup/diagnose.sh | 33 +++++ scripts/setup/init-layout.sh | 62 ++++++++++ scripts/setup/lib.sh | 93 ++++++++++++++ scripts/setup/preflight.sh | 37 ++++++ scripts/setup/repo-status.sh | 52 ++++++++ scripts/setup/restore.sh | 17 +++ scripts/setup/rollback.sh | 23 ++++ setup.sh | 130 +++++++++++++++----- 18 files changed, 545 insertions(+), 59 deletions(-) create mode 100644 scripts/setup/backup.sh create mode 100644 scripts/setup/deploy-business.sh create mode 100644 scripts/setup/diagnose.sh create mode 100644 scripts/setup/init-layout.sh create mode 100644 scripts/setup/lib.sh create mode 100644 scripts/setup/preflight.sh create mode 100644 scripts/setup/repo-status.sh create mode 100644 scripts/setup/restore.sh create mode 100644 scripts/setup/rollback.sh diff --git a/deploy/README.md b/deploy/README.md index 2cd5c49..e52ba05 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -29,5 +29,16 @@ 9. 诊断 0. 退出 -当前版本仅提供 M00 菜单骨架和安全提示,生产安装动作将在后续 M00-D/M00-E 完善。 +当前版本提供 M00-D/M00-E 部署基线: +- 启动快检:架构、基础命令、Docker 禁用提醒、Redis 预留状态。 +- 首次安装:创建 `/opt/apps` 目录布局,写入 `run/layout.json`。 +- 更新业务服务:克隆/检查固定仓库,生成 release manifest。正式后端/后台未生成前仅执行安全 dry-run。 +- EMQX:输出原生 Apt/无 Docker/MQTTX 禁止策略和本机命令状态。 +- HTTPS:输出固定域名、API 路径和 Nginx 配置检查。 +- 状态:显示部署上下文、快检、仓库状态和当前 release manifest。 +- 备份:当前生成 manifest-only 备份记录,不触碰真实数据库。 +- 恢复/回滚:列出人工输入和回滚点,不自动改动生产数据。 +- 诊断:汇总环境、仓库、磁盘和服务状态。 + +生产执行仍必须由管理员在 Ubuntu 上运行 `/opt/apps/setup.sh` 或同源脚本;Codex 不从 Windows/WSL 自动触发生产部署。 diff --git a/deploy/VERSION b/deploy/VERSION index 9f4466a..dd63fc7 100644 --- a/deploy/VERSION +++ b/deploy/VERSION @@ -1,2 +1 @@ -0.0.1-m00-baseline - +0.1.0-m00-deploy-baseline diff --git a/docs/deployment-changelog.md b/docs/deployment-changelog.md index 31b4a6e..2485f74 100644 --- a/docs/deployment-changelog.md +++ b/docs/deployment-changelog.md @@ -1,13 +1,13 @@ # 部署变更记录 -## 2026-06-15 / 0.0.1-m00-baseline +## 2026-06-15 / 0.1.0-m00-deploy-baseline - 关联模块:M00 - 关联 commit:本地 HEAD(push 待完成) -- 变化内容:建立根目录 `setup.sh`、部署目录和状态文档。 +- 变化内容:建立根目录 `setup.sh`、`scripts/setup/*.sh` 模块化部署脚本、部署目录和状态文档。 - 配置变化:固定 `api.txyundm.cn`、`/opt/apps`、Ubuntu 24.04 amd64。 - 数据库变化:无。 - 兼容性:当前仅菜单骨架,不执行生产改动。 -- 已执行验证:待运行脚本。 +- 已执行验证:Windows 本地检查、WSL `bash -n setup.sh scripts/setup/*.sh`、`setup.sh --preflight`、`setup.sh --status`、`setup.sh --diagnose`;生产 Ubuntu 未执行。 - 回滚方式:尚未生产部署,无生产回滚。 - 生产环境人工步骤:后续由管理员在 Ubuntu `/opt/apps/setup.sh` 执行。 diff --git a/docs/deployment-status.md b/docs/deployment-status.md index e985942..977475d 100644 --- a/docs/deployment-status.md +++ b/docs/deployment-status.md @@ -2,7 +2,7 @@ | 项目 | 当前值 | |---|---| -| 菜单脚本版本 | 0.0.1-m00-baseline | +| 菜单脚本版本 | 0.1.0-m00-deploy-baseline | | Gitea 仓库 Web | https://git.txyundm.cn/panda/qipai.git | | API 固定域名 | https://api.txyundm.cn | | 小程序 API | https://api.txyundm.cn/app-api | @@ -25,18 +25,18 @@ | 命令行 MQTT 工具 | mosquitto-clients:未安装/未验证 | | Windows MQTTX 验证 | 未验证 | | WSL 环境验证 | 已完成轻量检查、shell 语法检查、临时副本准备和清理;完整构建待正式项目生成 | -| 最近环境快检 | 2026-06-15 本地骨架检查 | +| 最近环境快检 | 2026-06-15 WSL 执行 `setup.sh --preflight/--status/--diagnose` 通过,WARN 项已记录 | | 最近部署后复检 | 未执行 | | 最近验证 commit | 远端 HEAD;M00-C 推送脚本语法检查通过 | | 最近验证日期 | 2026-06-15 | | 已验证系统 | Ubuntu 24.04 / 未验证 | -| 菜单 1 首次安装 | 未验证 | -| 菜单 2 更新业务 | 未验证 | -| 菜单 3 MQTT | 未验证 | -| 菜单 4 域名与 HTTPS | 未验证 | -| 菜单 5 状态 | 未验证 | -| 菜单 6 备份 | 未验证 | -| 菜单 7 恢复 | 未验证 | -| 菜单 8 回滚 | 未验证 | -| 菜单 9 诊断 | 未验证 | -| 已知限制 | 当前仅为 M00 基线骨架,未执行生产部署。 | +| 菜单 1 首次安装 | 脚本已实现目录布局;未在生产 Ubuntu 执行 | +| 菜单 2 更新业务 | 脚本已实现仓库检查和 dry-run 发布清单;未在生产 Ubuntu 执行 | +| 菜单 3 MQTT | 状态检查已实现;EMQX 安装未执行 | +| 菜单 4 域名与 HTTPS | 状态检查已实现;证书申请/续期未执行 | +| 菜单 5 状态 | 已实现 | +| 菜单 6 备份 | manifest-only 已实现;真实备份待生产配置 | +| 菜单 7 恢复 | 人工恢复提示已实现 | +| 菜单 8 回滚 | 回滚点列表已实现;自动切换待正式 release | +| 菜单 9 诊断 | 已实现 | +| 已知限制 | 未执行生产部署;WSL 快检显示 Node/Nginx/PM2 缺失或未安装,生产 Ubuntu 需重新验证;正式后端/后台未生成前,业务构建为 dry-run。 | diff --git a/docs/devlogs/2026-06-15-M00-A-单仓库基线.md b/docs/devlogs/2026-06-15-M00-A-单仓库基线.md index abc4900..089beb1 100644 --- a/docs/devlogs/2026-06-15-M00-A-单仓库基线.md +++ b/docs/devlogs/2026-06-15-M00-A-单仓库基线.md @@ -11,6 +11,7 @@ - 将含密钥/依赖/真实数据风险的原始参考包和 SQL 从 Git 跟踪中移出,仅保留哈希和审计结论。 - 生成 `docs/reference-page-map.md`、`docs/db-schema-inventory.md` 和 `docs/reference-api-inventory.md` 作为可提交脱敏摘要。 - 生成 `scripts/dev/windows/push-module.ps1` 和 `check-gitea-ssh.ps1`,串联模块检查、提交、推送和远端校验。 +- 生成 `scripts/setup/*.sh` 和新版 `setup.sh` 菜单,覆盖 `/opt/apps` 目录、仓库状态、dry-run 发布清单、备份 manifest、恢复/回滚提示和诊断。 ## 起始状态 @@ -30,7 +31,7 @@ ## 部署影响 -有。新增 `setup.sh` 菜单骨架和部署状态文档,但未执行生产部署。 +有。新增并升级 `setup.sh` 与 `scripts/setup/*.sh` 菜单式部署骨架,但未执行生产部署。 ## 测试记录 @@ -40,6 +41,7 @@ - 脱敏摘要:已生成页面地图、数据库结构清单和接口线索文档。 - Windows 推送脚本:已新增,遇到 SSH 主机指纹问题时停止,不自动覆盖 `known_hosts`。 - PowerShell 语法检查:`push-module.ps1`、`check-gitea-ssh.ps1` 均已通过 Parser 检查。 +- 部署脚本:WSL 已执行 `bash -n setup.sh scripts/setup/*.sh`、`setup.sh --preflight`、`setup.sh --status`、`setup.sh --diagnose`;输出 PASS/WARN,未执行生产写入。 - WSL 检查:已执行 `check-env.sh`、`check-workspace.sh`、`verify-linux.sh`、`prepare-test-copy.sh` 和 `cleanup-test-copy.sh`;临时副本创建和清理通过。完整 Linux 构建待正式后端/后台项目生成后执行。 - Git fetch/push:首次多次失败后,`git push origin main` 已成功;随后 `git fetch origin main` 校验 `HEAD == origin/main` 通过。 diff --git a/docs/feature-status.md b/docs/feature-status.md index 993b263..4dce581 100644 --- a/docs/feature-status.md +++ b/docs/feature-status.md @@ -11,9 +11,9 @@ | API-001 | 固定 HTTPS API 域名 | M00-E/M01/M08/M10 | TODO | - | - | DNS/HTTPS 生产验证未执行。 | 在部署脚本和代码中统一 `api.txyundm.cn`。 | | TLS-001 | Nginx 与证书自动化 | M00-E/M10 | TODO | - | - | DNS/80/443 生产验证未执行。 | 补菜单脚本和证书检查。 | | WXNET-001 | 微信合法域名与真机验证 | M00-E/M08/M10 | TODO | - | - | 微信后台/真机未验证。 | 先完成检查报告模板。 | -| OPS-001 | 固定 `/opt/apps` 目录 | M00-D/M10 | TODO | - | - | Ubuntu 生产操作未执行。 | 生成部署菜单和目录检查。 | +| OPS-001 | 固定 `/opt/apps` 目录 | M00-D/M10 | PARTIAL | 本地 HEAD | `scripts/setup/init-layout.sh` 已生成目录布局和 manifest;未在生产 Ubuntu 执行。 | 生产操作未执行。 | 由管理员在 Ubuntu 菜单执行并记录结果。 | | OPS-002 | 单仓库 Gitea 推送与拉取部署 | M00-B/M10 | PARTIAL | 远端 HEAD | Windows 到 Gitea `origin/main` 首次 push 与远端校验通过。 | 生产服务器只读拉取部署尚未验证。 | M00-D/M00-E 继续完善生产拉取、菜单部署和状态检查。 | -| OPS-003 | 整仓发布清单 | M00-E/M10 | TODO | - | - | - | 生成 release manifest 模板。 | -| OPS-004 | 菜单式更新与环境监测 | M00-E/M10 | TODO | - | - | - | 生成 `setup.sh` 和 `scripts/setup`。 | -| IOT-001 | MQTT Broker 生产部署 | M00/M06 | TODO | - | - | 缺生产 EMQX 实机验证。 | 先完成部署文档和 MQTT 状态模板。 | +| OPS-003 | 整仓发布清单 | M00-E/M10 | PARTIAL | 本地 HEAD | `deploy-business.sh` 可生成 dry-run release manifest;正式构建待项目生成。 | 后端/后台尚未生成。 | M01/M09 后接入真实构建结果。 | +| OPS-004 | 菜单式更新与环境监测 | M00-E/M10 | PARTIAL | 本地 HEAD | `setup.sh` 已接入初始化、更新、MQTT、HTTPS、状态、备份、恢复、回滚和诊断菜单;WSL 快检/status/diagnose 通过。 | 未在生产 Ubuntu 执行。 | 生产执行后补部署记录。 | +| IOT-001 | MQTT Broker 生产部署 | M00/M06 | PARTIAL | 本地 HEAD | 菜单 3 已输出 EMQX 原生 Apt、禁止 MQTTX 和 mosquitto-clients 状态检查;未安装。 | 缺生产 EMQX 实机验证。 | M00/M06 继续补官方 Apt 安装和 ACL。 | | SYS-001 | 微信原生小程序 | M00-C/M08 | TODO | - | - | 参考小程序压缩包尚未深度整理。 | 后续导入正式 `miniapp/`。 | diff --git a/docs/release-manifest.md b/docs/release-manifest.md index 040a726..06eb966 100644 --- a/docs/release-manifest.md +++ b/docs/release-manifest.md @@ -2,11 +2,11 @@ | 项目 | 当前值 | |---|---| -| 最近发布 commit | 未发布;本地 M00 基线提交为本地 HEAD | +| 最近发布 commit | 未发布;M00 部署脚本仅生成 dry-run 发布清单 | | 发布分支 | main | | 后端构建 | 未执行 | | 后台构建 | 未执行 | | 小程序检查 | 未执行 | | 数据库迁移 | 未执行 | -| 部署结果 | 未部署 | +| 部署结果 | 未部署;生产需管理员人工执行菜单 | | 回滚点 | - | diff --git a/scripts/setup/README.md b/scripts/setup/README.md index c5254f5..631edc8 100644 --- a/scripts/setup/README.md +++ b/scripts/setup/README.md @@ -1,4 +1,17 @@ # Ubuntu 菜单脚本目录 -后续 M00-D/M00-E 将在此目录补充 `/opt/apps` 初始化、Gitea 拉取、业务部署、EMQX、Nginx、证书、备份、恢复、回滚和诊断脚本。 +本目录为根目录 `setup.sh` 提供模块化函数。 +| 文件 | 用途 | +|---|---| +| `lib.sh` | 固定路径、仓库、域名、状态输出和架构检查。 | +| `preflight.sh` | 启动快检:架构、基础命令、Docker 禁用提醒、Redis 预留状态。 | +| `init-layout.sh` | 创建 `/opt/apps` 目录布局并写入 `run/layout.json`。 | +| `repo-status.sh` | 检查固定仓库、分支、DIRTY/AHEAD/BEHIND/DIVERGED 状态。 | +| `deploy-business.sh` | 克隆/更新仓库并生成 dry-run release manifest。 | +| `backup.sh` | 生成 manifest-only 备份记录。 | +| `restore.sh` | 输出人工恢复要求,不自动改动生产数据。 | +| `rollback.sh` | 列出 release 回滚点。 | +| `diagnose.sh` | 汇总快检、仓库、磁盘、服务和公开端点。 | + +M00 阶段脚本必须保持可重复执行和非破坏性。真实数据库、证书、EMQX ACL、Nginx 写入和 PM2 切换将在后续模块具备配置后继续补全。 diff --git a/scripts/setup/backup.sh b/scripts/setup/backup.sh new file mode 100644 index 0000000..ac9875e --- /dev/null +++ b/scripts/setup/backup.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib.sh +. "${SCRIPT_DIR}/lib.sh" + +qipai_backup() { + qipai_require_root_for_write + local backup_dir manifest + backup_dir="${APP_ROOT}/backups/manual/$(date +%Y%m%d%H%M%S)" + mkdir -p "$backup_dir" + manifest="${backup_dir}/backup.json" + cat >"$manifest" <"$manifest" </dev/null || df -h / + + qipai_info "service status summary:" + for service in nginx mysql emqx gitea; do + if command -v systemctl >/dev/null 2>&1; then + systemctl is-active --quiet "$service" 2>/dev/null && qipai_pass "${service}: active" || qipai_warn "${service}: inactive or missing" + fi + done + + qipai_info "public endpoints:" + qipai_info "app health: ${QIPAI_API_ORIGIN}/app-api/health" + qipai_info "admin health: ${QIPAI_API_ORIGIN}/admin-api/health" +} + +if [ "${1:-}" = "--run" ]; then + qipai_diagnose +fi diff --git a/scripts/setup/init-layout.sh b/scripts/setup/init-layout.sh new file mode 100644 index 0000000..1b1318f --- /dev/null +++ b/scripts/setup/init-layout.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib.sh +. "${SCRIPT_DIR}/lib.sh" + +qipai_init_layout() { + qipai_require_root_for_write + + local dirs=( + "${APP_ROOT}" + "${APP_ROOT}/qipai-repo" + "${APP_ROOT}/qipai-backend" + "${APP_ROOT}/qipai-admin" + "${APP_ROOT}/qipai-miniapp" + "${APP_ROOT}/releases" + "${APP_ROOT}/backups/mysql" + "${APP_ROOT}/backups/emqx" + "${APP_ROOT}/backups/files" + "${APP_ROOT}/logs" + "${APP_ROOT}/nginx" + "${APP_ROOT}/redis-reserved" + "${APP_ROOT}/run" + ) + + for dir in "${dirs[@]}"; do + mkdir -p "$dir" + qipai_pass "directory exists: $dir" + done + + if id qipai >/dev/null 2>&1; then + qipai_pass "user qipai exists" + else + qipai_warn "user qipai does not exist; create manually before production deployment" + fi + + if id git >/dev/null 2>&1; then + qipai_pass "user git exists" + else + qipai_warn "user git does not exist; required for native Gitea service" + fi + + cat >"${APP_ROOT}/run/layout.json" </dev/null 2>&1; then + qipai_pass "${command_name}: $(command -v "$command_name")" + else + qipai_warn "${command_name}: not installed" + fi +} + +qipai_repo_dir() { + printf '%s/qipai-repo\n' "$APP_ROOT" +} + +qipai_release_dir() { + printf '%s/releases\n' "$APP_ROOT" +} + +qipai_current_release_file() { + printf '%s/current-release.json\n' "$APP_ROOT" +} + +qipai_print_context() { + qipai_info "deploy version: ${QIPAI_DEPLOY_VERSION}" + qipai_info "app root: ${APP_ROOT}" + qipai_info "repo: ${QIPAI_REPO_URL}" + qipai_info "branch: ${QIPAI_BRANCH}" + qipai_info "api origin: ${QIPAI_API_ORIGIN}" +} + diff --git a/scripts/setup/preflight.sh b/scripts/setup/preflight.sh new file mode 100644 index 0000000..18bdb55 --- /dev/null +++ b/scripts/setup/preflight.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib.sh +. "${SCRIPT_DIR}/lib.sh" + +qipai_preflight() { + qipai_print_context + qipai_check_arch + qipai_command_status git + qipai_command_status bash + qipai_command_status node + qipai_command_status npm + qipai_command_status mysql + qipai_command_status nginx + qipai_command_status pm2 + qipai_command_status openssl + qipai_command_status curl + + if command -v docker >/dev/null 2>&1; then + qipai_warn "docker detected but this project does not use Docker" + else + qipai_pass "docker: not installed or not in PATH" + fi + + if command -v redis-server >/dev/null 2>&1; then + qipai_warn "redis-server detected; Redis is reserved/disabled for MVP" + else + qipai_pass "redis: RESERVED/DISABLED" + fi +} + +if [ "${1:-}" = "--run" ]; then + qipai_preflight +fi + diff --git a/scripts/setup/repo-status.sh b/scripts/setup/repo-status.sh new file mode 100644 index 0000000..6b23b56 --- /dev/null +++ b/scripts/setup/repo-status.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib.sh +. "${SCRIPT_DIR}/lib.sh" + +qipai_repo_status() { + local repo_dir + repo_dir="$(qipai_repo_dir)" + + if [ ! -d "${repo_dir}/.git" ]; then + qipai_warn "repo not cloned: ${repo_dir}" + qipai_info "expected repo: ${QIPAI_REPO_URL}" + return 0 + fi + + git -C "$repo_dir" remote -v + local branch status + branch="$(git -C "$repo_dir" branch --show-current)" + status="$(git -C "$repo_dir" status --short --branch --untracked-files=all)" + qipai_info "branch: ${branch}" + printf '%s\n' "$status" + + if [ "$branch" != "$QIPAI_BRANCH" ]; then + qipai_fail "branch mismatch: expected ${QIPAI_BRANCH}, actual ${branch}" + return 1 + fi + + if git -C "$repo_dir" diff --quiet && git -C "$repo_dir" diff --cached --quiet; then + qipai_pass "repo is not dirty" + else + qipai_fail "repo is DIRTY; deployment must stop" + return 1 + fi + + git -C "$repo_dir" fetch origin "$QIPAI_BRANCH" + local counts + counts="$(git -C "$repo_dir" rev-list --left-right --count "${QIPAI_BRANCH}...origin/${QIPAI_BRANCH}")" + qipai_info "ahead/behind: ${counts}" + case "$counts" in + "0 0") qipai_pass "repo matches origin/${QIPAI_BRANCH}" ;; + 0$'\t'*) qipai_warn "repo is BEHIND origin/${QIPAI_BRANCH}" ;; + *$'\t'0) qipai_fail "repo is AHEAD origin/${QIPAI_BRANCH}; deployment must stop"; return 1 ;; + *) qipai_fail "repo is DIVERGED; deployment must stop"; return 1 ;; + esac +} + +if [ "${1:-}" = "--run" ]; then + qipai_repo_status +fi + diff --git a/scripts/setup/restore.sh b/scripts/setup/restore.sh new file mode 100644 index 0000000..ad99150 --- /dev/null +++ b/scripts/setup/restore.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib.sh +. "${SCRIPT_DIR}/lib.sh" + +qipai_restore() { + qipai_warn "restore is not automatic in M00 baseline" + qipai_info "Required manual inputs: backup path, MySQL dump, uploads archive, EMQX export" + qipai_info "No production data was changed." +} + +if [ "${1:-}" = "--run" ]; then + qipai_restore +fi + diff --git a/scripts/setup/rollback.sh b/scripts/setup/rollback.sh new file mode 100644 index 0000000..5bb857a --- /dev/null +++ b/scripts/setup/rollback.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib.sh +. "${SCRIPT_DIR}/lib.sh" + +qipai_rollback() { + local releases + releases="$(qipai_release_dir)" + if [ ! -d "$releases" ]; then + qipai_warn "no releases directory: $releases" + return 0 + fi + qipai_info "available releases:" + find "$releases" -mindepth 1 -maxdepth 1 -type d -printf '%f\n' | sort -r | head -20 + qipai_warn "M00 baseline lists rollback points only; automatic switch requires a selected release id" +} + +if [ "${1:-}" = "--run" ]; then + qipai_rollback +fi + diff --git a/setup.sh b/setup.sh index 3badf72..be4de15 100644 --- a/setup.sh +++ b/setup.sh @@ -1,52 +1,101 @@ #!/usr/bin/env bash set -euo pipefail -VERSION="0.0.1-m00-baseline" -APP_ROOT="/opt/apps" -REPO_SSH="ssh://git@127.0.0.1:2222/panda/qipai.git" -PUBLIC_API="https://api.txyundm.cn" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SETUP_DIR="${SCRIPT_DIR}/scripts/setup" + +# shellcheck source=scripts/setup/lib.sh +. "${SETUP_DIR}/lib.sh" +# shellcheck source=scripts/setup/preflight.sh +. "${SETUP_DIR}/preflight.sh" +# shellcheck source=scripts/setup/init-layout.sh +. "${SETUP_DIR}/init-layout.sh" +# shellcheck source=scripts/setup/repo-status.sh +. "${SETUP_DIR}/repo-status.sh" +# shellcheck source=scripts/setup/deploy-business.sh +. "${SETUP_DIR}/deploy-business.sh" +# shellcheck source=scripts/setup/backup.sh +. "${SETUP_DIR}/backup.sh" +# shellcheck source=scripts/setup/restore.sh +. "${SETUP_DIR}/restore.sh" +# shellcheck source=scripts/setup/rollback.sh +. "${SETUP_DIR}/rollback.sh" +# shellcheck source=scripts/setup/diagnose.sh +. "${SETUP_DIR}/diagnose.sh" print_header() { - echo "自助棋牌室系统部署菜单 ${VERSION}" + echo "自助棋牌室系统部署菜单 ${QIPAI_DEPLOY_VERSION}" echo "生产目录: ${APP_ROOT}" - echo "固定 API: ${PUBLIC_API}" + echo "固定 API: ${QIPAI_API_ORIGIN}" echo } -check_arch() { - local kernel_arch dpkg_arch bits - kernel_arch="$(uname -m 2>/dev/null || echo unknown)" - dpkg_arch="$(dpkg --print-architecture 2>/dev/null || echo unknown)" - bits="$(getconf LONG_BIT 2>/dev/null || echo unknown)" - echo "内核架构: ${kernel_arch}" - echo "DPKG 架构: ${dpkg_arch}" - echo "用户空间位数: ${bits}" - if [ "${kernel_arch}" != "x86_64" ] || [ "${dpkg_arch}" != "amd64" ] || [ "${bits}" != "64" ]; then - echo "FAIL: 仅支持 Ubuntu 24.04 x86-64/amd64。" - exit 1 +pause_menu() { + echo + printf "按回车返回菜单..." + read -r _ || true +} + +run_action() { + local title="$1" + shift + echo + echo "== ${title} ==" + "$@" + pause_menu +} + +show_status() { + qipai_print_context + qipai_preflight || true + qipai_repo_status || true + if [ -f "$(qipai_current_release_file)" ]; then + qipai_info "current release manifest: $(qipai_current_release_file)" + cat "$(qipai_current_release_file)" + else + qipai_warn "current release manifest not found" fi } -quick_check() { - echo "== 启动快检 ==" - check_arch - command -v git >/dev/null 2>&1 && echo "Git: PASS" || echo "Git: WARN 未安装" - command -v nginx >/dev/null 2>&1 && echo "Nginx: PASS" || echo "Nginx: WARN 未安装" - command -v node >/dev/null 2>&1 && echo "Node.js: PASS" || echo "Node.js: WARN 未安装" - echo "仓库: ${REPO_SSH}" +show_mqtt_status() { + qipai_info "EMQX target: native Ubuntu Apt package, no Docker" + qipai_info "MQTT broker host: 101.42.38.246" + qipai_info "MQTTX on server: forbidden" + if command -v emqx >/dev/null 2>&1; then + qipai_pass "emqx command exists" + emqx version 2>/dev/null || true + else + qipai_warn "emqx command not found" + fi + if command -v mosquitto_pub >/dev/null 2>&1; then + qipai_pass "mosquitto-clients available" + else + qipai_warn "mosquitto-clients not installed" + fi } -not_implemented() { - echo "当前 M00 基线仅提供菜单骨架;该选项将在后续子阶段完善。" +show_https_status() { + qipai_info "domain: ${QIPAI_DOMAIN}" + qipai_info "origin: ${QIPAI_API_ORIGIN}" + qipai_info "app api: ${QIPAI_API_ORIGIN}/app-api" + qipai_info "admin api: ${QIPAI_API_ORIGIN}/admin-api" + if command -v nginx >/dev/null 2>&1; then + nginx -t + else + qipai_warn "nginx not installed" + fi + if command -v openssl >/dev/null 2>&1; then + qipai_info "TLS live check requires public DNS/network and is not forced in M00" + fi } main_menu() { while true; do print_header - echo "1. 首次安装" - echo "2. 更新业务服务" + echo "1. 首次安装 / 初始化目录" + echo "2. 更新业务服务 / 生成发布清单" echo "3. 安装或检查 EMQX" - echo "4. 配置域名与 HTTPS" + echo "4. 配置域名与 HTTPS / 状态检查" echo "5. 查看状态" echo "6. 备份" echo "7. 恢复" @@ -56,14 +105,29 @@ main_menu() { printf "请选择: " read -r choice case "${choice}" in - 1|2|3|4|6|7|8) not_implemented ;; - 5|9) quick_check ;; + 1) run_action "首次安装 / 初始化目录" qipai_init_layout ;; + 2) run_action "更新业务服务 / 生成发布清单" qipai_deploy_business ;; + 3) run_action "安装或检查 EMQX" show_mqtt_status ;; + 4) run_action "配置域名与 HTTPS / 状态检查" show_https_status ;; + 5) run_action "查看状态" show_status ;; + 6) run_action "备份" qipai_backup ;; + 7) run_action "恢复" qipai_restore ;; + 8) run_action "回滚" qipai_rollback ;; + 9) run_action "诊断" qipai_diagnose ;; 0) exit 0 ;; - *) echo "无效选项" ;; + *) echo "无效选项"; pause_menu ;; esac echo done } -main_menu "$@" +if [ "${1:-}" = "--preflight" ]; then + qipai_preflight +elif [ "${1:-}" = "--status" ]; then + show_status +elif [ "${1:-}" = "--diagnose" ]; then + qipai_diagnose +else + main_menu "$@" +fi