blob: 0f2c2c392e7de6b57029b06efb56b947491facb5 [file] [log] [blame]
margaretha89623632026-02-12 12:08:02 +01001# This script is automatocally generated by GH Copilot to wrap the command
2# to run Kustvakt server and creates thread dumps on SIGQUIT/SIGTERM at
3# data/threaddumps. Only fallback kill -3 since jstack and jcmd are only
4# available in jdk.
5#
6# The script is intended to be used with and be placed at the same location as
7# a compose.yaml.
8
9#!/bin/sh
10set -eu
11
12# POSIX-compatible wrapper to start the original command and capture thread
13# dumps into /kustvakt/data/threaddumps when the container receives SIGQUIT
14# or SIGTERM. This avoids bash-specific syntax so it works with /bin/sh.
15
16DUMP_DIR="/kustvakt/data/threaddumps"
17mkdir -p "$DUMP_DIR"
18
19# File where we collect the JVM's stderr stream so kill -3 output can be
20# extracted when jcmd/jstack are not available.
21STDERR_LOG="/kustvakt/data/logs/jvm-stderr.log"
22
23child_pid=0
24
25on_quit() {
26 TS=$(date +"%Y%m%d-%H%M%S")
27 FILE="$DUMP_DIR/threaddump-$TS.txt"
28 echo "[wrapper] Creating thread dump to $FILE" >&2
29
30 if command -v jcmd >/dev/null 2>&1; then
31 echo "[wrapper] Running: jcmd $child_pid Thread.print" >&2
32 if jcmd "$child_pid" Thread.print > "$FILE" 2>&1; then
33 echo "[wrapper] jcmd wrote $FILE" >&2
34 else
35 echo "[wrapper] jcmd failed" >&2
36 fi
37 elif command -v jstack >/dev/null 2>&1; then
38 echo "[wrapper] Running: jstack -l $child_pid" >&2
39 if jstack -l "$child_pid" > "$FILE" 2>&1; then
40 echo "[wrapper] jstack wrote $FILE" >&2
41 else
42 echo "[wrapper] jstack failed" >&2
43 fi
44 else
45 # If we don't have jcmd/jstack, trigger JVM to print a thread dump to
46 # stderr (kill -3) and capture the appended portion from the stderr log.
47 MARKER="===THREAD_DUMP_MARKER $TS $child_pid ==="
48 printf "%s\n" "$MARKER" >> "$STDERR_LOG" || true
49 kill -3 "$child_pid" 2>/dev/null || true
50 # give JVM a moment to write to stderr
51 sleep 1
52
53 # Extract the portion after the MARKER into the dump file.
54 # Find the last occurrence of the marker and tail from the next line.
55 if marker_line=$(grep -nF "$MARKER" "$STDERR_LOG" 2>/dev/null | tail -n 1 | cut -d: -f1); then
56 if [ -n "$marker_line" ]; then
57 # tail from marker_line+1
58 start=$((marker_line + 1))
59 if tail -n +$start "$STDERR_LOG" > "$FILE" 2>/dev/null; then
60 echo "[wrapper] Extracted JVM stderr to $FILE" >&2
61 else
62 echo "[wrapper] Failed to extract JVM stderr to $FILE" >&2
63 fi
64 else
65 # nothing found; create empty file so caller sees some output
66 : > "$FILE" || true
67 fi
68 else
69 : > "$FILE" || true
70 fi
71 fi
72
73 # If the dump file is empty or missing, fall back to writing last 2000 lines
74 if [ ! -s "$FILE" ]; then
75 echo "[wrapper] $FILE is empty; writing fallback from $STDERR_LOG" >&2
76 printf "[wrapper] Fallback thread dump (no jcmd/jstack output)\n" > "$FILE" || true
77 tail -n 2000 "$STDERR_LOG" >> "$FILE" 2>/dev/null || true
78 echo "[wrapper] Wrote fallback content to $FILE" >&2
79 fi
80
81 # Forward quit/term to child so it can shutdown
82 kill -s QUIT "$child_pid" 2>/dev/null || kill -s TERM "$child_pid" 2>/dev/null || true
83}
84
85trap 'on_quit' QUIT TERM
86
87if [ "$#" -eq 0 ]; then
88 echo "[wrapper] No command provided to start Kustvakt" >&2
89 exit 1
90fi
91
92first="$1"
93shift
94
95# Determine how to invoke the target process.
96if command -v "$first" >/dev/null 2>&1; then
97 # executable available in PATH
98 set -- "$first" "$@"
99else
100 case "$first" in
101 *.jar)
102 if [ -f "/kustvakt/$first" ]; then
103 set -- java -jar "/kustvakt/$first" "$@"
104 else
105 set -- java -jar "$first" "$@"
106 fi
107 ;;
108 /*)
109 if [ -f "$first" ]; then
110 case "$first" in
111 *.jar)
112 set -- java -jar "$first" "$@"
113 ;;
114 *)
115 set -- "$first" "$@"
116 ;;
117 esac
118 else
119 set -- "$first" "$@"
120 fi
121 ;;
122 *)
123 if [ -f "/kustvakt/$first" ]; then
124 case "/kustvakt/$first" in
125 *.jar)
126 set -- java -jar "/kustvakt/$first" "$@"
127 ;;
128 *)
129 set -- "/kustvakt/$first" "$@"
130 ;;
131 esac
132 else
133 set -- java -jar "$first" "$@"
134 fi
135 ;;
136 esac
137fi
138
139WRAPPER_LOG="/kustvakt/data/logs/kustvakt-wrapper.log"
140timestamp() { date -u +"%Y-%m-%dT%H:%M:%SZ"; }
141
142echo "[wrapper] Starting child: $*" | tee -a "$WRAPPER_LOG" >&2
143
144# Start the child in background and capture its PID.
145# Prefer starting the child in a separate session so it does not receive
146# the initial container signal (which docker sends to PID 1). We then
147# explicitly forward QUIT/TERM to the child after creating the dump.
148if command -v setsid >/dev/null 2>&1; then
149 echo "[$(timestamp)] wrapper: starting child with setsid" >> "$WRAPPER_LOG" || true
150 setsid "$@" >>"$STDERR_LOG" 2>&1 &
151else
152 echo "[$(timestamp)] wrapper: setsid not available; starting child normally" >> "$WRAPPER_LOG" || true
153 "$@" >>"$STDERR_LOG" 2>&1 &
154fi
155child_pid=$!
156
157# Record the child's PID to a file and wrapper log for easier debugging
158echo "$child_pid" > /kustvakt/data/kustvakt-child.pid 2>/dev/null || true
159echo "[$(timestamp)] wrapper: child_pid=$child_pid (pid file: /kustvakt/data/kustvakt-child.pid)" >> "$WRAPPER_LOG" || true
160
161# Wait for the child and propagate exit code
162wait "$child_pid"
163exit_code=$?
164exit $exit_code