#!/usr/bin/env bash # Drive and narrate the Hermes automated-triage demo. # # This is the autonomous loop: a build fails, Ariadne diagnoses it through # Hermes, authorizes a predefined repair, performs it, and rebuilds green # without a human touching anything. # # hermes_triage_demo.sh monitor # follow the Test Automation Diagram live # hermes_triage_demo.sh reset # restore the demo to its pre-run state # hermes_triage_demo.sh preflight # confirm the lab is ready to demo # hermes_triage_demo.sh run # arm the failure and narrate the loop # hermes_triage_demo.sh status # current incident/alert state, no changes # # The code-proposal demo is a separate script: hermes_code_demo.sh. They prove # different halves of the diagram and reset different things, so they are kept # apart rather than behind one command. # # FIRST RUN: copy hermes_demo.env.example to hermes_demo.env in this directory # and fill it in. That file is git-ignored precisely so it can hold real # tokens; this script sources it automatically. # # Needs kubectl access to the cluster as well. Nothing here mutates the cluster # directly: the demo only asks Jenkins to run a parameterized build. set -euo pipefail # shellcheck source=scripts/ops/hermes_demo_lib.sh . "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/hermes_demo_lib.sh" # The fixture is a ConfigMap the demo job reads. Resetting it is the whole # blast radius of this script: no repository is touched, because the triage # loop repairs infrastructure rather than source. cmd_reset() { say "Reset — restoring the triage demo to its pre-run state" note "fixture -> healthy" if kubectl -n "$DEMO_NS" patch cm hermes-triage-demo-fixture \ --type merge -p '{"data":{"state":"healthy"}}' >/dev/null 2>&1; then note " fixture: $(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}')" else note " fixture patch failed (is the demo namespace present?)" fi say "Ready" note "no repository was touched; this demo repairs infrastructure, not source" note "run 'preflight' next, then 'run'" } cmd_preflight() { require_jenkins say "Preflight — triage demo" note "fixture state: $(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}' 2>/dev/null || echo MISSING)" shared_preflight } cmd_status() { shared_status say "Demo namespace" kubectl -n "$DEMO_NS" get jobs --no-headers 2>/dev/null | sed 's/^/ /' } cmd_run() { require_jenkins local start_num next_num start_num="$(last_build_number "$FIXTURE_JOB")" next_num=$((start_num + 1)) say "Arming the demo failure (SEED_FAILURE=true) -> build #$next_num" note "HTTP $(jenkins_post "/job/$FIXTURE_JOB/buildWithParameters?SEED_FAILURE=true")" note "Only manual step. Everything after this is automatic." say "Waiting for the seeded build to fail" note "result: $(wait_for_build "$FIXTURE_JOB" "$next_num")" say "Ariadne detects, gathers evidence, asks Hermes, authorizes, repairs" note "the repair is a single in-process ConfigMap patch, so watch the fixture" for _ in $(seq 1 40); do sleep 10 if [ "$(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}' 2>/dev/null)" = "healthy" ]; then note "fixture patched back to healthy" break fi done ariadne_ticks 400 4 say "Ariadne triggers one rebuild with seeding disabled" note "result: $(wait_for_build "$FIXTURE_JOB" $((next_num + 1)))" say "Resolution" sleep 45 ariadne_ticks 200 3 note "fixture state: $(kubectl -n "$DEMO_NS" get cm hermes-triage-demo-fixture -o jsonpath='{.data.state}')" } case "${1:-}" in run|fixture) cmd_run ;; status) cmd_status ;; preflight) cmd_preflight ;; reset) cmd_reset ;; monitor) run_monitor "$FIXTURE_JOB" ;; *) sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//' ; exit 1 ;; esac