Add monitoring metrics, numeric sorting, report-time display, vehicle number labels, and map layout fixes. Include accumulated mileage, hydrogen, OneOS authentication, open platform, ingestion, deployment, and UI updates. Exclude temporary files, generated reports, and credentials. Validate frontend 632 tests and production build, API packages, vehicle-map tests, and release installer tests. Gateway suite has one pre-existing date-sensitive identity throttling test failure reproduced on the parent commit.
198 lines
9.0 KiB
Bash
Executable File
198 lines
9.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
RELEASE_ID=${1:?release id is required}
|
|
ARCHIVE=${2:?web archive is required}
|
|
API_BINARY=${3:-}
|
|
ONEOS_SCOPE_BINARY=${4:-}
|
|
RECONCILIATION_BINARY=${5:-}
|
|
OPEN_STAT_BINARY=${6:-}
|
|
ALERT_EVALUATOR_BINARY=${7:-}
|
|
ALERT_STREAM_EVALUATOR_BINARY=${8:-}
|
|
ALERT_NOTIFICATION_DISPATCHER_BINARY=${9:-}
|
|
ROOT=${PLATFORM_ROOT:-/opt/lingniu-vehicle-platform}
|
|
BASE_URL=${PLATFORM_BASE_URL:-http://127.0.0.1:20300}
|
|
SERVICE=${PLATFORM_SERVICE:-lingniu-vehicle-platform}
|
|
ALERT_EVALUATOR_SERVICE=${ALERT_EVALUATOR_SERVICE:-lingniu-vehicle-alert-evaluator}
|
|
ALERT_STREAM_EVALUATOR_SERVICE=${ALERT_STREAM_EVALUATOR_SERVICE:-lingniu-vehicle-alert-stream-evaluator}
|
|
ALERT_NOTIFICATION_DISPATCHER_SERVICE=${ALERT_NOTIFICATION_DISPATCHER_SERVICE:-lingniu-vehicle-alert-notification-dispatcher}
|
|
COMPATIBILITY_GENERATIONS=${COMPATIBILITY_GENERATIONS:-3}
|
|
RELEASE_HISTORY_LIMIT=${RELEASE_HISTORY_LIMIT:-20}
|
|
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
|
SYSTEMCTL_BIN=${SYSTEMCTL_BIN:-systemctl}
|
|
CURL_BIN=${CURL_BIN:-curl}
|
|
|
|
case "$RELEASE_ID" in
|
|
''|*[!A-Za-z0-9._-]*) printf 'invalid release id: %s\n' "$RELEASE_ID" >&2; exit 1 ;;
|
|
esac
|
|
test -f "$ARCHIVE" || { printf 'web archive is missing: %s\n' "$ARCHIVE" >&2; exit 1; }
|
|
if test -n "$API_BINARY"; then
|
|
test -f "$API_BINARY" || { printf 'platform API binary is missing: %s\n' "$API_BINARY" >&2; exit 1; }
|
|
fi
|
|
if test -n "$ONEOS_SCOPE_BINARY"; then
|
|
test -f "$ONEOS_SCOPE_BINARY" || { printf 'OneOS scope sync binary is missing: %s\n' "$ONEOS_SCOPE_BINARY" >&2; exit 1; }
|
|
fi
|
|
if test -n "$RECONCILIATION_BINARY"; then
|
|
test -f "$RECONCILIATION_BINARY" || { printf 'reconciliation evaluator binary is missing: %s\n' "$RECONCILIATION_BINARY" >&2; exit 1; }
|
|
fi
|
|
if test -n "$OPEN_STAT_BINARY"; then
|
|
test -f "$OPEN_STAT_BINARY" || { printf 'open platform statistics binary is missing: %s\n' "$OPEN_STAT_BINARY" >&2; exit 1; }
|
|
fi
|
|
if test -n "$ALERT_EVALUATOR_BINARY"; then
|
|
test -f "$ALERT_EVALUATOR_BINARY" || { printf 'alert evaluator binary is missing: %s\n' "$ALERT_EVALUATOR_BINARY" >&2; exit 1; }
|
|
fi
|
|
if test -n "$ALERT_STREAM_EVALUATOR_BINARY"; then
|
|
test -f "$ALERT_STREAM_EVALUATOR_BINARY" || { printf 'alert stream evaluator binary is missing: %s\n' "$ALERT_STREAM_EVALUATOR_BINARY" >&2; exit 1; }
|
|
fi
|
|
if test -n "$ALERT_NOTIFICATION_DISPATCHER_BINARY"; then
|
|
test -f "$ALERT_NOTIFICATION_DISPATCHER_BINARY" || { printf 'alert notification dispatcher binary is missing: %s\n' "$ALERT_NOTIFICATION_DISPATCHER_BINARY" >&2; exit 1; }
|
|
fi
|
|
test -x "$SCRIPT_DIR/prepare-web-release-tree.sh" || { printf 'release tree helper is missing\n' >&2; exit 1; }
|
|
test -f "$SCRIPT_DIR/prune-release-history.py" || { printf 'release pruning helper is missing\n' >&2; exit 1; }
|
|
test -f "$SCRIPT_DIR/verify-customer-demo.py" || { printf 'customer demo gate is missing\n' >&2; exit 1; }
|
|
test -f "$SCRIPT_DIR/import-source-providers.py" || { printf 'source provider import helper is missing\n' >&2; exit 1; }
|
|
|
|
old=$(readlink -f "$ROOT/current")
|
|
next="$ROOT/releases/$RELEASE_ID"
|
|
env_file="$ROOT/env/platform.env"
|
|
old_release=$(sed -n 's/^PLATFORM_RELEASE=//p' "$env_file" | tail -1)
|
|
switched=false
|
|
|
|
set_release_env() {
|
|
python3 - "$env_file" "$1" <<'PY'
|
|
from __future__ import print_function
|
|
import io
|
|
import sys
|
|
|
|
path, release = sys.argv[1], sys.argv[2]
|
|
with io.open(path, 'r', encoding='utf-8') as handle:
|
|
lines = handle.read().splitlines()
|
|
updated = []
|
|
found = False
|
|
for line in lines:
|
|
if line.startswith('PLATFORM_RELEASE='):
|
|
updated.append('PLATFORM_RELEASE=' + release)
|
|
found = True
|
|
else:
|
|
updated.append(line)
|
|
if not found:
|
|
updated.append('PLATFORM_RELEASE=' + release)
|
|
with io.open(path, 'w', encoding='utf-8') as handle:
|
|
handle.write('\n'.join(updated) + '\n')
|
|
PY
|
|
}
|
|
|
|
rollback() {
|
|
local status=$?
|
|
trap - ERR
|
|
set +e
|
|
if test "$switched" = true; then
|
|
ln -s "$old" "$ROOT/current.rollback"
|
|
python3 -c 'import os,sys; os.replace(sys.argv[1], sys.argv[2])' "$ROOT/current.rollback" "$ROOT/current"
|
|
set_release_env "$old_release"
|
|
"$SYSTEMCTL_BIN" restart "$SERVICE"
|
|
test -z "$ALERT_EVALUATOR_BINARY" || "$SYSTEMCTL_BIN" restart "$ALERT_EVALUATOR_SERVICE"
|
|
test -z "$ALERT_STREAM_EVALUATOR_BINARY" || "$SYSTEMCTL_BIN" restart "$ALERT_STREAM_EVALUATOR_SERVICE"
|
|
test -z "$ALERT_NOTIFICATION_DISPATCHER_BINARY" || "$SYSTEMCTL_BIN" restart "$ALERT_NOTIFICATION_DISPATCHER_SERVICE"
|
|
fi
|
|
printf 'web release install failed; current restored to %s\n' "$old" >&2
|
|
exit "$status"
|
|
}
|
|
trap rollback ERR
|
|
|
|
test ! -e "$next" || { printf 'release already exists: %s\n' "$next" >&2; exit 1; }
|
|
mkdir -p "$next/web"
|
|
for runtime_file in platform-api customer-hydrogen-worker alert-evaluator alert-stream-evaluator alert-notification-dispatcher platform-migrate oneos-scope-sync reconciliation-evaluator alert-benchmark open-platform-stat; do
|
|
if test -f "$old/$runtime_file"; then
|
|
cp "$old/$runtime_file" "$next/$runtime_file"
|
|
fi
|
|
done
|
|
test -f "$next/platform-api" || { printf 'current release is missing platform-api\n' >&2; exit 1; }
|
|
if test -n "$API_BINARY"; then
|
|
cp "$API_BINARY" "$next/platform-api"
|
|
fi
|
|
if test -n "$ONEOS_SCOPE_BINARY"; then
|
|
cp "$ONEOS_SCOPE_BINARY" "$next/oneos-scope-sync"
|
|
fi
|
|
if test -n "$RECONCILIATION_BINARY"; then
|
|
cp "$RECONCILIATION_BINARY" "$next/reconciliation-evaluator"
|
|
fi
|
|
if test -n "$OPEN_STAT_BINARY"; then
|
|
cp "$OPEN_STAT_BINARY" "$next/open-platform-stat"
|
|
fi
|
|
if test -n "$ALERT_EVALUATOR_BINARY"; then
|
|
cp "$ALERT_EVALUATOR_BINARY" "$next/alert-evaluator"
|
|
fi
|
|
if test -n "$ALERT_STREAM_EVALUATOR_BINARY"; then
|
|
cp "$ALERT_STREAM_EVALUATOR_BINARY" "$next/alert-stream-evaluator"
|
|
fi
|
|
if test -n "$ALERT_NOTIFICATION_DISPATCHER_BINARY"; then
|
|
cp "$ALERT_NOTIFICATION_DISPATCHER_BINARY" "$next/alert-notification-dispatcher"
|
|
fi
|
|
if test -f "$old/lingniu-vehicle-platform.service"; then
|
|
cp "$old/lingniu-vehicle-platform.service" "$next/lingniu-vehicle-platform.service"
|
|
fi
|
|
cp -a "$old/deploy" "$next/deploy"
|
|
if test -d "$SCRIPT_DIR/migrations"; then
|
|
mkdir -p "$next/deploy/migrations"
|
|
cp "$SCRIPT_DIR"/migrations/*.sql "$next/deploy/migrations/"
|
|
fi
|
|
if test -d "$SCRIPT_DIR/systemd"; then
|
|
mkdir -p "$next/deploy/systemd"
|
|
cp "$SCRIPT_DIR"/systemd/* "$next/deploy/systemd/"
|
|
fi
|
|
cp "$SCRIPT_DIR/prepare-web-release-tree.sh" "$next/deploy/prepare-web-release-tree.sh"
|
|
cp "$SCRIPT_DIR/prune-release-history.py" "$next/deploy/prune-release-history.py"
|
|
cp "$SCRIPT_DIR/verify-customer-demo.py" "$next/deploy/verify-customer-demo.py"
|
|
cp "$SCRIPT_DIR/import-source-providers.py" "$next/deploy/import-source-providers.py"
|
|
cp "$0" "$next/deploy/install-web-release.sh"
|
|
chmod +x "$next/platform-api" "$next/deploy/"*.sh "$next/deploy/prune-release-history.py" "$next/deploy/verify-customer-demo.py" "$next/deploy/import-source-providers.py"
|
|
for runtime_file in customer-hydrogen-worker alert-evaluator alert-stream-evaluator alert-notification-dispatcher platform-migrate oneos-scope-sync reconciliation-evaluator alert-benchmark open-platform-stat; do
|
|
test ! -f "$next/$runtime_file" || chmod +x "$next/$runtime_file"
|
|
done
|
|
|
|
while IFS= read -r member; do
|
|
case "$member" in
|
|
/*|../*|*/../*|*/..) printf 'web archive contains unsafe path: %s\n' "$member" >&2; exit 1 ;;
|
|
esac
|
|
done < <(tar -tzf "$ARCHIVE")
|
|
tar --no-same-owner -xzf "$ARCHIVE" -C "$next/web"
|
|
find "$next/web" -type f -name '._*' -delete
|
|
"$next/deploy/prepare-web-release-tree.sh" "$next/web" "$old/web" "$COMPATIBILITY_GENERATIONS"
|
|
|
|
ln -s "$next" "$ROOT/current.next"
|
|
python3 -c 'import os,sys; os.replace(sys.argv[1], sys.argv[2])' "$ROOT/current.next" "$ROOT/current"
|
|
switched=true
|
|
set_release_env "$RELEASE_ID"
|
|
"$SYSTEMCTL_BIN" restart "$SERVICE"
|
|
test -z "$ALERT_EVALUATOR_BINARY" || "$SYSTEMCTL_BIN" restart "$ALERT_EVALUATOR_SERVICE"
|
|
test -z "$ALERT_STREAM_EVALUATOR_BINARY" || "$SYSTEMCTL_BIN" restart "$ALERT_STREAM_EVALUATOR_SERVICE"
|
|
test -z "$ALERT_NOTIFICATION_DISPATCHER_BINARY" || "$SYSTEMCTL_BIN" restart "$ALERT_NOTIFICATION_DISPATCHER_SERVICE"
|
|
|
|
ready=false
|
|
for _ in $(seq 1 15); do
|
|
if "$SYSTEMCTL_BIN" is-active --quiet "$SERVICE" && "$CURL_BIN" -fsS "$BASE_URL/" >/dev/null; then ready=true; break; fi
|
|
sleep 1
|
|
done
|
|
test "$ready" = true || { printf 'service did not become ready\n' >&2; exit 1; }
|
|
verify_bin=${VERIFY_WEB_RELEASE_BIN:-$next/deploy/verify-web-release.sh}
|
|
"$verify_bin" "$next/web" "$BASE_URL" "$next/web/.compatibility-assets"
|
|
|
|
if test -f "$ROOT/env/access-tokens.env"; then
|
|
set -a
|
|
# shellcheck disable=SC1090
|
|
. "$ROOT/env/access-tokens.env"
|
|
set +a
|
|
test -n "${VIEWER_TOKEN:-}" || { printf 'viewer token is unavailable for health verification\n' >&2; exit 1; }
|
|
health=$("$CURL_BIN" -fsS -H "Authorization: Bearer $VIEWER_TOKEN" "$BASE_URL/api/ops/health")
|
|
printf '%s' "$health" | python3 -c 'import json,sys; value=(((json.load(sys.stdin).get("data") or {}).get("runtime") or {}).get("platformRelease")); sys.exit(0 if value == sys.argv[1] else 1)' "$RELEASE_ID"
|
|
fi
|
|
|
|
prune_bin=${PRUNE_RELEASE_BIN:-$next/deploy/prune-release-history.py}
|
|
python3 "$prune_bin" "$ROOT" "$RELEASE_HISTORY_LIMIT" "$next" "$old"
|
|
rm -f "$ARCHIVE"
|
|
switched=false
|
|
trap - ERR
|
|
printf 'web_release_install=ok release=%s previous=%s\n' "$RELEASE_ID" "$(basename "$old")"
|