Files
Genarrative/scripts/prepare-server-provision-tools.sh
kdletters 7aafb37f04 修复 Server-Provision 按目标状态准备工具包
新增目标机已有 SpacetimeDB 与 otelcol-contrib 时复用本机安装的准备逻辑
补充 Prepare Provision Tools 传入 SPACETIME_ROOT,避免非默认路径检查错目录
新增 Server-Provision 工具准备回归检查脚本,防止已有工具时仍触发下载
更新开发运维文档与 Hermes 共享记忆,沉淀先检查目标机状态再准备文件的约定
2026-06-10 11:10:29 +08:00

340 lines
13 KiB
Bash
Executable File
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.
#!/usr/bin/env bash
set -euo pipefail
PROVISION_TOOLS_DIR="${PROVISION_TOOLS_DIR:-provision-tools}"
PROVISION_DOWNLOADS_DIR="${PROVISION_DOWNLOADS_DIR:-}"
OTELCOL_VERSION="${OTELCOL_VERSION:-0.151.0}"
PREPARE_OTELCOL="${PREPARE_OTELCOL:-${ENABLE_OTELCOL:-true}}"
OTELCOL_DOWNLOAD_ROOT="${OTELCOL_DOWNLOAD_ROOT:-https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download}"
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_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_ROOT="${SPACETIME_ROOT:-/stdb}"
SPACETIME_EXPECTED_VERSION="${SPACETIME_EXPECTED_VERSION:-}"
SPACETIME_ARCHIVE_PATH="${SPACETIME_ARCHIVE_PATH:-}"
SPACETIME_INSTALLER_PATH="${SPACETIME_INSTALLER_PATH:-}"
SPACETIME_UPDATE_INSTALLER_PATH="${SPACETIME_UPDATE_INSTALLER_PATH:-}"
PROVISION_DOWNLOAD_PROXY="${PROVISION_DOWNLOAD_PROXY:-}"
PROVISION_NO_PROXY="${PROVISION_NO_PROXY:-127.0.0.1,localhost}"
PROVISION_REQUIRE_LOCAL_DOWNLOADS="${PROVISION_REQUIRE_LOCAL_DOWNLOADS:-false}"
PROVISION_TOOLS_TMP_PARENT="${PROVISION_TOOLS_TMP_PARENT:-${WORKSPACE:-$(pwd)}/.tmp/server-provision-tools}"
TMP_DIR_TO_CLEAN=""
OTELCOL_SOURCE_DESCRIPTION="skipped"
SPACETIME_SOURCE_DESCRIPTION="unset"
cleanup_tmp_dir() {
if [[ -n "${TMP_DIR_TO_CLEAN}" ]]; then
rm -rf "${TMP_DIR_TO_CLEAN}"
fi
}
require_cmd() {
local name="$1"
if ! command -v "${name}" >/dev/null 2>&1; then
echo "[prepare-provision-tools] 缺少命令: ${name}" >&2
exit 1
fi
}
configure_download_proxy() {
if [[ -z "${PROVISION_DOWNLOAD_PROXY}" ]]; then
return
fi
export HTTP_PROXY="${PROVISION_DOWNLOAD_PROXY}"
export HTTPS_PROXY="${PROVISION_DOWNLOAD_PROXY}"
export ALL_PROXY="${PROVISION_DOWNLOAD_PROXY}"
export http_proxy="${PROVISION_DOWNLOAD_PROXY}"
export https_proxy="${PROVISION_DOWNLOAD_PROXY}"
export all_proxy="${PROVISION_DOWNLOAD_PROXY}"
export NO_PROXY="${PROVISION_NO_PROXY}"
export no_proxy="${PROVISION_NO_PROXY}"
echo "[prepare-provision-tools] 已配置下载代理: ${PROVISION_DOWNLOAD_PROXY%%://*}://***"
}
download_file() {
local url="$1"
local output="$2"
if command -v curl >/dev/null 2>&1; then
curl -fsSL --retry 3 --retry-delay 2 "${url}" -o "${output}"
elif command -v wget >/dev/null 2>&1; then
wget -O "${output}" "${url}"
else
echo "[prepare-provision-tools] 需要 curl 或 wget 下载: ${url}" >&2
exit 1
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() {
local label="$1"
local path="$2"
if [[ -z "${path}" ]]; then
return
fi
if [[ "${path}" == /* || "${path}" == *..* || "${path}" == "." ]]; then
echo "[prepare-provision-tools] ${label} 只能是工作区内的相对路径: ${path}" >&2
exit 1
fi
}
make_spacetime_wrapper() {
local target="$1"
cat >"${target}" <<'EOF'
#!/usr/bin/env sh
set -eu
SELF_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
exec "$SELF_DIR/bin/current/spacetimedb-cli" "$@"
EOF
chmod 0755 "${target}"
}
prepare_otelcol() {
local tmp_dir="$1"
local archive="${tmp_dir}/otelcol-contrib.tar.gz"
local extract_dir="${tmp_dir}/otelcol-contrib"
local url="${OTELCOL_DOWNLOAD_ROOT}/v${OTELCOL_VERSION}/otelcol-contrib_${OTELCOL_VERSION}_linux_amd64.tar.gz"
local downloaded_archive="${PROVISION_DOWNLOADS_DIR}/otelcol-contrib_${OTELCOL_VERSION}_linux_amd64.tar.gz"
local source_archive=""
local target="${PROVISION_TOOLS_DIR}/otelcol-contrib"
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
source_archive="${OTELCOL_ARCHIVE_PATH}"
elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_archive}" ]]; then
source_archive="${downloaded_archive}"
fi
if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then
echo "[prepare-provision-tools] 要求使用本地已有的 otelcol-contrib 来源,但目标机未满足且未找到下载包: ${downloaded_archive}" >&2
exit 1
fi
mkdir -p "${extract_dir}"
if [[ -n "${source_archive}" ]]; then
echo "[prepare-provision-tools] 使用已下载的 otelcol-contrib 包: ${source_archive}"
cp "${source_archive}" "${archive}"
OTELCOL_SOURCE_DESCRIPTION="local ${source_archive}"
else
echo "[prepare-provision-tools] 下载 otelcol-contrib: ${url}"
download_file "${url}" "${archive}"
OTELCOL_SOURCE_DESCRIPTION="download ${url}"
fi
tar -xzf "${archive}" -C "${extract_dir}"
if [[ ! -x "${extract_dir}/otelcol-contrib" ]]; then
echo "[prepare-provision-tools] otelcol-contrib 包中缺少可执行文件。" >&2
exit 1
fi
install -m 0755 "${extract_dir}/otelcol-contrib" "${target}"
"${target}" --version >/dev/null
}
prepare_spacetime() {
local tmp_dir="$1"
local install_root="${tmp_dir}/spacetime-root"
local target_dir="${PROVISION_TOOLS_DIR}/spacetime"
local archive_name="spacetime-${SPACETIME_TARGET_HOST}.tar.gz"
local downloaded_archive="${PROVISION_DOWNLOADS_DIR}/${archive_name}"
local source_archive=""
local update_name="spacetimedb-update-${SPACETIME_TARGET_HOST}"
local downloaded_update="${PROVISION_DOWNLOADS_DIR}/${update_name}"
local source_update=""
local prepared_update="${tmp_dir}/spacetimedb-update"
local downloaded_installer="${PROVISION_DOWNLOADS_DIR}/spacetime-install.sh"
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}"
if [[ -n "${SPACETIME_ARCHIVE_PATH}" && -f "${SPACETIME_ARCHIVE_PATH}" ]]; then
source_archive="${SPACETIME_ARCHIVE_PATH}"
elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_archive}" ]]; then
source_archive="${downloaded_archive}"
fi
if [[ -n "${source_archive}" ]]; then
echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB release tarball: ${source_archive}"
mkdir -p "${install_root}/bin/current"
tar -xzf "${source_archive}" -C "${install_root}/bin/current"
chmod 0755 "${install_root}/bin/current/spacetimedb-cli" "${install_root}/bin/current/spacetimedb-standalone"
SPACETIME_SOURCE_DESCRIPTION="local archive ${source_archive}"
elif [[ -n "${SPACETIME_UPDATE_INSTALLER_PATH}" && -f "${SPACETIME_UPDATE_INSTALLER_PATH}" ]]; then
source_update="${SPACETIME_UPDATE_INSTALLER_PATH}"
elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_update}" ]]; then
source_update="${downloaded_update}"
fi
if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then
echo "[prepare-provision-tools] 要求使用本地已有的 SpacetimeDB release tarball但目标机未满足且未找到下载包: ${downloaded_archive}" >&2
exit 1
fi
if [[ -n "${source_archive}" ]]; then
:
elif [[ -n "${source_update}" ]]; then
echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB Linux update installer: ${source_update}"
cp "${source_update}" "${prepared_update}"
chmod 0755 "${prepared_update}"
TMPDIR="${tmp_dir}" "${prepared_update}" --root-dir "${install_root}" -y
SPACETIME_SOURCE_DESCRIPTION="local update ${source_update}"
else
if [[ -n "${SPACETIME_INSTALLER_PATH}" && -f "${SPACETIME_INSTALLER_PATH}" ]]; then
source_installer="${SPACETIME_INSTALLER_PATH}"
elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_installer}" ]]; then
source_installer="${downloaded_installer}"
fi
if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_installer}" ]]; then
echo "[prepare-provision-tools] 要求使用本地已有的 SpacetimeDB 官方安装器脚本,但未找到: ${downloaded_installer}" >&2
exit 1
elif [[ -n "${source_installer}" ]]; then
echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB 官方安装器脚本: ${source_installer}"
cp "${source_installer}" "${tmp_dir}/spacetime-install.sh"
else
echo "[prepare-provision-tools] 下载 SpacetimeDB 官方安装器脚本: ${SPACETIME_INSTALLER_URL}"
download_file "${SPACETIME_INSTALLER_URL}" "${tmp_dir}/spacetime-install.sh"
fi
chmod 0755 "${tmp_dir}/spacetime-install.sh"
TMPDIR="${tmp_dir}" SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT}" sh "${tmp_dir}/spacetime-install.sh" --root-dir "${install_root}" -y
SPACETIME_SOURCE_DESCRIPTION="installer ${SPACETIME_INSTALLER_URL}; download root ${SPACETIME_DOWNLOAD_ROOT}"
fi
if [[ ! -x "${install_root}/bin/current/spacetimedb-cli" ]]; then
echo "[prepare-provision-tools] SpacetimeDB 安装结果缺少 bin/current/spacetimedb-cli。" >&2
exit 1
fi
if [[ ! -x "${install_root}/bin/current/spacetimedb-standalone" ]]; then
echo "[prepare-provision-tools] SpacetimeDB 安装结果缺少 bin/current/spacetimedb-standalone。" >&2
exit 1
fi
mkdir -p "${target_dir}"
cp -a "${install_root}/bin" "${target_dir}/bin"
make_spacetime_wrapper "${target_dir}/spacetime"
"${target_dir}/spacetime" --version >/dev/null
}
main() {
local tmp_dir
require_cmd chmod
require_cmd cp
require_cmd install
require_cmd mktemp
require_cmd rm
require_cmd tar
validate_relative_dir "PROVISION_TOOLS_DIR" "${PROVISION_TOOLS_DIR}"
validate_relative_dir "PROVISION_DOWNLOADS_DIR" "${PROVISION_DOWNLOADS_DIR}"
if [[ -n "${PROVISION_DOWNLOADS_DIR}" && "${PROVISION_DOWNLOADS_DIR%/}" == "${PROVISION_TOOLS_DIR%/}" ]]; then
echo "[prepare-provision-tools] PROVISION_DOWNLOADS_DIR 不能等于 PROVISION_TOOLS_DIR否则会被清理: ${PROVISION_DOWNLOADS_DIR}" >&2
exit 1
fi
configure_download_proxy
mkdir -p "${PROVISION_TOOLS_TMP_PARENT}"
tmp_dir="$(mktemp -d "${PROVISION_TOOLS_TMP_PARENT%/}/run.XXXXXX")"
TMP_DIR_TO_CLEAN="${tmp_dir}"
trap cleanup_tmp_dir EXIT
rm -rf "${PROVISION_TOOLS_DIR}"
mkdir -p "${PROVISION_TOOLS_DIR}"
if [[ "${PREPARE_OTELCOL}" == "true" ]]; then
prepare_otelcol "${tmp_dir}"
else
echo "[prepare-provision-tools] PREPARE_OTELCOL=${PREPARE_OTELCOL},跳过 otelcol-contrib 工具包准备。"
fi
prepare_spacetime "${tmp_dir}"
cat >"${PROVISION_TOOLS_DIR}/MANIFEST.txt" <<EOF
otelcol-contrib ${OTELCOL_VERSION} ${OTELCOL_SOURCE_DESCRIPTION}
spacetime ${SPACETIME_SOURCE_DESCRIPTION}
spacetime target host ${SPACETIME_TARGET_HOST}
require local downloads ${PROVISION_REQUIRE_LOCAL_DOWNLOADS}
EOF
echo "[prepare-provision-tools] 工具包已准备: ${PROVISION_TOOLS_DIR}"
find "${PROVISION_TOOLS_DIR}" -maxdepth 5 \( -type f -o -type l \) | sort
}
main "$@"