Files
easyai/scripts/deployment-runtime.sh
T

84 lines
3.8 KiB
Bash

#!/bin/bash
# Shared installation/update checks. Never print compose config or credentials.
init_deployment_docker_config() {
local file="$1" configured fallback
configured="$(read_env_value "$file" DOCKER_CONFIG_FILE)"
if [ -n "$configured" ] && [ -f "$configured" ]; then return 0; fi
if [ -n "$configured" ] && [ "$configured" != /root/.docker/config.json ]; then
echo '❌ DOCKER_CONFIG_FILE 不是可读取的配置文件;未启动服务' >&2
return 1
fi
if [ -f "${DOCKER_CONFIG:-$HOME/.docker}/config.json" ]; then
write_env_value "$file" DOCKER_CONFIG_FILE "${DOCKER_CONFIG:-$HOME/.docker}/config.json"
return 0
fi
# Anonymous installations have no ~/.docker/config.json. A missing short
# bind source would otherwise be created by Docker as a DIRECTORY.
fallback="$PWD/data/docker-auth/config.json"
mkdir -p "$(dirname "$fallback")"
chmod 700 "$(dirname "$fallback")"
if [ ! -e "$fallback" ]; then (umask 077; printf '{}\n' > "$fallback"); fi
[ -f "$fallback" ] || { echo '❌ 安装目录的镜像认证配置不是文件' >&2; return 1; }
write_env_value "$file" DOCKER_CONFIG_FILE "$fallback"
}
verify_deployment_images() {
local compose="$1" configuration
shift
configuration="$(sudo $compose config --format json)" || return 1
printf '%s' "$configuration" | python3 ./scripts/verify-deployment-images.py --sudo --services "$@"
}
check_deployment_storage() {
local compose="$1" configuration
shift
configuration="$(sudo $compose config --format json)" || return 1
printf '%s' "$configuration" | python3 ./scripts/check-deployment-storage.py --sudo --services "$@"
}
verify_pulled_release() {
local compose="$1" configuration
shift
configuration="$(sudo $compose config --format json)" || return 1
printf '%s' "$configuration" | python3 ./scripts/verify-pulled-release.py --sudo --services "$@"
}
wait_for_deployment_services() {
local compose="$1" timeout="$2" deadline service container_id state running health all_ready passes=0
shift 2
local services=("$@")
[[ "$timeout" =~ ^[1-9][0-9]*$ ]] || { echo '❌ 健康检查等待秒数必须为正整数' >&2; return 1; }
if [ "${#services[@]}" -eq 0 ]; then
while IFS= read -r service; do [ -z "$service" ] || services+=("$service"); done < <(sudo $compose config --services)
fi
[ "${#services[@]}" -gt 0 ] || return 1
deadline=$((SECONDS + timeout))
echo "⏳ 等待 ${#services[@]} 个服务恢复可用(最长 ${timeout} 秒)..."
while (( SECONDS < deadline )); do
all_ready=true
for service in "${services[@]}"; do
container_id="$(sudo $compose ps -q "$service" 2>/dev/null || true)"
if [ -z "$container_id" ]; then all_ready=false; continue; fi
state="$(sudo docker inspect --format '{{.State.Running}}|{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$container_id" 2>/dev/null || true)"
running="${state%%|*}"; health="${state#*|}"
if [ "$running" != true ] || { [ "$health" != none ] && [ "$health" != healthy ]; }; then
all_ready=false
elif [ "$service" = watchtower ] && [ "$health" = none ]; then
sudo docker exec "$container_id" /watchtower --health-check >/dev/null 2>&1 || all_ready=false
fi
done
if [ "$all_ready" = true ]; then
passes=$((passes + 1))
if [ "$passes" -ge 2 ]; then echo '✅ 所选服务已恢复可用'; return 0; fi
sleep 2
else
passes=0
sleep 5
fi
done
echo '❌ 服务未在规定时间内恢复可用,部署未完成' >&2
sudo $compose ps "${services[@]}" || true
echo "请运行:$compose logs --tail=100 ${services[*]}" >&2
return 1
}