blob: 0f2c2c392e7de6b57029b06efb56b947491facb5 [file] [log] [blame]
# This script is automatocally generated by GH Copilot to wrap the command
# to run Kustvakt server and creates thread dumps on SIGQUIT/SIGTERM at
# data/threaddumps. Only fallback kill -3 since jstack and jcmd are only
# available in jdk.
#
# The script is intended to be used with and be placed at the same location as
# a compose.yaml.
#!/bin/sh
set -eu
# POSIX-compatible wrapper to start the original command and capture thread
# dumps into /kustvakt/data/threaddumps when the container receives SIGQUIT
# or SIGTERM. This avoids bash-specific syntax so it works with /bin/sh.
DUMP_DIR="/kustvakt/data/threaddumps"
mkdir -p "$DUMP_DIR"
# File where we collect the JVM's stderr stream so kill -3 output can be
# extracted when jcmd/jstack are not available.
STDERR_LOG="/kustvakt/data/logs/jvm-stderr.log"
child_pid=0
on_quit() {
TS=$(date +"%Y%m%d-%H%M%S")
FILE="$DUMP_DIR/threaddump-$TS.txt"
echo "[wrapper] Creating thread dump to $FILE" >&2
if command -v jcmd >/dev/null 2>&1; then
echo "[wrapper] Running: jcmd $child_pid Thread.print" >&2
if jcmd "$child_pid" Thread.print > "$FILE" 2>&1; then
echo "[wrapper] jcmd wrote $FILE" >&2
else
echo "[wrapper] jcmd failed" >&2
fi
elif command -v jstack >/dev/null 2>&1; then
echo "[wrapper] Running: jstack -l $child_pid" >&2
if jstack -l "$child_pid" > "$FILE" 2>&1; then
echo "[wrapper] jstack wrote $FILE" >&2
else
echo "[wrapper] jstack failed" >&2
fi
else
# If we don't have jcmd/jstack, trigger JVM to print a thread dump to
# stderr (kill -3) and capture the appended portion from the stderr log.
MARKER="===THREAD_DUMP_MARKER $TS $child_pid ==="
printf "%s\n" "$MARKER" >> "$STDERR_LOG" || true
kill -3 "$child_pid" 2>/dev/null || true
# give JVM a moment to write to stderr
sleep 1
# Extract the portion after the MARKER into the dump file.
# Find the last occurrence of the marker and tail from the next line.
if marker_line=$(grep -nF "$MARKER" "$STDERR_LOG" 2>/dev/null | tail -n 1 | cut -d: -f1); then
if [ -n "$marker_line" ]; then
# tail from marker_line+1
start=$((marker_line + 1))
if tail -n +$start "$STDERR_LOG" > "$FILE" 2>/dev/null; then
echo "[wrapper] Extracted JVM stderr to $FILE" >&2
else
echo "[wrapper] Failed to extract JVM stderr to $FILE" >&2
fi
else
# nothing found; create empty file so caller sees some output
: > "$FILE" || true
fi
else
: > "$FILE" || true
fi
fi
# If the dump file is empty or missing, fall back to writing last 2000 lines
if [ ! -s "$FILE" ]; then
echo "[wrapper] $FILE is empty; writing fallback from $STDERR_LOG" >&2
printf "[wrapper] Fallback thread dump (no jcmd/jstack output)\n" > "$FILE" || true
tail -n 2000 "$STDERR_LOG" >> "$FILE" 2>/dev/null || true
echo "[wrapper] Wrote fallback content to $FILE" >&2
fi
# Forward quit/term to child so it can shutdown
kill -s QUIT "$child_pid" 2>/dev/null || kill -s TERM "$child_pid" 2>/dev/null || true
}
trap 'on_quit' QUIT TERM
if [ "$#" -eq 0 ]; then
echo "[wrapper] No command provided to start Kustvakt" >&2
exit 1
fi
first="$1"
shift
# Determine how to invoke the target process.
if command -v "$first" >/dev/null 2>&1; then
# executable available in PATH
set -- "$first" "$@"
else
case "$first" in
*.jar)
if [ -f "/kustvakt/$first" ]; then
set -- java -jar "/kustvakt/$first" "$@"
else
set -- java -jar "$first" "$@"
fi
;;
/*)
if [ -f "$first" ]; then
case "$first" in
*.jar)
set -- java -jar "$first" "$@"
;;
*)
set -- "$first" "$@"
;;
esac
else
set -- "$first" "$@"
fi
;;
*)
if [ -f "/kustvakt/$first" ]; then
case "/kustvakt/$first" in
*.jar)
set -- java -jar "/kustvakt/$first" "$@"
;;
*)
set -- "/kustvakt/$first" "$@"
;;
esac
else
set -- java -jar "$first" "$@"
fi
;;
esac
fi
WRAPPER_LOG="/kustvakt/data/logs/kustvakt-wrapper.log"
timestamp() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
echo "[wrapper] Starting child: $*" | tee -a "$WRAPPER_LOG" >&2
# Start the child in background and capture its PID.
# Prefer starting the child in a separate session so it does not receive
# the initial container signal (which docker sends to PID 1). We then
# explicitly forward QUIT/TERM to the child after creating the dump.
if command -v setsid >/dev/null 2>&1; then
echo "[$(timestamp)] wrapper: starting child with setsid" >> "$WRAPPER_LOG" || true
setsid "$@" >>"$STDERR_LOG" 2>&1 &
else
echo "[$(timestamp)] wrapper: setsid not available; starting child normally" >> "$WRAPPER_LOG" || true
"$@" >>"$STDERR_LOG" 2>&1 &
fi
child_pid=$!
# Record the child's PID to a file and wrapper log for easier debugging
echo "$child_pid" > /kustvakt/data/kustvakt-child.pid 2>/dev/null || true
echo "[$(timestamp)] wrapper: child_pid=$child_pid (pid file: /kustvakt/data/kustvakt-child.pid)" >> "$WRAPPER_LOG" || true
# Wait for the child and propagate exit code
wait "$child_pid"
exit_code=$?
exit $exit_code