mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 15:51:13 +00:00
bf13549b32
ci/woodpecker/push/02-build-push Pipeline failed
- Enhanced `.env.example` with detailed CMake build flags and replay-mode strategy flags for development and CI environments. - Updated `.gitignore` to include a new deploy rollback bookmark. - Revised `_docs/_autodev_state.md` to reflect the current task status and steps. - Added new lessons to `_docs/LESSONS.md` regarding testing and architectural improvements. - Documented changes in `_docs/02_document/deployment/ci_cd_pipeline.md` to reflect the relaxed OpenCV version pin. - Updated test data documentation in `_docs/02_document/tests/test-data.md` to clarify fixture usage and paths. This commit continues the cycle-1 documentation sync and addresses various configuration updates for improved clarity and functionality.
137 lines
4.9 KiB
Bash
Executable File
137 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# GPS-Denied Onboard — graceful shutdown of the service stack.
|
|
#
|
|
# Refuses to stop the airborne stack when /run/azaion/in-flight is set
|
|
# (deployment_procedures.md § Deployment Strategy — ground-only safety
|
|
# gate). Saves the current image SHAs to .previous-tags.env so deploy.sh
|
|
# --rollback can restore them.
|
|
#
|
|
# Honours the 30 s stop_grace_period declared in docker-compose.yml so
|
|
# C13 can emit flight_footer{clean_shutdown=true} per
|
|
# deployment_procedures.md § Graceful Shutdown.
|
|
#
|
|
# Usage:
|
|
# scripts/stop-services.sh [--target dev|airborne|operator-workstation]
|
|
# [--compose-file <path>] [--force] [--help]
|
|
#
|
|
# Defaults:
|
|
# target = dev
|
|
# compose-file = docker-compose.yml
|
|
#
|
|
# Exit codes:
|
|
# 0 stack stopped cleanly (or already stopped)
|
|
# 64 missing prerequisite (docker / compose file)
|
|
# 65 SSH unreachable when DEPLOY_HOST is set
|
|
# 68 refused — /run/azaion/in-flight is set and --force was not passed
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
GPS-Denied Onboard — graceful shutdown of the service stack.
|
|
|
|
Refuses to stop the airborne stack when /run/azaion/in-flight is set
|
|
(deployment_procedures.md § Deployment Strategy — ground-only safety
|
|
gate). Saves the current image SHAs to .previous-tags.env so deploy.sh
|
|
--rollback can restore them.
|
|
|
|
Honours the 30 s stop_grace_period declared in docker-compose.yml so
|
|
C13 can emit flight_footer{clean_shutdown=true} per
|
|
deployment_procedures.md § Graceful Shutdown.
|
|
|
|
Usage:
|
|
scripts/stop-services.sh [--target dev|airborne|operator-workstation]
|
|
[--compose-file <path>] [--force] [--help]
|
|
|
|
Defaults:
|
|
target = dev
|
|
compose-file = docker-compose.yml
|
|
|
|
Exit codes:
|
|
0 stack stopped cleanly (or already stopped)
|
|
64 missing prerequisite (docker / compose file)
|
|
65 SSH unreachable when DEPLOY_HOST is set
|
|
68 refused — /run/azaion/in-flight is set and --force was not passed
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
TARGET="dev"
|
|
COMPOSE_FILE=""
|
|
FORCE=0
|
|
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--target) TARGET="$2"; shift 2 ;;
|
|
--compose-file) COMPOSE_FILE="$2"; shift 2 ;;
|
|
--force) FORCE=1; shift ;;
|
|
--help|-h) usage ;;
|
|
*) echo "ERROR: unknown argument: $1" >&2; usage ;;
|
|
esac
|
|
done
|
|
|
|
if [ -z "${COMPOSE_FILE}" ]; then
|
|
case "${TARGET}" in
|
|
dev) COMPOSE_FILE="docker-compose.yml" ;;
|
|
airborne) COMPOSE_FILE="${AIRBORNE_COMPOSE_FILE:-/etc/gps-denied/docker-compose.airborne.yml}" ;;
|
|
operator-workstation) COMPOSE_FILE="docker-compose.yml" ;;
|
|
*) echo "ERROR: invalid --target: ${TARGET}" >&2; exit 64 ;;
|
|
esac
|
|
fi
|
|
|
|
remote_exec=""
|
|
if [ -n "${DEPLOY_HOST:-}" ]; then
|
|
if ! ssh -o BatchMode=yes -o ConnectTimeout=5 "${DEPLOY_HOST}" true 2>/dev/null; then
|
|
echo "ERROR: cannot reach 'ssh ${DEPLOY_HOST}' non-interactively." >&2
|
|
exit 65
|
|
fi
|
|
remote_exec="ssh ${DEPLOY_HOST}"
|
|
fi
|
|
|
|
if [ "${TARGET}" = "airborne" ]; then
|
|
if ${remote_exec} test -e /run/azaion/in-flight 2>/dev/null; then
|
|
if [ "${FORCE}" = "1" ]; then
|
|
echo "WARNING: /run/azaion/in-flight is set but --force was passed —" >&2
|
|
echo " continuing. This will abort a live flight pipeline." >&2
|
|
else
|
|
echo "ERROR: /run/azaion/in-flight is set on the target host." >&2
|
|
echo " Refusing to stop the airborne stack mid-flight." >&2
|
|
echo " Wait for the flight to end, or pass --force to override." >&2
|
|
exit 68
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if ! ${remote_exec} command -v docker >/dev/null 2>&1; then
|
|
echo "ERROR: docker not found on $( [ -n "${remote_exec}" ] && echo "remote" || echo "local" ) host" >&2
|
|
exit 64
|
|
fi
|
|
|
|
echo "[stop-services] target: ${TARGET}"
|
|
echo "[stop-services] compose-file: ${COMPOSE_FILE}"
|
|
|
|
PREV_TAGS_FILE="${REPO_ROOT}/.previous-tags.env"
|
|
echo "[stop-services] saving current image digests to ${PREV_TAGS_FILE}"
|
|
{
|
|
echo "# Saved by scripts/stop-services.sh on $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
echo "# Used by deploy.sh --rollback to restore the previous image set."
|
|
echo "# Service tag layout: PREV_<SERVICE>_IMAGE=<repo>@<sha256-digest>"
|
|
${remote_exec} docker compose -f "${COMPOSE_FILE}" config --services 2>/dev/null \
|
|
| while read -r service; do
|
|
image=$(${remote_exec} docker compose -f "${COMPOSE_FILE}" \
|
|
images --format '{{.Repository}}@{{.ID}}' "${service}" 2>/dev/null \
|
|
| head -n1 || true)
|
|
[ -n "${image}" ] || continue
|
|
key=$(echo "PREV_${service}_IMAGE" | tr '[:lower:]-' '[:upper:]_')
|
|
echo "${key}=${image}"
|
|
done
|
|
} > "${PREV_TAGS_FILE}"
|
|
|
|
echo "[stop-services] docker compose down (graceful, 30s grace per compose stop_grace_period)"
|
|
${remote_exec} docker compose -f "${COMPOSE_FILE}" down --remove-orphans
|
|
|
|
echo "[stop-services] OK"
|