bb17615f41
SLICE-03 (devops-engineer): ported from coreci/scripts/proxmox/: api.sh (verbatim), ct-exists.sh, lxc-clone.sh (4GB/16GB, hostname=praxis), lxc-config.sh (praxis env vars, praxis-firstboot.sh snippet), lxc-start.sh, stage-snippet.sh (G-101 FIX: bakes GITEA_TOKEN into snippet via sed), timing.sh (verbatim), rollback.sh (proxy code removed) SLICE-04 (devops-engineer): health-check.sh adapted for /health:8789 (G-104 FIX: timeout bumped 300s→600s for Docker build margin) REQ-DEPLOY-03, 04, 05, 07, 08 covered. ---ci--- project: praxis phase: 1 milestone: v0.2 status: execute slice: 03-04 wave: 2 ---/ci---
102 lines
3.8 KiB
Bash
Executable File
102 lines
3.8 KiB
Bash
Executable File
# CoreCI — deploy-stage timing helper (P11 — IDEATE-39).
|
|
#
|
|
# Sourced (not executed) by the deploy orchestrators
|
|
# (proxy-deploy.sh, lxc-deploy.sh) to emit structured slog-style
|
|
# JSON timing lines for each deploy stage to stderr, where a log
|
|
# aggregator (or `2>>timing.log`) can pick them up.
|
|
#
|
|
# Usage:
|
|
# . /path/to/timing.sh
|
|
# timing_start clone
|
|
# ... clone work ...
|
|
# timing_end clone
|
|
#
|
|
# Emits one JSON line per timing_end to stderr:
|
|
# {"event":"deploy_timing","stage":"clone","duration_s":3}
|
|
#
|
|
# Optional node_exporter textfile collector: if the env var
|
|
# NODE_TEXTFILE_COLLECTOR_DIR points to a writable directory, the
|
|
# latest per-stage duration is ALSO written there as
|
|
# `coreci_deploy_timing_<stage>.prom` so a node_exporter textfile
|
|
# collector scrapes it. If the dir is unset or unwritable, only the
|
|
# JSON log is emitted (the structured-log-first decision, PLAN v3.6
|
|
# P11 Wave 2).
|
|
#
|
|
# Dependencies: date (POSIX epoch via +%s). jq is NOT required (the
|
|
# JSON line is constructed with printf so there is no external dep
|
|
# on the slow path). Idempotent: re-sourcing is harmless (the
|
|
# _TIMING_STARTS associative state is reset on source, but the
|
|
# orchestrator sources exactly once at startup).
|
|
#
|
|
# NOTE: Ported verbatim from coreci. The metric/prefix names retain
|
|
# the `coreci_` origin identifier for compatibility with existing
|
|
# node_exporter dashboards; rename in a follow-up if desired.
|
|
#
|
|
# shellcheck shell=sh
|
|
|
|
# _TIMING_STARTS is a flat file-backed map (stage → epoch seconds).
|
|
# POSIX sh has no associative arrays, so we use a single newline-
|
|
# separated string of "stage=epoch" records and scan it. Stages are
|
|
# short identifiers (clone/config/start/health/smoke) so the linear
|
|
# scan is trivially cheap.
|
|
_TIMING_STARTS=""
|
|
|
|
# timing_start <stage> — record the current epoch for <stage>.
|
|
# Overwrites a prior start for the same stage (idempotent re-entry).
|
|
timing_start() {
|
|
_stage="$1"
|
|
_now=$(date +%s)
|
|
# Drop any prior record for this stage, then append the fresh one.
|
|
_TIMING_STARTS="$(printf '%s\n' "$_TIMING_STARTS" \
|
|
| while IFS= read -r _line; do
|
|
case "$_line" in
|
|
"${_stage}="*) ;;
|
|
*) [ -n "$_line" ] && printf '%s\n' "$_line" ;;
|
|
esac
|
|
done)"
|
|
_TIMING_STARTS="${_TIMING_STARTS:+${_TIMING_STARTS}
|
|
}${_stage}=${_now}"
|
|
}
|
|
|
|
# timing_end <stage> — compute duration since timing_start <stage>,
|
|
# emit the JSON line to stderr, and optionally write the textfile
|
|
# collector entry. If no start was recorded for <stage>, emit nothing
|
|
# (defensive — a stray timing_end with no start is a no-op).
|
|
timing_end() {
|
|
_stage="$1"
|
|
_now=$(date +%s)
|
|
_start=""
|
|
# Scan the records for the matching stage.
|
|
_rest=""
|
|
while IFS= read -r _line; do
|
|
[ -n "$_line" ] || continue
|
|
case "$_line" in
|
|
"${_stage}="*)
|
|
_start="${_line#*=}"
|
|
;;
|
|
*)
|
|
_rest="${_rest:+${_rest}
|
|
}${_line}"
|
|
;;
|
|
esac
|
|
done <<EOF
|
|
${_TIMING_STARTS}
|
|
EOF
|
|
[ -n "$_start" ] || return 0
|
|
_duration=$((_now - _start))
|
|
_TIMING_STARTS="$_rest"
|
|
# Structured JSON to stderr (slog-style: single-line JSON).
|
|
printf '{"event":"deploy_timing","stage":"%s","duration_s":%s}\n' \
|
|
"$_stage" "$_duration" >&2
|
|
# Optional node_exporter textfile collector.
|
|
if [ -n "${NODE_TEXTFILE_COLLECTOR_DIR:-}" ] && \
|
|
[ -d "$NODE_TEXTFILE_COLLECTOR_DIR" ] && \
|
|
[ -w "$NODE_TEXTFILE_COLLECTOR_DIR" ]; then
|
|
_tf="${NODE_TEXTFILE_COLLECTOR_DIR}/coreci_deploy_timing_${_stage}.prom"
|
|
{
|
|
printf '# HELP coreci_deploy_timing_seconds Duration of the %s deploy stage.\n' "$_stage"
|
|
printf '# TYPE coreci_deploy_timing_seconds gauge\n'
|
|
printf 'coreci_deploy_timing_seconds{stage="%s"} %s\n' "$_stage" "$_duration"
|
|
} > "$_tf" 2>/dev/null || true
|
|
fi
|
|
} |