-
Notifications
You must be signed in to change notification settings - Fork 50
Expand file tree
/
Copy pathwrapper.sh
More file actions
executable file
·298 lines (269 loc) · 10.5 KB
/
wrapper.sh
File metadata and controls
executable file
·298 lines (269 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#!/bin/bash
set -o pipefail -o errexit -o nounset
# If we are outside Docker-in-Docker make sure /dev/shm exists
if [ -z "${WITHDOCKER:-}" ]; then
mkdir -p /dev/shm
chmod 777 /dev/shm
mount -t tmpfs tmpfs /dev/shm
fi
# We disable scale-to-zero for the lifetime of this script and restore
# the original setting on exit.
SCALE_TO_ZERO_FILE="/uk/libukp/scale_to_zero_disable"
scale_to_zero_write() {
local char="$1"
# Skip when not running inside Unikraft Cloud (control file absent)
if [[ -e "$SCALE_TO_ZERO_FILE" ]]; then
# Write the character, but do not fail the whole script if this errors out
echo -n "$char" > "$SCALE_TO_ZERO_FILE" 2>/dev/null || \
echo "[wrapper] Failed to write to scale-to-zero control file" >&2
fi
}
disable_scale_to_zero() { scale_to_zero_write "+"; }
enable_scale_to_zero() { scale_to_zero_write "-"; }
wait_for_tcp_port() {
local host="$1"
local port="$2"
local name="$3"
local attempts="${4:-0}"
local sleep_secs="${5:-0.5}"
local timeout_label="${6:-}"
local attempt=0
echo "[wrapper] Waiting for ${name} on ${host}:${port}..."
while true; do
if (echo >/dev/tcp/"${host}"/"${port}") >/dev/null 2>&1; then
echo "[wrapper] ${name} is ready on ${host}:${port}"
return 0
fi
if (( attempts > 0 )); then
attempt=$((attempt + 1))
if (( attempt >= attempts )); then
if [[ -n "${timeout_label}" ]]; then
echo "[wrapper] WARNING: ${name} not ready on ${host}:${port} after ${timeout_label}" >&2
else
echo "[wrapper] WARNING: ${name} not ready on ${host}:${port} after ${attempts} attempts" >&2
fi
return 1
fi
fi
sleep "${sleep_secs}"
done
}
# Disable scale-to-zero for the duration of the script when not running under Docker
if [[ -z "${WITHDOCKER:-}" ]]; then
echo "[wrapper] Disabling scale-to-zero"
disable_scale_to_zero
fi
# -----------------------------------------------------------------------------
# Ensure a sensible hostname ---------------------------------------------------
# -----------------------------------------------------------------------------
if h=$(cat /proc/sys/kernel/hostname 2>/dev/null); then
if [ -z "$h" ] || [ "$h" = "(none)" ]; then
if command -v hostname >/dev/null 2>&1; then
hostname kernel-vm 2>/dev/null || true
fi
echo -n "kernel-vm" > /proc/sys/kernel/hostname 2>/dev/null || true
fi
fi
export HOSTNAME="${HOSTNAME:-kernel-vm}"
# if CHROMIUM_FLAGS is not set, default to the flags used in playwright_stealth
# NOTE: --disable-background-networking was intentionally removed because it prevents
# Chrome from fetching extensions via ExtensionInstallForcelist enterprise policy.
# Enterprise extensions require Chrome to make HTTP requests to fetch update.xml and .crx files.
#
# Chromium renders to Xvfb (DISPLAY=:1) so that screenshots, recordings, xdotool
# input, and live view all work. Flags like --ozone-platform=headless and
# --disable-software-rasterizer are intentionally absent.
if [ -z "${CHROMIUM_FLAGS:-}" ]; then
CHROMIUM_FLAGS="--accept-lang=en-US,en \
--allow-pre-commit-input \
--blink-settings=primaryHoverType=2,availableHoverTypes=2,primaryPointerType=4,availablePointerTypes=4 \
--crash-dumps-dir=/tmp/chromium-dumps \
--disable-back-forward-cache \
--disable-background-timer-throttling \
--disable-backgrounding-occluded-windows \
--disable-blink-features=AutomationControlled \
--disable-breakpad \
--disable-client-side-phishing-detection \
--disable-component-extensions-with-background-pages \
--disable-crash-reporter \
--disable-crashpad \
--disable-dev-shm-usage \
--disable-features=AcceptCHFrame,AutoExpandDetailsElement,AvoidUnnecessaryBeforeUnloadCheckSync,CertificateTransparencyComponentUpdater,DeferRendererTasksAfterInput,DestroyProfileOnBrowserClose,DialMediaRouteProvider,ExtensionManifestV2Disabled,GlobalMediaControls,HttpsUpgrades,ImprovedCookieControls,LazyFrameLoading,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Translate \
--disable-field-trial-config \
--disable-gcm-registration \
--disable-gpu \
--disable-gpu-compositing \
--disable-hang-monitor \
--disable-ipc-flooding-protection \
--disable-notifications \
--disable-popup-blocking \
--disable-prompt-on-repost \
--disable-renderer-backgrounding \
--disable-search-engine-choice-screen \
--enable-use-zoom-for-dsf=false \
--export-tagged-pdf \
--force-color-profile=srgb \
--hide-crash-restore-bubble \
--metrics-recording-only \
--mute-audio \
--no-default-browser-check \
--no-first-run \
--no-sandbox \
--no-service-autorun \
--password-store=basic \
--unsafely-disable-devtools-self-xss-warnings \
--use-angle=swiftshader \
--use-gl=angle \
--use-mock-keychain \
--window-size=${WIDTH:-1920},${HEIGHT:-1080} \
--window-position=0,0"
fi
export CHROMIUM_FLAGS
# -----------------------------------------------------------------------------
# House-keeping for the unprivileged "kernel" user ----------------------------
# When RUN_AS_ROOT is true, we skip ownership changes since we're running as root.
# -----------------------------------------------------------------------------
if [[ "${RUN_AS_ROOT:-}" != "true" ]]; then
dirs=(
/home/kernel/user-data
/home/kernel/.config/chromium
/home/kernel/.pki/nssdb
/home/kernel/.cache/dconf
/tmp
/var/log
/var/log/supervisord
)
for dir in "${dirs[@]}"; do
if [ ! -d "$dir" ]; then
mkdir -p "$dir"
fi
done
# Ensure correct ownership (ignore errors if already correct)
chown -R kernel:kernel /home/kernel /home/kernel/user-data /home/kernel/.config /home/kernel/.pki /home/kernel/.cache 2>/dev/null || true
# Make policy directory writable for runtime updates
chown -R kernel:kernel /etc/chromium/policies 2>/dev/null || true
else
# When running as root, just create the necessary directories without ownership changes
dirs=(
/tmp
/var/log
/var/log/supervisord
/home/kernel
/home/kernel/user-data
)
for dir in "${dirs[@]}"; do
if [ ! -d "$dir" ]; then
mkdir -p "$dir"
fi
done
fi
# -----------------------------------------------------------------------------
# Dynamic log aggregation for /var/log/supervisord -----------------------------
# -----------------------------------------------------------------------------
# Tails any existing and future files under /var/log/supervisord,
# prefixing each line with the relative filepath, e.g. [chromium] ...
start_dynamic_log_aggregator() {
echo "[wrapper] Starting dynamic log aggregator for /var/log/supervisord"
(
declare -A tailed_files=()
start_tail() {
local f="$1"
[[ -f "$f" ]] || return 0
[[ -n "${tailed_files[$f]:-}" ]] && return 0
local label="${f#/var/log/supervisord/}"
# Tie tails to this subshell lifetime so they exit when we stop it
tail --pid="$$" -n +1 -F "$f" 2>/dev/null | sed -u "s/^/[${label}] /" &
tailed_files[$f]=1
}
# Periodically scan for new *.log files without extra dependencies
while true; do
while IFS= read -r -d '' f; do
start_tail "$f"
done < <(find /var/log/supervisord -type f -print0 2>/dev/null || true)
sleep 1
done
) &
tail_pids+=("$!")
}
# Track background tailing processes for cleanup
tail_pids=()
# Start log aggregator early so we see supervisor and service logs as they appear
start_dynamic_log_aggregator
# Export common env used by services
export DISPLAY=:1
export HEIGHT=${HEIGHT:-1080}
export WIDTH=${WIDTH:-1920}
export INTERNAL_PORT="${INTERNAL_PORT:-9223}"
export CHROME_PORT="${CHROME_PORT:-9222}"
# Cleanup handler
cleanup () {
echo "[wrapper] Cleaning up..."
# Re-enable scale-to-zero if the script terminates early
enable_scale_to_zero
supervisorctl -c /etc/supervisor/supervisord.conf stop novnc || true
supervisorctl -c /etc/supervisor/supervisord.conf stop x11vnc || true
supervisorctl -c /etc/supervisor/supervisord.conf stop chromedriver || true
supervisorctl -c /etc/supervisor/supervisord.conf stop chromium || true
supervisorctl -c /etc/supervisor/supervisord.conf stop xvfb || true
supervisorctl -c /etc/supervisor/supervisord.conf stop dbus || true
supervisorctl -c /etc/supervisor/supervisord.conf stop kernel-images-api || true
# Stop log tailers
if [[ -n "${tail_pids[*]:-}" ]]; then
for tp in "${tail_pids[@]}"; do
kill -TERM "$tp" 2>/dev/null || true
done
fi
}
trap cleanup TERM INT
echo "[wrapper] Starting supervisord"
supervisord -c /etc/supervisor/supervisord.conf
echo "[wrapper] Waiting for supervisord socket..."
for i in {1..30}; do
if [ -S /var/run/supervisor.sock ]; then
break
fi
sleep 0.2
done
init-envoy.sh
echo "[wrapper] Starting system D-Bus daemon via supervisord"
supervisorctl -c /etc/supervisor/supervisord.conf start dbus
for i in {1..50}; do
if [ -S /run/dbus/system_bus_socket ]; then
break
fi
sleep 0.2
done
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/dbus/system_bus_socket"
echo "[wrapper] Starting Xvfb via supervisord"
supervisorctl -c /etc/supervisor/supervisord.conf start xvfb
for i in {1..50}; do
if xdpyinfo -display "$DISPLAY" >/dev/null 2>&1; then
break
fi
sleep 0.2
done
echo "[wrapper] Starting Chromium via supervisord on internal port $INTERNAL_PORT"
supervisorctl -c /etc/supervisor/supervisord.conf start chromium
wait_for_tcp_port 127.0.0.1 "$INTERNAL_PORT" "Chromium remote debugging" 100 0.2 "20s" || true
echo "[wrapper] ✨ Starting kernel-images API via supervisord."
supervisorctl -c /etc/supervisor/supervisord.conf start kernel-images-api
API_PORT="${KERNEL_IMAGES_API_PORT:-10001}"
wait_for_tcp_port 127.0.0.1 "${API_PORT}" "kernel-images API"
echo "[wrapper] Starting ChromeDriver via supervisord"
supervisorctl -c /etc/supervisor/supervisord.conf start chromedriver
wait_for_tcp_port 127.0.0.1 9225 "ChromeDriver" 50 0.2 "10s" || true
if [[ "${ENABLE_LIVE_VIEW:-}" == "true" ]]; then
echo "[wrapper] Starting x11vnc via supervisord"
supervisorctl -c /etc/supervisor/supervisord.conf start x11vnc
wait_for_tcp_port 127.0.0.1 5900 "x11vnc" 50 0.2 "10s" || true
echo "[wrapper] Starting noVNC via supervisord"
supervisorctl -c /etc/supervisor/supervisord.conf start novnc
wait_for_tcp_port 127.0.0.1 8080 "noVNC" 50 0.2 "10s" || true
fi
echo "[wrapper] startup complete!"
# Re-enable scale-to-zero once startup has completed (when not under Docker)
if [[ -z "${WITHDOCKER:-}" ]]; then
enable_scale_to_zero
fi
# Keep the container running while streaming logs
wait