193 lines
4.4 KiB
Bash
Executable File
193 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Generate partially prefilled release evidence markdown.
|
|
#
|
|
# Usage:
|
|
# bash ops/generate_release_evidence.sh
|
|
# bash ops/generate_release_evidence.sh --out release-evidence-custom.md
|
|
# bash ops/generate_release_evidence.sh --sofiia-url http://127.0.0.1:8002 --skip-preflight
|
|
#
|
|
# Exit codes:
|
|
# 0 = file created
|
|
# 1 = critical error
|
|
|
|
set -euo pipefail
|
|
|
|
SOFIIA_URL="http://127.0.0.1:8002"
|
|
OUT_FILE=""
|
|
SKIP_PREFLIGHT=0
|
|
SKIP_HEALTH=0
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--out)
|
|
OUT_FILE="${2:-}"
|
|
shift 2
|
|
;;
|
|
--sofiia-url)
|
|
SOFIIA_URL="${2:-}"
|
|
shift 2
|
|
;;
|
|
--skip-preflight)
|
|
SKIP_PREFLIGHT=1
|
|
shift
|
|
;;
|
|
--skip-health)
|
|
SKIP_HEALTH=1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
cat <<'EOF'
|
|
Usage: bash ops/generate_release_evidence.sh [options]
|
|
|
|
Options:
|
|
--out <file> Output markdown file path
|
|
--sofiia-url <url> Sofiia console base URL (default: http://127.0.0.1:8002)
|
|
--skip-preflight Skip preflight execution
|
|
--skip-health Skip health/metrics checks
|
|
EOF
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if ! command -v git >/dev/null 2>&1; then
|
|
echo "ERROR: git is required"
|
|
exit 1
|
|
fi
|
|
if ! command -v date >/dev/null 2>&1; then
|
|
echo "ERROR: date is required"
|
|
exit 1
|
|
fi
|
|
|
|
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
|
|
if [ -z "${REPO_ROOT}" ]; then
|
|
echo "ERROR: not inside a git repository"
|
|
exit 1
|
|
fi
|
|
|
|
cd "${REPO_ROOT}"
|
|
|
|
TS_TAG="$(date -u '+%Y%m%d-%H%M%S')"
|
|
if [ -z "${OUT_FILE}" ]; then
|
|
OUT_FILE="release-evidence-${TS_TAG}.md"
|
|
fi
|
|
|
|
UTC_TS="$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
|
KYIV_TS="$(TZ=Europe/Kyiv date '+%Y-%m-%d %H:%M:%S %Z' 2>/dev/null || date '+%Y-%m-%d %H:%M:%S')"
|
|
GIT_SHA="$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")"
|
|
GIT_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")"
|
|
GIT_MSG="$(git log -1 --pretty=%s 2>/dev/null || echo "unknown")"
|
|
HOST_NAME="$(hostname 2>/dev/null || echo "unknown")"
|
|
NODE_ID_VALUE="${NODE_ID:-unset}"
|
|
OPERATOR_VALUE="${USER:-unknown}"
|
|
|
|
PREFLIGHT_STATUS="SKIPPED"
|
|
PREFLIGHT_CMD='bash ops/preflight_sofiia_console.sh'
|
|
if [ "${SKIP_PREFLIGHT}" = "0" ]; then
|
|
set +e
|
|
bash ops/preflight_sofiia_console.sh >/dev/null 2>&1
|
|
PREFLIGHT_CODE=$?
|
|
set -e
|
|
if [ "${PREFLIGHT_CODE}" = "0" ]; then
|
|
PREFLIGHT_STATUS="PASS"
|
|
elif [ "${PREFLIGHT_CODE}" = "2" ]; then
|
|
PREFLIGHT_STATUS="WARN"
|
|
else
|
|
PREFLIGHT_STATUS="FAIL"
|
|
fi
|
|
fi
|
|
|
|
HEALTH_CODE="SKIPPED"
|
|
METRICS_CODE="SKIPPED"
|
|
if [ "${SKIP_HEALTH}" = "0" ]; then
|
|
set +e
|
|
HEALTH_CODE="$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "${SOFIIA_URL}/api/health" 2>/dev/null || echo "000")"
|
|
METRICS_CODE="$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "${SOFIIA_URL}/metrics" 2>/dev/null || echo "000")"
|
|
set -e
|
|
fi
|
|
|
|
cat > "${OUT_FILE}" <<EOF
|
|
# Release Evidence: Sofiia Console
|
|
|
|
## 1) Release metadata
|
|
|
|
- Release ID: ${TS_TAG}
|
|
- Date/Time UTC: ${UTC_TS}
|
|
- Date/Time Europe/Kyiv: ${KYIV_TS}
|
|
- Operator: ${OPERATOR_VALUE}
|
|
- Hostname: ${HOST_NAME}
|
|
- NODE_ID (env): ${NODE_ID_VALUE}
|
|
- Target nodes: NODA1 / NODA2
|
|
- Deployed SHAs:
|
|
- sofiia-console: ${GIT_SHA}
|
|
- router:
|
|
- gateway:
|
|
- memory-service:
|
|
- Git branch: ${GIT_BRANCH}
|
|
- HEAD commit message: ${GIT_MSG}
|
|
- Change summary (1-3 bullets):
|
|
-
|
|
|
|
## 2) Preflight results
|
|
|
|
- Command: \`${PREFLIGHT_CMD}\`
|
|
- Status: ${PREFLIGHT_STATUS}
|
|
- WARN summary (if any):
|
|
-
|
|
|
|
## 3) Deploy steps performed
|
|
|
|
- NODA2 precheck: OK / FAIL
|
|
- Notes:
|
|
- NODA1 rollout: OK / FAIL
|
|
- Method (docker/systemd/manual):
|
|
- Notes:
|
|
- NODA2 finalize: OK / FAIL
|
|
- Notes:
|
|
|
|
## 4) Smoke evidence
|
|
|
|
- GET /api/health: HTTP ${HEALTH_CODE}
|
|
- GET /metrics: HTTP ${METRICS_CODE}
|
|
- Idempotency A/B smoke:
|
|
- Command: \`bash ops/redis_idempotency_smoke.sh\`
|
|
- Result: PASS / FAIL
|
|
- message_id:
|
|
- /api/audit auth checks:
|
|
- without key -> 401 confirmed: yes / no
|
|
- with key -> 200 confirmed: yes / no
|
|
|
|
## 5) Post-release checks
|
|
|
|
- Key metrics deltas (optional):
|
|
- sofiia_rate_limited_total:
|
|
- sofiia_idempotency_replays_total:
|
|
- Audit write/read quick check: OK / FAIL
|
|
- Retention dry-run:
|
|
- Command: \`python3 ops/prune_audit_db.py --dry-run\`
|
|
- candidates=
|
|
- Notes:
|
|
|
|
## 6) Rollback plan & outcome
|
|
|
|
- Rollback needed: no / yes
|
|
- If yes:
|
|
- reason:
|
|
- rollback commands used:
|
|
- result:
|
|
- Final service state: healthy / degraded
|
|
|
|
## 7) Sign-off
|
|
|
|
- Reviewer / approver:
|
|
- Timestamp UTC:
|
|
- Notes:
|
|
EOF
|
|
|
|
echo "Release evidence file created: ${OUT_FILE}"
|
|
exit 0
|