hy-app-monitor/testbox/scripts/auto-pull-restart.sh

343 lines
11 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="${ROOT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
cd "$ROOT_DIR"
LOG_FILE="${TESTBOX_AUTODEPLOY_LOG_FILE:-$ROOT_DIR/logs/auto-deploy.log}"
LOCK_FILE="${TESTBOX_DEPLOY_LOCK_FILE:-$ROOT_DIR/run/deploy.lock}"
mkdir -p "$ROOT_DIR/logs" "$ROOT_DIR/run"
env_value() {
python3 "$ROOT_DIR/scripts/env-value.py" "$ROOT_DIR/.env" "$1" "${2:-}"
}
log() {
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG_FILE"
}
compose() {
docker compose --env-file .env -f docker-compose.infra.yml -f docker-compose.apps.yml "$@"
}
repo_changed() {
local dir="$1"
local url="$2"
local branch="$3"
local label="$4"
local before=""
local after=""
mkdir -p "$(dirname "$dir")"
if [ -e "$dir" ] && [ ! -d "$dir/.git" ]; then
mv "$dir" "$dir.pre-auto-git-$(date +%Y%m%d%H%M%S)"
fi
if [ ! -d "$dir/.git" ]; then
log "$label clone branch=$branch"
git clone --branch "$branch" "$url" "$dir"
git -C "$dir" rev-parse HEAD >"$ROOT_DIR/run/$label.after"
return 0
fi
before="$(git -C "$dir" rev-parse HEAD 2>/dev/null || true)"
if ! git -C "$dir" fetch --prune origin "$branch" >>"$LOG_FILE" 2>&1; then
log "$label fetch failed branch=$branch"
return 2
fi
git -C "$dir" checkout -B "$branch" "origin/$branch" >>"$LOG_FILE" 2>&1
git -C "$dir" reset --hard "origin/$branch" >>"$LOG_FILE" 2>&1
after="$(git -C "$dir" rev-parse HEAD)"
printf '%s\n' "$before" >"$ROOT_DIR/run/$label.before"
printf '%s\n' "$after" >"$ROOT_DIR/run/$label.after"
if [ "$before" != "$after" ]; then
log "$label changed ${before:-none} -> $after"
return 0
fi
return 10
}
unique_words() {
tr ' ' '\n' | awk 'NF && !seen[$0]++' | tr '\n' ' ' | sed 's/[[:space:]]*$//'
}
all_java_services() {
printf '%s\n' "auth gateway external console other live wallet order"
}
java_module_for_service() {
case "$1" in
auth) echo "rc-auth" ;;
gateway) echo "rc-gateway" ;;
external) echo "rc-service/rc-service-external/external-start" ;;
console) echo "rc-service/rc-service-console/console-start" ;;
other) echo "rc-service/rc-service-other/other-start" ;;
live) echo "rc-service/rc-service-live/live-start" ;;
wallet) echo "rc-service/rc-service-wallet/wallet-start" ;;
order) echo "rc-service/rc-service-order/order-start" ;;
*) return 1 ;;
esac
}
clean_java_service_jars() {
local java_dir="$1"
shift
local service
for service in "$@"; do
case "$service" in
auth)
rm -f "$java_dir/rc-auth/target/rc-auth-"*.jar "$java_dir/rc-auth/target/rc-auth-"*.jar.original
;;
gateway)
rm -f "$java_dir/rc-gateway/target/rc-gateway-"*.jar "$java_dir/rc-gateway/target/rc-gateway-"*.jar.original
;;
external)
rm -f "$java_dir/rc-service/rc-service-external/external-start/target/rc-service-external-"*.jar "$java_dir/rc-service/rc-service-external/external-start/target/rc-service-external-"*.jar.original
;;
console)
rm -f "$java_dir/rc-service/rc-service-console/console-start/target/rc-service-console-"*.jar "$java_dir/rc-service/rc-service-console/console-start/target/rc-service-console-"*.jar.original
;;
other)
rm -f "$java_dir/rc-service/rc-service-other/other-start/target/rc-service-other-"*.jar "$java_dir/rc-service/rc-service-other/other-start/target/rc-service-other-"*.jar.original
;;
live)
rm -f "$java_dir/rc-service/rc-service-live/live-start/target/rc-service-live-"*.jar "$java_dir/rc-service/rc-service-live/live-start/target/rc-service-live-"*.jar.original
;;
wallet)
rm -f "$java_dir/rc-service/rc-service-wallet/wallet-start/target/rc-service-wallet-"*.jar "$java_dir/rc-service/rc-service-wallet/wallet-start/target/rc-service-wallet-"*.jar.original
;;
order)
rm -f "$java_dir/rc-service/rc-service-order/order-start/target/rc-service-order-"*.jar "$java_dir/rc-service/rc-service-order/order-start/target/rc-service-order-"*.jar.original
;;
*)
return 1
;;
esac
done
}
service_for_java_path() {
case "$1" in
rc-auth/*|nacos_config/rc-auth/*) echo "auth" ;;
rc-gateway/*|nacos_config/rc-gateway/*) echo "gateway" ;;
rc-service/rc-service-external/*|nacos_config/rc-service-external/*) echo "external" ;;
rc-service/rc-service-console/*|nacos_config/rc-service-console/*) echo "console" ;;
rc-service/rc-service-other/*|nacos_config/rc-service-other/*) echo "other" ;;
rc-service/rc-service-live/*|nacos_config/rc-service-live/*) echo "live" ;;
rc-service/rc-service-wallet/*|nacos_config/rc-service-wallet/*) echo "wallet" ;;
rc-service/rc-service-order/*|nacos_config/rc-service-order/*) echo "order" ;;
nacos_config/common/*|pom.xml|*/pom.xml|rc-common*/*|rc-service/rc-inner-api/*|ci/*)
all_java_services
;;
sql/*)
;;
*)
all_java_services
;;
esac
}
java_changed_services() {
local before="$1"
local after="$2"
local java_dir="$3"
local changed_paths
local services=""
local path
if [ -z "$before" ]; then
all_java_services
return 0
fi
changed_paths="$(git -C "$java_dir" diff --name-only "$before" "$after" || true)"
while IFS= read -r path; do
[ -n "$path" ] || continue
services="$services $(service_for_java_path "$path" | tr '\n' ' ')"
done <<< "$changed_paths"
printf '%s\n' "$services" | unique_words
}
build_and_restart_java() {
local java_dir="$1"
shift
local services=("$@")
local modules=""
local compose_services=""
local service
[ "${#services[@]}" -gt 0 ] || return 0
for service in "${services[@]}"; do
modules="${modules:+$modules,}$(java_module_for_service "$service")"
compose_services="$compose_services $service"
done
log "java build services=${services[*]} modules=$modules"
cd "$java_dir"
if [ -x ./ci/install-private-maven.sh ]; then
./ci/install-private-maven.sh >>"$LOG_FILE" 2>&1
fi
clean_java_service_jars "$java_dir" "${services[@]}"
mvn -Ptest -T 1C -pl "$modules" -am -Dmaven.test.skip=true package >>"$LOG_FILE" 2>&1
cd "$ROOT_DIR"
python3 scripts/import-nacos-configs.py >>"$LOG_FILE" 2>&1
TESTBOX_APPLY_JAVA_SQL=1 scripts/apply-mysql-baseline.sh >>"$LOG_FILE" 2>&1
compose build "${services[@]}" >>"$LOG_FILE" 2>&1
for service in "${services[@]}"; do
log "java restart service=$service"
compose up -d --no-deps --force-recreate "$service" >>"$LOG_FILE" 2>&1
done
compose ps "${services[@]}" | tee -a "$LOG_FILE"
}
build_and_restart_golang() {
log "golang build/restart"
scripts/apply-mysql-baseline.sh >>"$LOG_FILE" 2>&1
compose build golang >>"$LOG_FILE" 2>&1
compose up -d --no-deps --force-recreate golang >>"$LOG_FILE" 2>&1
compose ps golang | tee -a "$LOG_FILE"
}
build_and_restart_cron() {
log "cron build/restart"
compose build chatapp-cron >>"$LOG_FILE" 2>&1
compose up -d --no-deps --force-recreate chatapp-cron >>"$LOG_FILE" 2>&1
compose ps chatapp-cron | tee -a "$LOG_FILE"
}
build_and_restart_admin() {
local admin_dir="$1"
local admin_api_base_url
local admin_oss_url
admin_api_base_url="$(env_value TESTBOX_ADMIN_API_BASE_URL "https://yumi-test-admin.haiyihy.com/console")"
admin_oss_url="$(env_value TESTBOX_ADMIN_OSS_URL "")"
log "admin build/restart"
docker build \
-f "$ROOT_DIR/docker/chatapp3-admin.Dockerfile" \
--build-arg "ADMIN_API_BASE_URL=$admin_api_base_url" \
--build-arg "ADMIN_OSS_URL=$admin_oss_url" \
-t chatapp-test/admin:testbox \
"$admin_dir" >>"$LOG_FILE" 2>&1
compose up -d --no-deps --force-recreate admin >>"$LOG_FILE" 2>&1
compose ps admin | tee -a "$LOG_FILE"
}
run_once() {
local java_repo_url golang_repo_url cron_repo_url admin_repo_url
local java_branch golang_branch cron_branch admin_branch
local java_dir golang_dir cron_dir admin_dir
local rc
local java_before java_after
local services_line
exec 9>&- 2>/dev/null || true
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
log "deploy lock busy; skip this tick"
exec 9>&-
return 0
fi
java_repo_url="$(env_value JAVA_REPO_URL git@gitea.haiyihy.com:hy/chatapp3-java.git)"
golang_repo_url="$(env_value GOLANG_REPO_URL git@gitea.haiyihy.com:hy/chatapp3-golang.git)"
cron_repo_url="$(env_value CRON_REPO_URL git@gitea.haiyihy.com:hy/chatapp-cron.git)"
admin_repo_url="$(env_value ADMIN_REPO_URL git@gitea.haiyihy.com:hy/chatapp3-admin.git)"
java_branch="$(env_value TESTBOX_AUTODEPLOY_JAVA_BRANCH test)"
golang_branch="$(env_value TESTBOX_AUTODEPLOY_GOLANG_BRANCH test)"
cron_branch="$(env_value TESTBOX_AUTODEPLOY_CRON_BRANCH test)"
admin_branch="$(env_value TESTBOX_AUTODEPLOY_ADMIN_BRANCH test)"
java_dir="$(env_value JAVA_SOURCE_DIR "$ROOT_DIR/sources/chatapp3-java")"
golang_dir="$(env_value GOLANG_SOURCE_DIR "$ROOT_DIR/sources/chatapp3-golang")"
cron_dir="$(env_value CRON_SOURCE_DIR "$ROOT_DIR/sources/chatapp-cron")"
admin_dir="$(env_value ADMIN_SOURCE_DIR "$ROOT_DIR/sources/chatapp3-admin")"
rc=0
if repo_changed "$java_dir" "$java_repo_url" "$java_branch" java; then
java_before="$(cat "$ROOT_DIR/run/java.before" 2>/dev/null || true)"
java_after="$(cat "$ROOT_DIR/run/java.after" 2>/dev/null || true)"
services_line="$(java_changed_services "$java_before" "$java_after" "$java_dir")"
if [ -n "$services_line" ]; then
# shellcheck disable=SC2206
local java_services=($services_line)
build_and_restart_java "$java_dir" "${java_services[@]}"
else
log "java changed without service rebuild target; applying SQL/Nacos only"
python3 scripts/import-nacos-configs.py >>"$LOG_FILE" 2>&1
TESTBOX_APPLY_JAVA_SQL=1 scripts/apply-mysql-baseline.sh >>"$LOG_FILE" 2>&1
fi
else
rc=$?
[ "$rc" -eq 10 ] || log "java update skipped due to error rc=$rc"
fi
rc=0
if repo_changed "$golang_dir" "$golang_repo_url" "$golang_branch" golang; then
build_and_restart_golang
else
rc=$?
[ "$rc" -eq 10 ] || log "golang update skipped due to error rc=$rc"
fi
rc=0
if repo_changed "$cron_dir" "$cron_repo_url" "$cron_branch" cron; then
build_and_restart_cron
else
rc=$?
[ "$rc" -eq 10 ] || log "cron update skipped due to error rc=$rc"
fi
rc=0
if repo_changed "$admin_dir" "$admin_repo_url" "$admin_branch" admin; then
build_and_restart_admin "$admin_dir"
else
rc=$?
[ "$rc" -eq 10 ] || log "admin update skipped due to error rc=$rc"
fi
flock -u 9
exec 9>&-
}
usage() {
cat <<'EOF'
Usage:
auto-pull-restart.sh # loop forever
auto-pull-restart.sh --once # run one poll cycle
Reads TESTBOX_AUTODEPLOY_* from /opt/chatapp-test/.env.
EOF
}
case "${1:-}" in
--once)
run_once
;;
-h|--help)
usage
;;
"")
interval="$(env_value TESTBOX_AUTODEPLOY_INTERVAL_SECONDS 30)"
log "auto deploy loop started interval=${interval}s"
while true; do
if ! run_once; then
log "auto deploy tick failed"
fi
sleep "$interval"
done
;;
*)
usage >&2
exit 2
;;
esac