2dac4a69fd
精确锁定 SpacetimeDB Rust crate 并更新依赖锁文件 使用 2.6.0 CLI 重新生成 Rust bindings 对齐容器镜像、server provision 与本地版本校验 更新运维文档、项目记忆与 SpacetimeDB skills 版本口径
340 lines
13 KiB
Bash
Executable File
340 lines
13 KiB
Bash
Executable File
#!/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.6.0}"
|
|
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 "$@"
|