修复 Server-Provision 按目标状态准备工具包

新增目标机已有 SpacetimeDB 与 otelcol-contrib 时复用本机安装的准备逻辑
补充 Prepare Provision Tools 传入 SPACETIME_ROOT,避免非默认路径检查错目录
新增 Server-Provision 工具准备回归检查脚本,防止已有工具时仍触发下载
更新开发运维文档与 Hermes 共享记忆,沉淀先检查目标机状态再准备文件的约定
This commit is contained in:
kdletters
2026-06-10 11:10:16 +08:00
parent 0baad9e022
commit 7aafb37f04
6 changed files with 176 additions and 4 deletions

View File

@@ -109,6 +109,7 @@
- 背景:`Genarrative-Server-Provision``DEPLOY_TARGET=development` 语义是部署到 dev 服务器,不是构建机 dry-run。旧流水线把 development 映射到 `linux && genarrative-build`,还先在 build 节点准备 `provision-tools/` 再 stash 给后续阶段,导致真实 dev 初始化可能跑到 Jenkins controller / build 节点;脚本还安装 clang / lld / pkg-config / OpenSSL headers / sccache 等构建链依赖,超出了服务器初始化职责。 - 背景:`Genarrative-Server-Provision``DEPLOY_TARGET=development` 语义是部署到 dev 服务器,不是构建机 dry-run。旧流水线把 development 映射到 `linux && genarrative-build`,还先在 build 节点准备 `provision-tools/` 再 stash 给后续阶段,导致真实 dev 初始化可能跑到 Jenkins controller / build 节点;脚本还安装 clang / lld / pkg-config / OpenSSL headers / sccache 等构建链依赖,超出了服务器初始化职责。
- 决策Server-Provision 只做服务器初始化,全程运行在目标部署 agentdevelopment 使用 `linux && genarrative-dev-deploy`release 使用 `linux && genarrative-release-deploy``Prepare Provision Tools``Provision Server` 在同一个目标 agent workspace 顺序执行,不再切到 `linux && genarrative-build`,不再 `stash/unstash` 工具包。`scripts/jenkins-server-provision.sh` 不再安装 clang / lld / pkg-config / libssl-dev / sccache非 dry-run 仍要求目标 dev / release agent 具备 root 权限,因为 provision 会写 systemd、Nginx、`/etc` 和系统用户。Job 的 `Pipeline script from SCM` 与 Jenkinsfile 参数 `SOURCE_GIT_REMOTE_URL` 都必须使用本机路径或目标 agent 可访问的内网 Git 源,不允许公网 Git fallback。 - 决策Server-Provision 只做服务器初始化,全程运行在目标部署 agentdevelopment 使用 `linux && genarrative-dev-deploy`release 使用 `linux && genarrative-release-deploy``Prepare Provision Tools``Provision Server` 在同一个目标 agent workspace 顺序执行,不再切到 `linux && genarrative-build`,不再 `stash/unstash` 工具包。`scripts/jenkins-server-provision.sh` 不再安装 clang / lld / pkg-config / libssl-dev / sccache非 dry-run 仍要求目标 dev / release agent 具备 root 权限,因为 provision 会写 systemd、Nginx、`/etc` 和系统用户。Job 的 `Pipeline script from SCM` 与 Jenkinsfile 参数 `SOURCE_GIT_REMOTE_URL` 都必须使用本机路径或目标 agent 可访问的内网 Git 源,不允许公网 Git fallback。
- 追加决策2026-06-10`Prepare Provision Tools` 必须先读取目标机现状,再准备需要的文件。目标机 `/usr/local/bin/otelcol-contrib` 版本匹配 `OTELCOL_VERSION` 时直接复用;`${SPACETIME_ROOT}/bin/current/spacetimedb-cli``spacetimedb-standalone` 存在且 CLI 版本匹配 `SPACETIME_EXPECTED_VERSION``SPACETIME_DOWNLOAD_ROOT` 中的版本时,直接复用当前安装生成 `provision-tools/`。只有目标机缺失、不可执行或版本不匹配时,才消费 `PROVISION_DOWNLOADS_DIR` 中的本地包或进入下载分支。
- 影响范围:`jenkins/Jenkinsfile.production-server-provision``scripts/jenkins-server-provision.sh`、生产运维文档、Server-Provision 排障口径。 - 影响范围:`jenkins/Jenkinsfile.production-server-provision``scripts/jenkins-server-provision.sh`、生产运维文档、Server-Provision 排障口径。
- 验证方式Jenkins 日志中 Server-Provision 的 `Prepare``Checkout Provision Files``Prepare Provision Tools``Provision Server` 都在目标 dev / release agent 上执行;日志不出现 `Running on Jenkins``linux && genarrative-build``stash 'server-provision-tools'``Git 主地址拉取失败...改用备用地址``https://git.genarrative.world/GenarrativeAI/Genarrative.git` 或构建依赖 / sccache 安装步骤;`bash -n scripts/jenkins-server-provision.sh` 和编码检查通过。 - 验证方式Jenkins 日志中 Server-Provision 的 `Prepare``Checkout Provision Files``Prepare Provision Tools``Provision Server` 都在目标 dev / release agent 上执行;日志不出现 `Running on Jenkins``linux && genarrative-build``stash 'server-provision-tools'``Git 主地址拉取失败...改用备用地址``https://git.genarrative.world/GenarrativeAI/Genarrative.git` 或构建依赖 / sccache 安装步骤;`bash -n scripts/jenkins-server-provision.sh` 和编码检查通过。
- 关联文档:`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md` - 关联文档:`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`

View File

@@ -1314,6 +1314,14 @@
- 验证Jenkins 日志中 `Provision Target` 下的 `Prepare``Checkout Provision Files``Prepare Provision Tools``Provision Server` 都应运行在目标 dev / release agent日志不应出现 `stash 'server-provision-tools'`、目标阶段 `unstash``Git 主地址拉取失败...改用备用地址``https://git.genarrative.world/GenarrativeAI/Genarrative.git` - 验证Jenkins 日志中 `Provision Target` 下的 `Prepare``Checkout Provision Files``Prepare Provision Tools``Provision Server` 都应运行在目标 dev / release agent日志不应出现 `stash 'server-provision-tools'`、目标阶段 `unstash``Git 主地址拉取失败...改用备用地址``https://git.genarrative.world/GenarrativeAI/Genarrative.git`
- 关联:`jenkins/Jenkinsfile.production-server-provision``scripts/prepare-server-provision-tools.sh``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md` - 关联:`jenkins/Jenkinsfile.production-server-provision``scripts/prepare-server-provision-tools.sh``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## Server-Provision 不要无条件下载工具包
- 现象:目标 dev / release 机器已经安装正确版本的 SpacetimeDB 或 `otelcol-contrib`,但 `Prepare Provision Tools` 仍每次下载 release tarball网络慢或 GitHub 不稳时会把服务器初始化卡在准备阶段。
- 原因:工具准备阶段如果只按“生成交付包”理解,会忽略它已经运行在目标部署 agent 上这一事实;此时目标机本地的 `/usr/local/bin/otelcol-contrib``${SPACETIME_ROOT}/bin/current` 就是可信状态源。
- 处理:`scripts/prepare-server-provision-tools.sh` 必须先检查目标机状态:`otelcol-contrib --version` 命中 `OTELCOL_VERSION` 时复制现有二进制;`spacetimedb-cli --version` 命中 `SPACETIME_EXPECTED_VERSION``SPACETIME_DOWNLOAD_ROOT` 推导出的版本且 standalone 同时存在时,复制 `${SPACETIME_ROOT}/bin` 并生成 wrapper。只有缺失、不可执行或版本不匹配时才查 `PROVISION_DOWNLOADS_DIR` 或下载源。
- 验证:运行 `bash scripts/check-server-provision-tools.sh`Jenkins 日志应先出现“检查目标机 ...”,已有版本命中时出现“复用目标机已有 ...”,且不出现“下载 ...”。
- 关联:`scripts/prepare-server-provision-tools.sh``jenkins/Jenkinsfile.production-server-provision``docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`
## 个人任务 scope 不得扩成 work/site/module ## 个人任务 scope 不得扩成 work/site/module
- 现象:个人任务配置为 `work` / `site` / `module` 后进度串桶或静默按 0 处理。 - 现象:个人任务配置为 `work` / `site` / `module` 后进度串桶或静默按 0 处理。

View File

@@ -277,7 +277,7 @@ dev 服务器上的 Gitea 内网入口固定为 `http://10.2.0.10/GenarrativeAI/
- `GENARRATIVE_API_MAX_CONCURRENT_REQUESTS=512` 开启应用内 HTTP 并发背压;`GENARRATIVE_API_GALLERY_MAX_CONCURRENT_REQUESTS=320``GENARRATIVE_API_DETAIL_MAX_CONCURRENT_REQUESTS=64``GENARRATIVE_API_ADMIN_MAX_CONCURRENT_REQUESTS=16` 分别限制公开列表、公开详情和后台 API 热路径。超过许可时直接返回 `429 Too Many Requests``Retry-After: 1``/healthz``/readyz` 不受该限制。这些值不是 RPS 限速;如果压测中 429 上升但内存和 p95 收敛,说明背压正在保护进程。直连 `api-server` 的极高 RPS 压测若出现 `connection refused`,通常已经打到 TCP 监听 / accept 层,应同时检查 backlog、Nginx upstream keepalive 和前置限流。 - `GENARRATIVE_API_MAX_CONCURRENT_REQUESTS=512` 开启应用内 HTTP 并发背压;`GENARRATIVE_API_GALLERY_MAX_CONCURRENT_REQUESTS=320``GENARRATIVE_API_DETAIL_MAX_CONCURRENT_REQUESTS=64``GENARRATIVE_API_ADMIN_MAX_CONCURRENT_REQUESTS=16` 分别限制公开列表、公开详情和后台 API 热路径。超过许可时直接返回 `429 Too Many Requests``Retry-After: 1``/healthz``/readyz` 不受该限制。这些值不是 RPS 限速;如果压测中 429 上升但内存和 p95 收敛,说明背压正在保护进程。直连 `api-server` 的极高 RPS 压测若出现 `connection refused`,通常已经打到 TCP 监听 / accept 层,应同时检查 backlog、Nginx upstream keepalive 和前置限流。
- `api-server` 正常运行时 `/healthz` 返回进程存活状态,`/readyz` 返回是否仍接收新流量;收到 `SIGINT` / `SIGTERM` 后会先把 readiness 标记为不可用,再让 Axum 停止接新连接并等待已有 HTTP 请求排空。systemd 仍以 `KillSignal=SIGINT` 停服务,`TimeoutStopSec=90` 作为长请求排空上限。 - `api-server` 正常运行时 `/healthz` 返回进程存活状态,`/readyz` 返回是否仍接收新流量;收到 `SIGINT` / `SIGTERM` 后会先把 readiness 标记为不可用,再让 Axum 停止接新连接并等待已有 HTTP 请求排空。systemd 仍以 `KillSignal=SIGINT` 停服务,`TimeoutStopSec=90` 作为长请求排空上限。
- `genarrative-api.service` 设置 `LimitNOFILE=65535``TasksMax=2048`;上线后用 `systemctl show genarrative-api.service -p LimitNOFILE -p TasksMax -p TimeoutStopUSec``cat /proc/$(pidof api-server)/limits` 核对。 - `genarrative-api.service` 设置 `LimitNOFILE=65535``TasksMax=2048`;上线后用 `systemctl show genarrative-api.service -p LimitNOFILE -p TasksMax -p TimeoutStopUSec``cat /proc/$(pidof api-server)/limits` 核对。
- Server provision 不再通过 Windows helper 下载,也不再通过 Linux build 节点中转工具包。`Prepare Provision Tools` 在目标 dev / release agent 工作区内准备 SpacetimeDB `2.4.1``spacetime-x86_64-unknown-linux-gnu.tar.gz` `otelcol-contrib_0.151.0_linux_amd64.tar.gz` 并生成 `provision-tools/`;如果目标服务器下载需要代理,在 `PROVISION_DOWNLOAD_PROXY` 配置目标机可访问的 HTTP 代理。 - Server provision 不再通过 Windows helper 下载,也不再通过 Linux build 节点中转工具包。`Prepare Provision Tools` 在目标 dev / release agent 工作区内先检查 `/usr/local/bin/otelcol-contrib``${SPACETIME_ROOT}/bin/current`:版本已满足时直接复用目标机现有文件生成 `provision-tools/`,只有缺失或版本不匹配时才使用 `PROVISION_DOWNLOADS_DIR` 里的本地包或从配置的下载源准备 SpacetimeDB `2.4.1` / `otelcol-contrib 0.151.0`;如果目标服务器下载需要代理,在 `PROVISION_DOWNLOAD_PROXY` 配置目标机可访问的 HTTP 代理。
-`Genarrative-Server-Provision` 外,`Genarrative-Stdb-Module-Build``Genarrative-Web-Build``Genarrative-Api-Build``Genarrative-*Deploy``Genarrative-Database-Import/Export``Genarrative-Full-Build-And-Deploy``Genarrative-Notify-Email` 的生产流水线现都以 Linux agent 为主,仍按各自 Jenkinsfile 的 checkout 口径执行。Server provision 不使用公网备用 Git 源。 -`Genarrative-Server-Provision` 外,`Genarrative-Stdb-Module-Build``Genarrative-Web-Build``Genarrative-Api-Build``Genarrative-*Deploy``Genarrative-Database-Import/Export``Genarrative-Full-Build-And-Deploy``Genarrative-Notify-Email` 的生产流水线现都以 Linux agent 为主,仍按各自 Jenkinsfile 的 checkout 口径执行。Server provision 不使用公网备用 Git 源。
- `otelcol-contrib.service` 作为可选系统服务加入 provision默认监听 `127.0.0.1:4317/4318` 并使用 `deploy/otelcol/genarrative-debug.yaml`。api-server 是否发送 OTLP 仍由 `GENARRATIVE_OTEL_ENABLED` 控制,服务 unit 见 `deploy/systemd/otelcol-contrib.service` - `otelcol-contrib.service` 作为可选系统服务加入 provision默认监听 `127.0.0.1:4317/4318` 并使用 `deploy/otelcol/genarrative-debug.yaml`。api-server 是否发送 OTLP 仍由 `GENARRATIVE_OTEL_ENABLED` 控制,服务 unit 见 `deploy/systemd/otelcol-contrib.service`
- Nginx `/api/``/admin/api/` 通过 `genarrative_api` upstream 代理到 `127.0.0.1:8082`upstream keepalive 为 64`limit_conn` 负责连接 / 并发保护,`limit_req` 负责入口 RPS 快拒绝。当前模板把公开 gallery list 单独放到 `genarrative_gallery_rps`,默认 `rate=5000r/s``burst=4096``limit_conn=320`;公开详情和普通 API 放到 `genarrative_api_rps`,后台 API 放到 `genarrative_admin_rps`。通用 `/api` location 设置 `client_max_body_size 64m` 是反代兜底,防止拼图入口页 / 新增关卡本地参考图 Data URL 或旧兼容请求在到达 `api-server` 前被默认 1 MiB 上限拦截;拼图本地参考图前后端统一限制 6MB历史图片仍提交 `referenceImageAssetObjectId(s)`。若线上出现 `413 Request Entity Too Large` 且 access log 中 `request_time=0.000``upstream_status=-`,说明请求在 Nginx 层被拦截,先用 `nginx -T | grep client_max_body_size` 检查 release 模板是否已渲染并 reload同时检查前端是否超出 6MB 或错误提交了未压缩大图。`limit_conn_status 429``limit_req_status 429` 必须在 HTTP 与 HTTPS server 中同时生效;若线上压测看到 `limiting connections by zone "genarrative_api_conn"` 却返回 503优先检查 `nginx -T` 里 HTTPS server 是否缺少这些状态码,以及 `/api/runtime/puzzle/gallery` 是否误落到通用 `location ~ ^/api``limit_conn=64`。压测时看 `/var/log/nginx/genarrative.access.log` 中的 `request_time``upstream_connect_time``upstream_header_time``upstream_response_time``upstream_status``request_id` - Nginx `/api/``/admin/api/` 通过 `genarrative_api` upstream 代理到 `127.0.0.1:8082`upstream keepalive 为 64`limit_conn` 负责连接 / 并发保护,`limit_req` 负责入口 RPS 快拒绝。当前模板把公开 gallery list 单独放到 `genarrative_gallery_rps`,默认 `rate=5000r/s``burst=4096``limit_conn=320`;公开详情和普通 API 放到 `genarrative_api_rps`,后台 API 放到 `genarrative_admin_rps`。通用 `/api` location 设置 `client_max_body_size 64m` 是反代兜底,防止拼图入口页 / 新增关卡本地参考图 Data URL 或旧兼容请求在到达 `api-server` 前被默认 1 MiB 上限拦截;拼图本地参考图前后端统一限制 6MB历史图片仍提交 `referenceImageAssetObjectId(s)`。若线上出现 `413 Request Entity Too Large` 且 access log 中 `request_time=0.000``upstream_status=-`,说明请求在 Nginx 层被拦截,先用 `nginx -T | grep client_max_body_size` 检查 release 模板是否已渲染并 reload同时检查前端是否超出 6MB 或错误提交了未压缩大图。`limit_conn_status 429``limit_req_status 429` 必须在 HTTP 与 HTTPS server 中同时生效;若线上压测看到 `limiting connections by zone "genarrative_api_conn"` 却返回 503优先检查 `nginx -T` 里 HTTPS server 是否缺少这些状态码,以及 `/api/runtime/puzzle/gallery` 是否误落到通用 `location ~ ^/api``limit_conn=64`。压测时看 `/var/log/nginx/genarrative.access.log` 中的 `request_time``upstream_connect_time``upstream_header_time``upstream_response_time``upstream_status``request_id`

View File

@@ -164,6 +164,7 @@ BASH
PROVISION_DOWNLOAD_PROXY="${PROVISION_DOWNLOAD_PROXY:-}" \ PROVISION_DOWNLOAD_PROXY="${PROVISION_DOWNLOAD_PROXY:-}" \
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.4.1}" \ SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.4.1}" \
SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}" \ SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}" \
SPACETIME_ROOT="${SPACETIME_ROOT:-/stdb}" \
scripts/prepare-server-provision-tools.sh scripts/prepare-server-provision-tools.sh
' '
''' '''

View File

@@ -0,0 +1,86 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
TMP_ROOT="$(mktemp -d)"
trap 'rm -rf "${TMP_ROOT}"' EXIT
WORK_DIR="${TMP_ROOT}/workspace"
FAKE_BIN_DIR="${TMP_ROOT}/fake-bin"
TARGET_BIN_DIR="${TMP_ROOT}/target-bin"
SPACETIME_ROOT_DIR="${TMP_ROOT}/stdb"
OUTPUT_LOG="${TMP_ROOT}/prepare.log"
mkdir -p \
"${WORK_DIR}" \
"${FAKE_BIN_DIR}" \
"${TARGET_BIN_DIR}" \
"${SPACETIME_ROOT_DIR}/bin/current"
cat >"${FAKE_BIN_DIR}/curl" <<'EOF'
#!/usr/bin/env bash
echo "curl should not be called when target tools are already ready" >&2
exit 97
EOF
cat >"${FAKE_BIN_DIR}/wget" <<'EOF'
#!/usr/bin/env bash
echo "wget should not be called when target tools are already ready" >&2
exit 97
EOF
chmod +x "${FAKE_BIN_DIR}/curl" "${FAKE_BIN_DIR}/wget"
cat >"${TARGET_BIN_DIR}/otelcol-contrib" <<'EOF'
#!/usr/bin/env bash
echo "otelcol-contrib version 0.151.0"
EOF
chmod +x "${TARGET_BIN_DIR}/otelcol-contrib"
cat >"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-cli" <<'EOF'
#!/usr/bin/env bash
echo "spacetimedb-cli 2.4.1"
EOF
cat >"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-standalone" <<'EOF'
#!/usr/bin/env bash
echo "spacetimedb-standalone 2.4.1"
EOF
chmod +x \
"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-cli" \
"${SPACETIME_ROOT_DIR}/bin/current/spacetimedb-standalone"
if ! (
cd "${WORK_DIR}"
PATH="${FAKE_BIN_DIR}:${PATH}" \
WORKSPACE="${WORK_DIR}" \
PROVISION_TOOLS_DIR="provision-tools" \
PROVISION_DOWNLOADS_DIR="downloads" \
PROVISION_TOOLS_TMP_PARENT="${WORK_DIR}/.tmp/server-provision-tools" \
PROVISION_REQUIRE_LOCAL_DOWNLOADS="true" \
OTELCOL_TARGET_BIN="${TARGET_BIN_DIR}/otelcol-contrib" \
OTELCOL_VERSION="0.151.0" \
SPACETIME_ROOT="${SPACETIME_ROOT_DIR}" \
SPACETIME_EXPECTED_VERSION="2.4.1" \
"${REPO_ROOT}/scripts/prepare-server-provision-tools.sh" \
>"${OUTPUT_LOG}" 2>&1
); then
echo "[check-server-provision-tools] prepare-server-provision-tools.sh 执行失败。" >&2
cat "${OUTPUT_LOG}" >&2
exit 1
fi
grep -q "复用目标机已有 otelcol-contrib" "${OUTPUT_LOG}"
grep -q "复用目标机已有 SpacetimeDB 安装" "${OUTPUT_LOG}"
grep -q "otelcol-contrib 0.151.0 target existing" "${WORK_DIR}/provision-tools/MANIFEST.txt"
grep -q "spacetime target existing" "${WORK_DIR}/provision-tools/MANIFEST.txt"
test -x "${WORK_DIR}/provision-tools/otelcol-contrib"
test -x "${WORK_DIR}/provision-tools/spacetime/spacetime"
test -x "${WORK_DIR}/provision-tools/spacetime/bin/current/spacetimedb-cli"
test -x "${WORK_DIR}/provision-tools/spacetime/bin/current/spacetimedb-standalone"
if grep -q "下载 " "${OUTPUT_LOG}"; then
echo "[check-server-provision-tools] 已有目标机工具时不应进入下载分支。" >&2
cat "${OUTPUT_LOG}" >&2
exit 1
fi
echo "[check-server-provision-tools] OK"

View File

@@ -7,9 +7,12 @@ OTELCOL_VERSION="${OTELCOL_VERSION:-0.151.0}"
PREPARE_OTELCOL="${PREPARE_OTELCOL:-${ENABLE_OTELCOL:-true}}" PREPARE_OTELCOL="${PREPARE_OTELCOL:-${ENABLE_OTELCOL:-true}}"
OTELCOL_DOWNLOAD_ROOT="${OTELCOL_DOWNLOAD_ROOT:-https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download}" OTELCOL_DOWNLOAD_ROOT="${OTELCOL_DOWNLOAD_ROOT:-https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download}"
OTELCOL_ARCHIVE_PATH="${OTELCOL_ARCHIVE_PATH:-}" OTELCOL_ARCHIVE_PATH="${OTELCOL_ARCHIVE_PATH:-}"
OTELCOL_TARGET_BIN="${OTELCOL_TARGET_BIN:-/usr/local/bin/otelcol-contrib}"
SPACETIME_INSTALLER_URL="${SPACETIME_INSTALLER_URL:-https://install.spacetimedb.com}" SPACETIME_INSTALLER_URL="${SPACETIME_INSTALLER_URL:-https://install.spacetimedb.com}"
SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.4.1}" SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/download/v2.4.1}"
SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}" SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}"
SPACETIME_ROOT="${SPACETIME_ROOT:-/stdb}"
SPACETIME_EXPECTED_VERSION="${SPACETIME_EXPECTED_VERSION:-}"
SPACETIME_ARCHIVE_PATH="${SPACETIME_ARCHIVE_PATH:-}" SPACETIME_ARCHIVE_PATH="${SPACETIME_ARCHIVE_PATH:-}"
SPACETIME_INSTALLER_PATH="${SPACETIME_INSTALLER_PATH:-}" SPACETIME_INSTALLER_PATH="${SPACETIME_INSTALLER_PATH:-}"
SPACETIME_UPDATE_INSTALLER_PATH="${SPACETIME_UPDATE_INSTALLER_PATH:-}" SPACETIME_UPDATE_INSTALLER_PATH="${SPACETIME_UPDATE_INSTALLER_PATH:-}"
@@ -65,6 +68,60 @@ download_file() {
fi fi
} }
resolve_spacetime_expected_version() {
local download_root="${SPACETIME_DOWNLOAD_ROOT%/}"
if [[ -n "${SPACETIME_EXPECTED_VERSION}" ]]; then
printf "%s" "${SPACETIME_EXPECTED_VERSION}"
return
fi
if [[ "${download_root}" =~ /v([0-9]+(\.[0-9]+){1,2})$ ]]; then
printf "%s" "${BASH_REMATCH[1]}"
fi
}
target_otelcol_ready() {
local version_output
echo "[prepare-provision-tools] 检查目标机 otelcol-contrib: ${OTELCOL_TARGET_BIN}"
if [[ ! -x "${OTELCOL_TARGET_BIN}" ]]; then
echo "[prepare-provision-tools] 目标机 otelcol-contrib 不存在或不可执行,将准备交付文件。"
return 1
fi
version_output="$("${OTELCOL_TARGET_BIN}" --version 2>/dev/null || true)"
if [[ -n "${OTELCOL_VERSION}" && "${version_output}" != *"${OTELCOL_VERSION}"* ]]; then
echo "[prepare-provision-tools] 目标机 otelcol-contrib 版本不匹配,期望 ${OTELCOL_VERSION},当前: ${version_output:-unknown}"
return 1
fi
echo "[prepare-provision-tools] 目标机 otelcol-contrib 已满足要求: ${version_output:-version unknown}"
return 0
}
target_spacetime_ready() {
local target_cli="${SPACETIME_ROOT}/bin/current/spacetimedb-cli"
local target_standalone="${SPACETIME_ROOT}/bin/current/spacetimedb-standalone"
local expected_version version_output
echo "[prepare-provision-tools] 检查目标机 SpacetimeDB: ${SPACETIME_ROOT}/bin/current"
if [[ ! -x "${target_cli}" || ! -x "${target_standalone}" ]]; then
echo "[prepare-provision-tools] 目标机 SpacetimeDB current 目录不完整,将准备交付文件。"
return 1
fi
expected_version="$(resolve_spacetime_expected_version)"
version_output="$("${target_cli}" --version 2>/dev/null || true)"
if [[ -n "${expected_version}" && "${version_output}" != *"${expected_version}"* ]]; then
echo "[prepare-provision-tools] 目标机 SpacetimeDB 版本不匹配,期望 ${expected_version},当前: ${version_output:-unknown}"
return 1
fi
echo "[prepare-provision-tools] 目标机 SpacetimeDB 已满足要求: ${version_output:-version unknown}"
return 0
}
validate_relative_dir() { validate_relative_dir() {
local label="$1" local label="$1"
local path="$2" local path="$2"
@@ -101,13 +158,21 @@ prepare_otelcol() {
require_cmd tar require_cmd tar
if target_otelcol_ready; then
echo "[prepare-provision-tools] 复用目标机已有 otelcol-contrib: ${OTELCOL_TARGET_BIN}"
install -m 0755 "${OTELCOL_TARGET_BIN}" "${target}"
"${target}" --version >/dev/null
OTELCOL_SOURCE_DESCRIPTION="target existing ${OTELCOL_TARGET_BIN}"
return
fi
if [[ -n "${OTELCOL_ARCHIVE_PATH}" && -f "${OTELCOL_ARCHIVE_PATH}" ]]; then if [[ -n "${OTELCOL_ARCHIVE_PATH}" && -f "${OTELCOL_ARCHIVE_PATH}" ]]; then
source_archive="${OTELCOL_ARCHIVE_PATH}" source_archive="${OTELCOL_ARCHIVE_PATH}"
elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_archive}" ]]; then elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_archive}" ]]; then
source_archive="${downloaded_archive}" source_archive="${downloaded_archive}"
fi fi
if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then
echo "[prepare-provision-tools] 要求使用 Windows 已下载的 otelcol-contrib 包,但未找到: ${downloaded_archive}" >&2 echo "[prepare-provision-tools] 要求使用本地已有的 otelcol-contrib 来源,但目标机未满足且未找到下载包: ${downloaded_archive}" >&2
exit 1 exit 1
fi fi
@@ -146,6 +211,17 @@ prepare_spacetime() {
local downloaded_installer="${PROVISION_DOWNLOADS_DIR}/spacetime-install.sh" local downloaded_installer="${PROVISION_DOWNLOADS_DIR}/spacetime-install.sh"
local source_installer="" local source_installer=""
if target_spacetime_ready; then
echo "[prepare-provision-tools] 复用目标机已有 SpacetimeDB 安装: ${SPACETIME_ROOT}/bin/current"
mkdir -p "${target_dir}"
cp -a "${SPACETIME_ROOT}/bin" "${target_dir}/bin"
chmod 0755 "${target_dir}/bin/current/spacetimedb-cli" "${target_dir}/bin/current/spacetimedb-standalone"
make_spacetime_wrapper "${target_dir}/spacetime"
"${target_dir}/spacetime" --version >/dev/null
SPACETIME_SOURCE_DESCRIPTION="target existing ${SPACETIME_ROOT}/bin/current"
return
fi
mkdir -p "${install_root}" mkdir -p "${install_root}"
if [[ -n "${SPACETIME_ARCHIVE_PATH}" && -f "${SPACETIME_ARCHIVE_PATH}" ]]; then if [[ -n "${SPACETIME_ARCHIVE_PATH}" && -f "${SPACETIME_ARCHIVE_PATH}" ]]; then
source_archive="${SPACETIME_ARCHIVE_PATH}" source_archive="${SPACETIME_ARCHIVE_PATH}"
@@ -165,7 +241,7 @@ prepare_spacetime() {
source_update="${downloaded_update}" source_update="${downloaded_update}"
fi fi
if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then
echo "[prepare-provision-tools] 要求使用 Windows 已下载的 SpacetimeDB release tarball未找到: ${downloaded_archive}" >&2 echo "[prepare-provision-tools] 要求使用本地已有的 SpacetimeDB release tarball目标机未满足且未找到下载包: ${downloaded_archive}" >&2
exit 1 exit 1
fi fi
@@ -185,7 +261,7 @@ prepare_spacetime() {
fi fi
if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_installer}" ]]; then if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_installer}" ]]; then
echo "[prepare-provision-tools] 要求使用 Windows 已下载的 SpacetimeDB 官方安装器脚本,但未找到: ${downloaded_installer}" >&2 echo "[prepare-provision-tools] 要求使用本地已有的 SpacetimeDB 官方安装器脚本,但未找到: ${downloaded_installer}" >&2
exit 1 exit 1
elif [[ -n "${source_installer}" ]]; then elif [[ -n "${source_installer}" ]]; then
echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB 官方安装器脚本: ${source_installer}" echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB 官方安装器脚本: ${source_installer}"