Files
lingniu-vehicle-ingest/vehicle-data-platform/deploy/install-open-platform-release.sh
T
lingniu d6b957dfc8 feat: sync vehicle monitoring and accumulated platform updates
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.
2026-10-26 18:05:59 +08:00

124 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
RELEASE_ID=${1:?release id is required}
WEB_ARCHIVE=${2:?open portal web archive is required}
API_BINARY=${3:?open platform API binary is required}
ROOT=${OPEN_PLATFORM_ROOT:-/opt/lingniu-vehicle-open-platform}
BASE_URL=${OPEN_PLATFORM_BASE_URL:-http://127.0.0.1:20310}
SERVICE=${OPEN_PLATFORM_SERVICE:-lingniu-vehicle-open-platform}
SYSTEMCTL_BIN=${SYSTEMCTL_BIN:-systemctl}
CURL_BIN=${CURL_BIN:-curl}
RELEASE_HISTORY_LIMIT=${RELEASE_HISTORY_LIMIT:-12}
case "$RELEASE_ID" in
''|*[!A-Za-z0-9._-]*) printf 'invalid release id: %s\n' "$RELEASE_ID" >&2; exit 1 ;;
esac
test -f "$WEB_ARCHIVE" || { printf 'open portal archive is missing\n' >&2; exit 1; }
test -f "$API_BINARY" || { printf 'open platform API binary is missing\n' >&2; exit 1; }
old=
if test -L "$ROOT/current"; then
old=$(readlink -f "$ROOT/current")
fi
next="$ROOT/releases/$RELEASE_ID"
env_file="$ROOT/env/open-platform.env"
switched=false
set_release_env() {
python3 - "$env_file" "$1" <<'PY'
import pathlib
import sys
path = pathlib.Path(sys.argv[1])
release = sys.argv[2]
lines = path.read_text(encoding="utf-8").splitlines() if path.exists() else []
updated = []
found = False
for line in lines:
if line.startswith("OPEN_PLATFORM_RELEASE="):
updated.append("OPEN_PLATFORM_RELEASE=" + release)
found = True
else:
updated.append(line)
if not found:
updated.append("OPEN_PLATFORM_RELEASE=" + release)
path.write_text("\n".join(updated) + "\n", encoding="utf-8")
PY
chmod 0600 "$env_file"
}
rollback() {
status=$?
trap - ERR
set +e
if test "$switched" = true && test -n "$old"; 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 "$(basename "$old")"
"$SYSTEMCTL_BIN" restart "$SERVICE"
elif test "$switched" = true; then
"$SYSTEMCTL_BIN" stop "$SERVICE"
rm -f "$ROOT/current"
set_release_env ""
fi
printf 'open platform release failed; current restored to %s\n' "${old:-none}" >&2
exit "$status"
}
trap rollback ERR
test ! -e "$next" || { printf 'release already exists: %s\n' "$next" >&2; exit 1; }
mkdir -p "$next/web" "$ROOT/env"
cp "$API_BINARY" "$next/open-platform-api"
chmod 0755 "$next/open-platform-api"
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 "$WEB_ARCHIVE")
tar --no-same-owner -xzf "$WEB_ARCHIVE" -C "$next/web"
test -f "$next/web/index.html" || { printf 'open portal index is missing\n' >&2; exit 1; }
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"
ready=false
for _ in $(seq 1 20); do
if "$SYSTEMCTL_BIN" is-active --quiet "$SERVICE" && "$CURL_BIN" -fsS "$BASE_URL/healthz" >/dev/null; then
ready=true
break
fi
sleep 1
done
test "$ready" = true || { printf 'open platform service did not become ready\n' >&2; exit 1; }
# Read the entire response: grep -q can close a large document's pipe early,
# making curl fail with code 23 under pipefail and roll back a healthy release.
"$CURL_BIN" -fsS "$BASE_URL/" | grep '<div id="root"></div>' >/dev/null
"$CURL_BIN" -fsS "$BASE_URL/open-api/openapi.yaml" | grep '^openapi: 3.0.3' >/dev/null
"$CURL_BIN" -fsS "$BASE_URL/portal-api/catalog" | grep 'daily_hydrogen' >/dev/null
python3 - "$ROOT" "$RELEASE_HISTORY_LIMIT" "$next" "$old" <<'PY'
import pathlib
import shutil
import sys
root = pathlib.Path(sys.argv[1])
limit = int(sys.argv[2])
protected = {pathlib.Path(value).resolve() for value in sys.argv[3:] if value}
releases = sorted(
(p for p in (root / "releases").iterdir() if p.is_dir()),
key=lambda p: p.stat().st_mtime,
reverse=True,
)
for path in releases[limit:]:
if path.resolve() not in protected:
shutil.rmtree(path)
PY
switched=false
trap - ERR
printf 'open_platform_release_install=ok release=%s previous=%s\n' "$RELEASE_ID" "${old##*/}"