120 lines
4.4 KiB
Bash
120 lines
4.4 KiB
Bash
#!/bin/sh
|
|
# Deploy only the image produced after the remote database checks succeed.
|
|
set -eu
|
|
cd "$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
|
|
test "$(id -u)" -eq 0 || { echo "Deployment requires root on ces-control" >&2; exit 1; }
|
|
release_sha=${ASTER_RELEASE_SHA:?ASTER_RELEASE_SHA is required}
|
|
case "$release_sha" in *[!0-9a-f]*|'') echo "Invalid release SHA" >&2; exit 1;; esac
|
|
test "${#release_sha}" -eq 40
|
|
image="endorphin-aster-vm:$release_sha"
|
|
docker image inspect "$image" >/dev/null
|
|
|
|
umask 077
|
|
root=/opt/endorphin-aster-vm
|
|
config=/etc/endorphin-aster-vm/production.env
|
|
release="$root/releases/$release_sha"
|
|
mkdir -p "$release" /etc/endorphin-aster-vm /var/lib/endorphin-aster-vm/postgres /var/lib/endorphin-aster-vm/host
|
|
chown 10001:10001 /var/lib/endorphin-aster-vm/host
|
|
chmod 700 /var/lib/endorphin-aster-vm/host
|
|
exec 9>/var/lock/endorphin-aster-vm-deploy.lock
|
|
flock 9
|
|
|
|
if [ ! -f "$config" ]; then
|
|
password=$(openssl rand -hex 24)
|
|
printf 'POSTGRES_PASSWORD=%s\nASTER_PORT=18081\n' "$password" > "$config"
|
|
unset password
|
|
fi
|
|
chmod 600 "$config"
|
|
cp docker-compose.ces-control.yml "$release/compose.yml"
|
|
printf 'ASTER_IMAGE=%s\n' "$image" > "$release/release.env"
|
|
previous=$(readlink -f "$root/current" 2>/dev/null || true)
|
|
legacy_export=
|
|
cleanup_export() {
|
|
if [ -n "$legacy_export" ]; then rm -f "$legacy_export"; fi
|
|
}
|
|
trap cleanup_export EXIT
|
|
|
|
compose_at() {
|
|
location=$1
|
|
shift
|
|
docker compose -p endorphin-aster-vm --env-file "$config" \
|
|
--env-file "$location/release.env" -f "$location/compose.yml" "$@"
|
|
}
|
|
rollback() {
|
|
echo "Deployment failed; application data has been retained" >&2
|
|
if [ -n "$previous" ] && [ "$previous" != "$release" ] && [ -f "$previous/compose.yml" ]; then
|
|
echo "Restoring the previously healthy release" >&2
|
|
compose_at "$previous" up -d --no-build --wait --wait-timeout 180 || true
|
|
fi
|
|
}
|
|
|
|
if ! compose_at "$release" up -d --no-build --wait --wait-timeout 180; then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
if ! health=$(compose_at "$release" exec -T aster curl --fail --silent http://127.0.0.1:8080/health); then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
printf '%s' "$health" | python3 -c 'import json,sys; d=json.load(sys.stdin); assert d == {"status":"ok"}' || {
|
|
rollback
|
|
exit 1
|
|
}
|
|
if ! bootstrap=$(compose_at "$release" exec -T aster cli bootstrap); then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
printf '%s' "$bootstrap" | python3 -c 'import sys; s=sys.stdin.read(); assert "runtime=EndorObject type_system=disabled" in s; assert "released heap_objects=0" in s' || {
|
|
rollback
|
|
exit 1
|
|
}
|
|
# Import legacy basic information once, without changing database records.
|
|
# Files are authoritative; cli import only creates records that are missing.
|
|
if [ ! -f /var/lib/endorphin-aster-vm/host/.legacy-imported ]; then
|
|
if ! has_legacy=$(compose_at "$release" exec -T postgres env PGCLIENTENCODING=UTF8 psql -X -U aster -d aster -A -t -v ON_ERROR_STOP=1 \
|
|
-c "SELECT to_regclass('public.aster_metadata') IS NOT NULL"); then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
if [ "$has_legacy" = t ]; then
|
|
legacy_export=$(mktemp)
|
|
if ! compose_at "$release" exec -T postgres env PGCLIENTENCODING=UTF8 psql -X -U aster -d aster -A -t -v ON_ERROR_STOP=1 \
|
|
-c "SELECT COALESCE(json_agg(json_build_object('key', key, 'value', value)), '[]'::json) FROM public.aster_metadata" > "$legacy_export"; then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
if ! compose_at "$release" exec -T aster cli metadata import < "$legacy_export"; then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
rm -f "$legacy_export"
|
|
legacy_export=
|
|
elif [ "$has_legacy" != f ]; then
|
|
echo "Cannot determine legacy information schema" >&2
|
|
rollback
|
|
exit 1
|
|
fi
|
|
if ! touch /var/lib/endorphin-aster-vm/host/.legacy-imported; then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
fi
|
|
# File-backed host information; no SQL table or database write.
|
|
if ! compose_at "$release" exec -T aster cli metadata put deployment.release "$release_sha"; then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
if ! actual=$(compose_at "$release" exec -T aster cli metadata get deployment.release); then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
if [ "$actual" != "$release_sha" ]; then
|
|
rollback
|
|
exit 1
|
|
fi
|
|
ln -sfn "$release" "$root/current.next"
|
|
mv -Tf "$root/current.next" "$root/current"
|
|
compose_at "$release" ps
|
|
echo "Deployed release=$release_sha postgres=provisioned endpoint=127.0.0.1:18081"
|
|
echo "Persistent PostgreSQL data: /var/lib/endorphin-aster-vm/postgres"
|