Skip to content

Commit 76db86f

Browse files
Merge pull request #5 from patterncatalyst/feat/port-forward-ui-and-walkthrough-fix
feat: persistent UI port-forwards, walkthrough canary guard, credentials
2 parents c133964 + 11fb121 commit 76db86f

5 files changed

Lines changed: 189 additions & 41 deletions

File tree

‎examples/lgtm-datamesh/README.md‎

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,20 +203,30 @@ kubectl context set to `capstone`.
203203

204204
### Observing the results
205205

206-
The observability tools run inside the cluster. Port-forward to reach
207-
them from the host. Fedora ships Cockpit on port 9090, so Prometheus
208-
uses an alternate local port.
209-
210-
| Tool | Port-forward command | Local URL |
211-
|------|---------------------|-----------|
212-
| Grafana | `kubectl port-forward -n capstone svc/grafana 3000:80` | `http://localhost:3000` |
213-
| Prometheus | `kubectl port-forward -n capstone svc/prometheus-server 9091:80` | `http://localhost:9091` |
214-
| Kiali | `kubectl port-forward -n istio-system svc/kiali 20001:20001` | `http://localhost:20001/kiali` |
215-
| Tempo | (via Grafana → Explore → Tempo datasource) | — |
216-
| OpenMetadata | `kubectl port-forward -n capstone svc/openmetadata 8585:8585` | `http://localhost:8585` |
217-
218-
Grafana default credentials: `admin` / the value from
219-
`kubectl get secret grafana -n capstone -o jsonpath='{.data.admin-password}' | base64 -d`.
206+
Bootstrap and the walkthrough automatically start port-forwards for the
207+
four UI services via `scripts/port-forward-ui.sh`. They survive script
208+
exit and stay up until you stop them.
209+
210+
| Tool | Local URL | Notes |
211+
|------|-----------|-------|
212+
| Grafana | `http://localhost:3000` | |
213+
| Prometheus | `http://localhost:9091` | Port 9091 avoids Fedora Cockpit on 9090 |
214+
| Kiali | `http://localhost:20001/kiali` | |
215+
| Tempo | (via Grafana → Explore → Tempo datasource) | No direct forward needed |
216+
| OpenMetadata | `http://localhost:8585` | |
217+
218+
```bash
219+
./scripts/port-forward-ui.sh --status # check which forwards are alive
220+
./scripts/port-forward-ui.sh --stop # tear them all down
221+
./scripts/port-forward-ui.sh # restart them
222+
```
223+
224+
Default credentials:
225+
226+
| Tool | User | Password |
227+
|------|------|----------|
228+
| Grafana | `admin` | `capstone` |
229+
| OpenMetadata | `admin@open-metadata.org` | `admin` |
220230

221231
## Restoring baseline
222232

‎examples/lgtm-datamesh/demos/walkthrough.sh‎

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -141,21 +141,15 @@ run_act() {
141141
}
142142

143143
# ─── Cleanup ─────────────────────────────────────────────────────────────────
144-
# Two acts start background port-forwards: trace (to graphql-gateway, while the
145-
# query is in flight) and topology (to Kiali, kept open through the discussion).
146-
# Tear them down on exit no matter how we got there (Ctrl-C, normal exit,
147-
# failure).
148-
KIALI_PF=""
144+
# The trace act starts a temporary port-forward to graphql-gateway; tear it
145+
# down on exit. Persistent UI forwards (Grafana, Kiali, etc.) are managed
146+
# by port-forward-ui.sh and survive this script.
149147
TRACE_PF=""
150148
cleanup() {
151149
if [[ -n "$TRACE_PF" ]] && kill -0 "$TRACE_PF" 2>/dev/null; then
152150
printf '\n%s cleaning up trace port-forward (pid %s)%s\n' "$DIM" "$TRACE_PF" "$RST"
153151
kill "$TRACE_PF" 2>/dev/null || true
154152
fi
155-
if [[ -n "$KIALI_PF" ]] && kill -0 "$KIALI_PF" 2>/dev/null; then
156-
printf '\n%s cleaning up Kiali port-forward (pid %s)%s\n' "$DIM" "$KIALI_PF" "$RST"
157-
kill "$KIALI_PF" 2>/dev/null || true
158-
fi
159153
}
160154
trap cleanup EXIT
161155
trap 'printf "\n%sinterrupted%s\n" "$RED" "$RST"; exit 130' INT
@@ -275,6 +269,11 @@ ${BOLD}${BLU}╔═════════════════════
275269
INTRO
276270

277271
(( PREFLIGHT == 1 )) && preflight
272+
273+
# Start persistent UI port-forwards (Grafana, Prometheus, Kiali, OpenMetadata)
274+
# so the dashboards are available throughout the walkthrough.
275+
./scripts/port-forward-ui.sh
276+
278277
prompt_enter "press Enter to start"
279278

280279
# ─── ACT 1 · TRACE ───────────────────────────────────────────────────────────
@@ -402,6 +401,16 @@ if want_act scale; then
402401
fi
403402

404403
# ─── ACT 3 · CANARY ──────────────────────────────────────────────────────────
404+
# Guard: ensure order-service v1 is deployed — earlier demos (demo-order.sh,
405+
# demo-discovery.sh) uninstall it on success (CAP-008), and the canary act
406+
# needs it as the v1 baseline.
407+
if want_act canary; then
408+
if ! kubectl get deployment order-service -n "$NS" >/dev/null 2>&1; then
409+
info "order-service not deployed — restoring for canary act"
410+
helm upgrade --install order-service charts/capstone/charts/order-service -n "$NS" >/dev/null
411+
kubectl rollout status deploy/order-service -n "$NS" --timeout=120s >/dev/null
412+
fi
413+
fi
405414

406415
if want_act canary; then
407416
act_header "canary" "Canary a contract — v1 → v2, by weight" \
@@ -449,20 +458,8 @@ if want_act topology; then
449458
prompt_enter "press Enter to verify Kiali"
450459
run_act "topology (smoke)" ./demos/demo-kiali.sh || exit 1
451460

452-
narrate "now opening a port-forward to Kiali for you to show in the browser"
461+
narrate "Kiali is already port-forwarded (port-forward-ui.sh)"
453462
info " http://localhost:20001/kiali (Graph → namespace: capstone)"
454-
info " the port-forward stays open until this script exits (Ctrl-C or end of walkthrough)"
455-
# background port-forward; cleanup trap kills it on any exit
456-
kubectl port-forward -n "$ISTIO_SYSTEM" svc/kiali 20001:20001 >/dev/null 2>&1 &
457-
KIALI_PF=$!
458-
# give it a couple seconds to bind, then probe
459-
for _ in 1 2 3 4 5 6 7 8 9 10; do
460-
if curl -fsS http://127.0.0.1:20001/kiali/healthz >/dev/null 2>&1; then
461-
printf '%s ✓ Kiali port-forward live at http://localhost:20001/kiali%s\n' "$GRN" "$RST"
462-
break
463-
fi
464-
sleep 1
465-
done
466463

467464
narrate "to make EDGES appear in the graph, generate some traffic:"
468465
info " in another shell: for i in {1..40}; do ./demos/demo-trace-flow.sh >/dev/null; done"
@@ -476,8 +473,5 @@ printf '\n%s%s══════════════════════
476473
printf '%s%s walkthrough complete · %d / %d acts run%s\n' "$BOLD" "$GRN" "$ACT_NUM" "$ACT_TOTAL" "$RST"
477474
printf '%s%s═══════════════════════════════════════════════════════════════════════%s\n\n' "$BOLD" "$GRN" "$RST"
478475

479-
if want_act topology && [[ -n "$KIALI_PF" ]] && kill -0 "$KIALI_PF" 2>/dev/null; then
480-
printf '%s Kiali port-forward is still up (pid %s) — http://localhost:20001/kiali%s\n' "$DIM" "$KIALI_PF" "$RST"
481-
printf '%s press Enter to tear it down and exit, or Ctrl-C to keep the script alive until you do%s\n\n' "$DIM" "$RST"
482-
prompt_enter "press Enter to exit"
483-
fi
476+
printf '%s UI port-forwards remain active (Grafana :3000, Prometheus :9091, Kiali :20001, OpenMetadata :8585)%s\n' "$DIM" "$RST"
477+
printf '%s stop them with: ./scripts/port-forward-ui.sh --stop%s\n' "$DIM" "$RST"

‎examples/lgtm-datamesh/scripts/bootstrap-capstone.sh‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,21 @@ ok "catalog populated and lineage declared"
159159
step "Cluster status"
160160
bash ./scripts/cluster-status.sh || true
161161

162+
step "UI port-forwards (Grafana, Prometheus, Kiali, OpenMetadata)"
163+
./scripts/port-forward-ui.sh
164+
162165
step "Bring-up complete — the cluster is walkthrough-ready."
163166
cat <<EOF
164167
# The five-act presenter walkthrough (the deck's "What you can see it do"):
165168
./demos/walkthrough.sh
166169
170+
# UI dashboards (port-forwards started automatically):
171+
# Grafana http://localhost:3000
172+
# Prometheus http://localhost:9091
173+
# Kiali http://localhost:20001/kiali
174+
# OpenMetadata http://localhost:8585
175+
# Stop them: ./scripts/port-forward-ui.sh --stop
176+
167177
# Other things you can do from here:
168178
./demos/demo-discovery.sh # publish OpenAPI/proto/SDL to Apicurio
169179
./demos/demo-canary.sh up 90 10 # the v1->v2 contract canary (Phase B)
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env bash
2+
#
3+
# port-forward-ui.sh — start (or stop) persistent background port-forwards
4+
# for the four capstone UI services so they're reachable from the host
5+
# immediately after bootstrap, without manual kubectl commands.
6+
#
7+
# The forwards are designed to outlive this script (no cleanup trap). PIDs
8+
# are written to a pidfile so --stop can clean them up later.
9+
#
10+
# Usage:
11+
# ./scripts/port-forward-ui.sh # start all four forwards
12+
# ./scripts/port-forward-ui.sh --stop # kill all forwards
13+
# ./scripts/port-forward-ui.sh --status # show which are alive
14+
15+
set -uo pipefail
16+
17+
PIDFILE="/tmp/capstone-ui-pf.pids"
18+
19+
BOLD=""; GRN=""; DIM=""; RST=""
20+
if [[ -t 1 ]]; then
21+
BOLD=$'\033[1m'; GRN=$'\033[32m'; DIM=$'\033[2m'; RST=$'\033[0m'
22+
fi
23+
24+
ok() { printf ' %s✓%s %s\n' "$GRN" "$RST" "$1"; }
25+
info() { printf ' %s%s%s\n' "$DIM" "$1" "$RST"; }
26+
27+
# ── --stop ───────────────────────────────────────────────────────────────────
28+
29+
do_stop() {
30+
if [[ ! -f "$PIDFILE" ]]; then
31+
info "no pidfile — nothing to stop"
32+
return 0
33+
fi
34+
local killed=0
35+
while IFS='|' read -r pid label _ ; do
36+
if kill -0 "$pid" 2>/dev/null; then
37+
kill "$pid" 2>/dev/null && killed=$((killed + 1))
38+
info "stopped $label (pid $pid)"
39+
fi
40+
done < "$PIDFILE"
41+
rm -f "$PIDFILE"
42+
info "stopped $killed forward(s)"
43+
}
44+
45+
# ── --status ─────────────────────────────────────────────────────────────────
46+
47+
do_status() {
48+
if [[ ! -f "$PIDFILE" ]]; then
49+
info "no pidfile — no forwards tracked"
50+
return 0
51+
fi
52+
while IFS='|' read -r pid label url ; do
53+
if kill -0 "$pid" 2>/dev/null; then
54+
printf ' %s✓%s %-16s %s (pid %s)\n' "$GRN" "$RST" "$label" "$url" "$pid"
55+
else
56+
printf ' ✗ %-16s dead (pid %s)\n' "$label" "$pid"
57+
fi
58+
done < "$PIDFILE"
59+
}
60+
61+
# ── args ─────────────────────────────────────────────────────────────────────
62+
63+
case "${1:-start}" in
64+
--stop) do_stop; exit 0 ;;
65+
--status) do_status; exit 0 ;;
66+
start|--start) ;;
67+
--help|-h)
68+
printf 'Usage: %s [--stop | --status | --help]\n' "$(basename "$0")"
69+
exit 0 ;;
70+
*) printf 'unknown flag: %s\n' "$1"; exit 2 ;;
71+
esac
72+
73+
# ── start ────────────────────────────────────────────────────────────────────
74+
# Each entry: label | namespace | service | local_port | remote_port | url
75+
76+
FORWARDS=(
77+
"Grafana|observability|grafana|3000|80|http://localhost:3000"
78+
"Prometheus|observability|prometheus-server|9091|80|http://localhost:9091"
79+
"Kiali|istio-system|kiali|20001|20001|http://localhost:20001/kiali"
80+
"OpenMetadata|capstone|openmetadata|8585|8585|http://localhost:8585"
81+
)
82+
83+
port_in_use() {
84+
local port="$1"
85+
ss -tlnp 2>/dev/null | grep -q ":${port} " && return 0
86+
return 1
87+
}
88+
89+
# kill any stale forwards from a previous run before starting fresh
90+
[[ -f "$PIDFILE" ]] && do_stop >/dev/null 2>&1
91+
: > "$PIDFILE"
92+
93+
started=0
94+
for entry in "${FORWARDS[@]}"; do
95+
IFS='|' read -r label ns svc local_port remote_port url <<< "$entry"
96+
97+
if port_in_use "$local_port"; then
98+
info "$label: port $local_port already bound (skipped)"
99+
continue
100+
fi
101+
102+
if ! kubectl get svc "$svc" -n "$ns" >/dev/null 2>&1; then
103+
info "$label: svc/$svc not found in $ns (skipped)"
104+
continue
105+
fi
106+
107+
kubectl port-forward -n "$ns" "svc/$svc" "${local_port}:${remote_port}" >/dev/null 2>&1 &
108+
pf_pid=$!
109+
printf '%s|%s|%s\n' "$pf_pid" "$label" "$url" >> "$PIDFILE"
110+
started=$((started + 1))
111+
done
112+
113+
# brief pause to let the forwards bind
114+
sleep 1
115+
116+
printf '\n'
117+
printf ' %s%-16s %-40s %s%s\n' "$BOLD" "Service" "URL" "Status" "$RST"
118+
printf ' %-16s %-40s %s\n' "───────────────" "────────────────────────────────────────" "──────"
119+
while IFS='|' read -r pid label url ; do
120+
if kill -0 "$pid" 2>/dev/null; then
121+
printf ' %s✓%s %-14s %-40s %slive%s\n' "$GRN" "$RST" "$label" "$url" "$GRN" "$RST"
122+
else
123+
printf ' ✗ %-14s %-40s failed\n' "$label" "$url"
124+
fi
125+
done < "$PIDFILE"
126+
printf '\n'
127+
128+
ok "$started UI port-forward(s) started (pidfile: $PIDFILE)"
129+
info "Grafana login: admin / capstone"
130+
info "OpenMetadata login: admin@open-metadata.org / admin"
131+
info "stop with: ./scripts/port-forward-ui.sh --stop"

‎examples/lgtm-datamesh/scripts/teardown.sh‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ if [[ "${1:-}" == "--remove-profile" ]]; then
1515
REMOVE=1
1616
fi
1717

18+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
19+
"$SCRIPT_DIR/port-forward-ui.sh" --stop 2>/dev/null || true
20+
1821
if ! minikube status -p "$PROFILE_NAME" >/dev/null 2>&1; then
1922
printf '==> Profile %s is not present. Nothing to do.\n' "$PROFILE_NAME"
2023
exit 0

0 commit comments

Comments
 (0)