Ran every read/analysis tool against the real 24-site integrator (lib + wired dispatch). Fixed: nc-find --name (GNU sed \+ → POSIX; 0 rows on BSD/macOS), nc-find tsv/jsonl exit-1-on-success, nc-parse tclproc-refs dropping digit-leading procs (3M_check_ack), nc-xlate diff missing --site, nc-diff-interface + nc-smat-diff printf '-'-leading option-injection dropping output, nc-status not-up crashing on --format, and nc-status not-up's gawk-only \<up\> word-boundary → portable form (BSD/macOS). Test matrix in Deliverables. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
158 lines
5.1 KiB
Bash
Executable File
158 lines
5.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# nc-status.sh — Cloverleaf engine runtime status. Native v3 wrapper around
|
|
# the shipped status/tstat binaries — modelled on v1 `status`, `tstats`,
|
|
# `tstat`, `thread_status`, `procstatus`, `dstatus`, `connstatus`, `not_up`.
|
|
#
|
|
# Subcommands:
|
|
# sites site-level status (daemon + processes + threads)
|
|
# threads thread-level status (port, state, host)
|
|
# not-up only threads not in 'up' state
|
|
# connections raw connection state (from connstatus binary if available)
|
|
# queued threads with messages queued
|
|
# raw pass-through to the underlying tstat binary
|
|
#
|
|
# Flags (where applicable):
|
|
# --site SITE single site; default = all sites under $HCIROOT
|
|
# --filter REGEX match on thread name
|
|
# --format text|tsv default text
|
|
#
|
|
# This is V1-modeled but native-bash. The exact binary names depend on the
|
|
# Cloverleaf version; we auto-discover under $HCIROOT/bin (and server/bin).
|
|
set -o pipefail
|
|
|
|
NC_SELF="$0"
|
|
|
|
die() { printf 'nc-status: %s\n' "$*" >&2; exit 1; }
|
|
warn() { printf 'nc-status: %s\n' "$*" >&2; }
|
|
|
|
resolve_binary() {
|
|
local name="$1"
|
|
if command -v "$name" >/dev/null 2>&1; then command -v "$name"; return; fi
|
|
for d in "${HCIROOT:-}/bin" "${HCIROOT:-}/server/bin"; do
|
|
[ -x "$d/$name" ] && { echo "$d/$name"; return; }
|
|
done
|
|
return 1
|
|
}
|
|
|
|
list_sites() {
|
|
local root="${HCIROOT:-}"
|
|
[ -d "$root" ] || die "no \$HCIROOT or it doesn't exist"
|
|
find "$root" -mindepth 1 -maxdepth 2 -name NetConfig -type f 2>/dev/null \
|
|
| xargs -I{} dirname {} 2>/dev/null \
|
|
| xargs -I{} basename {} 2>/dev/null \
|
|
| sort -u
|
|
}
|
|
|
|
cmd_sites() {
|
|
local target_site=""
|
|
local format="text"
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--site) shift; target_site="$1" ;;
|
|
--format) shift; format="$1" ;;
|
|
*) die "unknown flag: $1" ;;
|
|
esac
|
|
shift
|
|
done
|
|
local hcienginestat; hcienginestat=$(resolve_binary hcienginestat 2>/dev/null || true)
|
|
local sites_to_check
|
|
if [ -n "$target_site" ]; then sites_to_check="$target_site"; else sites_to_check=$(list_sites); fi
|
|
[ "$format" = "tsv" ] && printf 'site\tstate\tdetail\n'
|
|
while IFS= read -r s; do
|
|
[ -z "$s" ] && continue
|
|
local detail="" state="?"
|
|
if [ -n "$hcienginestat" ]; then
|
|
detail=$(HCISITE="$s" "$hcienginestat" 2>&1 || true)
|
|
if echo "$detail" | grep -qiE 'running|active|up'; then state="up"
|
|
elif echo "$detail" | grep -qiE 'stopped|down'; then state="down"
|
|
else state="unknown"; fi
|
|
else
|
|
# Fallback: check for lock file / pid file as a poor-man's check
|
|
if [ -e "${HCIROOT:-}/$s/lock" ] || [ -e "${HCIROOT:-}/$s/exec/processes" ]; then
|
|
state="config-present"
|
|
fi
|
|
fi
|
|
if [ "$format" = "tsv" ]; then
|
|
printf '%s\t%s\t%s\n' "$s" "$state" "$(echo "$detail" | head -1)"
|
|
else
|
|
printf '== %-20s [%s] ==\n%s\n' "$s" "$state" "$(echo "$detail" | head -10)"
|
|
fi
|
|
done <<< "$sites_to_check"
|
|
}
|
|
|
|
cmd_threads() {
|
|
local target_site="${HCISITE:-}"
|
|
local filter=""
|
|
local format="text"
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--site) shift; target_site="$1" ;;
|
|
--filter) shift; filter="$1" ;;
|
|
--format) shift; format="$1" ;;
|
|
*) die "unknown flag: $1" ;;
|
|
esac
|
|
shift
|
|
done
|
|
local tstat; tstat=$(resolve_binary tstat) || die "tstat binary not found under \$HCIROOT/bin or PATH"
|
|
local args=()
|
|
[ -n "$target_site" ] && args+=("-s" "$target_site")
|
|
local output; output=$(HCISITE="$target_site" "$tstat" "${args[@]}" 2>&1 || true)
|
|
if [ -n "$filter" ]; then
|
|
output=$(printf '%s' "$output" | grep -E -- "$filter")
|
|
fi
|
|
if [ "$format" = "tsv" ]; then
|
|
# Best-effort: parse the tstat output into TSV
|
|
printf '%s\n' "$output" | awk 'NR>1 && NF>0 { gsub(/ +/, "\t"); print }'
|
|
else
|
|
printf '%s\n' "$output"
|
|
fi
|
|
}
|
|
|
|
cmd_not_up() {
|
|
local site="${HCISITE:-}"
|
|
local filter=""
|
|
local format="text"
|
|
while [ $# -gt 0 ]; do
|
|
case "$1" in
|
|
--site) shift; site="$1" ;;
|
|
--filter) shift; filter="$1" ;;
|
|
# Accept --format and forward it to cmd_threads. The larry.sh dispatch
|
|
# ALWAYS appends --format, so without this not-up died "unknown flag:
|
|
# --format" and was unusable via the wired tool.
|
|
--format) shift; format="$1" ;;
|
|
*) die "unknown flag: $1" ;;
|
|
esac
|
|
shift
|
|
done
|
|
cmd_threads --site "$site" --format "$format" ${filter:+--filter "$filter"} \
|
|
| awk 'NR==1 || tolower($0) !~ /(^|[^a-z])up([^a-z]|$)/'
|
|
}
|
|
|
|
cmd_connections() {
|
|
local connstatus; connstatus=$(resolve_binary connstatus 2>/dev/null) || die "connstatus binary not found"
|
|
"$connstatus" "$@"
|
|
}
|
|
|
|
cmd_queued() {
|
|
local site="${HCISITE:-}"
|
|
cmd_threads --site "$site" "$@" \
|
|
| awk 'NR==1 || tolower($0) ~ /queued|obq|ibq/'
|
|
}
|
|
|
|
cmd_raw() {
|
|
local tstat; tstat=$(resolve_binary tstat) || die "tstat binary not found"
|
|
"$tstat" "$@"
|
|
}
|
|
|
|
SUB="${1:-sites}"
|
|
case "$SUB" in
|
|
sites) shift; cmd_sites "$@" ;;
|
|
threads) shift; cmd_threads "$@" ;;
|
|
not-up) shift; cmd_not_up "$@" ;;
|
|
connections) shift; cmd_connections "$@" ;;
|
|
queued) shift; cmd_queued "$@" ;;
|
|
raw) shift; cmd_raw "$@" ;;
|
|
help|-h|--help) sed -n '2,20p' "$NC_SELF" ;;
|
|
*) die "unknown subcommand: $SUB" ;;
|
|
esac
|