Files
quant-os/ops/activate_static_status.sh
T

110 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
if [[ "$#" -lt 1 || "$#" -gt 2 ]]; then
echo "usage: $0 <40-char-git-sha> [web-root]" >&2
exit 2
fi
release_sha="$1"
web_root="${2:-/srv/www/quant-os}"
if [[ ! "${release_sha}" =~ ^[0-9a-f]{40}$ ]]; then
echo "release SHA must be a 40-character lowercase Git SHA" >&2
exit 2
fi
if [[ "${web_root}" != /* || "${web_root}" == "/" ]]; then
echo "web root must be an explicit absolute non-root path" >&2
exit 2
fi
if [[ ! -d "${web_root}" ]]; then
echo "web root does not exist: ${web_root}" >&2
exit 1
fi
lock_dir="${web_root}/.status-deploy.lock"
lock_acquired=false
next_link=""
next_link_created=false
cleanup() {
exit_status="$?"
if [[ "${next_link_created}" == "true" && -L "${next_link}" ]]; then
rm -f "${next_link}"
fi
if [[ "${lock_acquired}" == "true" ]]; then
rmdir "${lock_dir}" 2>/dev/null || true
fi
exit "${exit_status}"
}
trap cleanup EXIT HUP INT TERM
if [[ "${QUANT_OS_STATUS_DEPLOY_LOCK_HELD:-0}" == "1" ]]; then
if [[ ! -d "${lock_dir}" || -L "${lock_dir}" ]]; then
echo "caller asserted a deployment lock that is not held" >&2
exit 1
fi
else
if ! mkdir "${lock_dir}" 2>/dev/null; then
echo "another status deployment or activation holds ${lock_dir}" >&2
exit 1
fi
lock_acquired=true
fi
release_dir="${web_root}/releases/${release_sha}"
if [[ ! -d "${release_dir}" || -L "${release_dir}" ]]; then
echo "release must be a regular directory: ${release_dir}" >&2
exit 1
fi
release_entries=()
while IFS= read -r -d '' entry; do
release_entries+=("${entry}")
done < <(find "${release_dir}" -mindepth 1 -maxdepth 1 -print0 2>/dev/null)
if [[ "${#release_entries[@]}" != "2" ]]; then
echo "release must contain exactly index.html and status-data.js" >&2
exit 1
fi
for required in index.html status-data.js; do
if [[ ! -f "${release_dir}/${required}" || -L "${release_dir}/${required}" ]]; then
echo "release must contain a regular non-symlink ${required}" >&2
exit 1
fi
done
for entry in "${release_entries[@]}"; do
case "$(basename "${entry}")" in
index.html|status-data.js)
;;
*)
echo "unexpected release entry: $(basename "${entry}")" >&2
exit 1
;;
esac
done
next_link="${web_root}/.status-next-${release_sha}"
if [[ -e "${next_link}" || -L "${next_link}" ]]; then
echo "temporary activation link already exists: ${next_link}" >&2
exit 1
fi
ln -s "releases/${release_sha}" "${next_link}"
next_link_created=true
if [[ -e "${web_root}/status" && ! -L "${web_root}/status" ]]; then
echo "active status path exists and is not a symlink" >&2
exit 1
fi
if mv --version >/dev/null 2>&1; then
mv -Tf "${next_link}" "${web_root}/status"
else
mv -fh "${next_link}" "${web_root}/status"
fi
next_link_created=false
active_target="$(readlink "${web_root}/status")"
if [[ "${active_target}" != "releases/${release_sha}" ]]; then
echo "active release verification failed" >&2
exit 1
fi
echo "activated ${release_sha}"