From 10f170f89635d4ca36e7c882aeae0b5554acca42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 09:01:14 +0000 Subject: [PATCH 1/6] Initial plan From 06a1cde6d1b0a59adee7f3c3e6dd1f7c546216db Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 09:05:57 +0000 Subject: [PATCH 2/6] Fix VNC container startup failure when x11 volume is in corrupt state Agent-Logs-Url: https://github.com/LCAS/aoc_container_base/sessions/8c372695-b798-4c45-887e-2f66c08ba314 Co-authored-by: cooperj <28831674+cooperj@users.noreply.github.com> --- docker/vnc-entrypoint.sh | 127 +++++++++++++++++++++++++++++++++++---- 1 file changed, 116 insertions(+), 11 deletions(-) diff --git a/docker/vnc-entrypoint.sh b/docker/vnc-entrypoint.sh index 4c6cebb..5db2fa9 100644 --- a/docker/vnc-entrypoint.sh +++ b/docker/vnc-entrypoint.sh @@ -5,27 +5,132 @@ echo "************************************************************************** echo "AOC VNC container starting..." echo "****************************************************************************************************************************************" -sudo rm -rf /tmp/.X1-lock /tmp/.X11-unix/X1 > /dev/null 2>&1 -screen -dmS turbovnc bash -c '/opt/TurboVNC/bin/vncserver :1 -depth 24 -noxstartup -securitytypes TLSNone,X509None,None 2>&1 | tee /tmp/vnc.log; read -p "Press any key to continue..."' +# --- X11 volume cleanup --- +# The x11 volume may contain stale lock files and sockets from a previous (crashed) run. +# Clear them so TurboVNC can start cleanly. +cleanup_x11() { + local had_stale=false -echo "waiting for display to be up" -while ! xdpyinfo -display :1 2> /dev/null > /dev/null; do - sleep .1 -done -echo "display is up" + if [ -e /tmp/.X1-lock ]; then + echo " [x11] Found stale lock file /tmp/.X1-lock — removing..." + rm -f /tmp/.X1-lock || sudo rm -f /tmp/.X1-lock + if [ -e /tmp/.X1-lock ]; then + echo " [x11] WARNING: failed to remove /tmp/.X1-lock — x11 volume may be in a corrupt state." >&2 + else + echo " [x11] Removed stale lock file." + had_stale=true + fi + fi + + if [ -e /tmp/.X11-unix/X1 ]; then + echo " [x11] Found stale socket /tmp/.X11-unix/X1 — removing..." + rm -f /tmp/.X11-unix/X1 || sudo rm -f /tmp/.X11-unix/X1 + if [ -e /tmp/.X11-unix/X1 ]; then + echo " [x11] WARNING: failed to remove /tmp/.X11-unix/X1 — x11 volume may be in a corrupt state." >&2 + else + echo " [x11] Removed stale socket." + had_stale=true + fi + fi + + if $had_stale; then + echo " [x11] Stale X11 files from previous run cleared successfully." + else + echo " [x11] No stale X11 files found." + fi + + # Ensure the socket directory has the correct sticky-bit permissions + chmod 1777 /tmp/.X11-unix 2>/dev/null || sudo chmod 1777 /tmp/.X11-unix 2>/dev/null || true +} + +echo "Checking x11 volume state..." +cleanup_x11 + +# --- Start TurboVNC --- +VNC_STARTUP_TIMEOUT=30 # seconds to wait for VNC display to come up + +start_turbovnc() { + echo "Starting TurboVNC server on display :1..." + screen -dmS turbovnc bash -c '/opt/TurboVNC/bin/vncserver :1 -depth 24 -noxstartup -securitytypes TLSNone,X509None,None 2>&1 | tee /tmp/vnc.log; read -p "Press any key to continue..."' + + echo "Waiting for display :1 to become available (timeout: ${VNC_STARTUP_TIMEOUT}s)..." + local max_iterations=$(( VNC_STARTUP_TIMEOUT * 2 )) # 0.5s per iteration + local waited=0 + while ! xdpyinfo -display :1 2>/dev/null >/dev/null; do + sleep 0.5 + waited=$((waited + 1)) + if [ "$waited" -ge "$max_iterations" ]; then + return 1 + fi + done + return 0 +} -echo "starting xfce4" +if ! start_turbovnc; then + echo "" >&2 + echo "ERROR: TurboVNC failed to start within ${VNC_STARTUP_TIMEOUT}s." >&2 + echo " This is often caused by stale files left in the x11 volume from a previous run." >&2 + if [ -s /tmp/vnc.log ]; then + echo "--- VNC server log (/tmp/vnc.log) ---" >&2 + cat /tmp/vnc.log >&2 + echo "--- End of VNC server log ---" >&2 + else + echo " (no VNC log available at /tmp/vnc.log)" >&2 + fi + + echo "" >&2 + echo "Attempting automatic recovery: cleaning up x11 volume and retrying..." >&2 + screen -S turbovnc -X quit 2>/dev/null || true + cleanup_x11 + + if ! start_turbovnc; then + echo "" >&2 + echo "FATAL: TurboVNC failed to start even after x11 volume cleanup." >&2 + if [ -s /tmp/vnc.log ]; then + echo "--- VNC server log (/tmp/vnc.log) ---" >&2 + cat /tmp/vnc.log >&2 + echo "--- End of VNC server log ---" >&2 + fi + echo "" >&2 + echo "To recover manually, remove the x11 volume and restart:" >&2 + echo " docker compose down -v && docker compose up" >&2 + exit 1 + fi + + echo "Recovery successful: TurboVNC started after x11 volume cleanup." +fi + +echo "Display :1 is up." + +# --- Start XFCE4 --- +XFCE_STARTUP_TIMEOUT=30 # seconds to wait for xfce4-session to set DBUS_SESSION_BUS_ADDRESS + +echo "Starting xfce4..." screen -dmS xfce4 bash -c 'DISPLAY=:1 /usr/bin/xfce4-session 2>&1 | tee /tmp/xfce4.log' + +xfce_max_iterations=$(( XFCE_STARTUP_TIMEOUT * 2 )) # 0.5s per iteration +xfce_waited=0 while [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; do if pgrep xfce4-session > /dev/null; then XFCE_PID=$(pgrep xfce4-session) export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$XFCE_PID/environ|cut -d= -f2-|tr -d '\0') fi - sleep .1 + sleep 0.5 + xfce_waited=$((xfce_waited + 1)) + if [ "$xfce_waited" -ge "$xfce_max_iterations" ]; then + echo "" >&2 + echo "ERROR: xfce4-session did not become ready within ${XFCE_STARTUP_TIMEOUT}s." >&2 + if [ -s /tmp/xfce4.log ]; then + echo "--- xfce4 log (/tmp/xfce4.log) ---" >&2 + cat /tmp/xfce4.log >&2 + echo "--- End of xfce4 log ---" >&2 + fi + exit 1 + fi done -echo "xfce4 up" +echo "xfce4 up." -echo "starting novnc ${NOVNC_VERSION}" +echo "Starting novnc ${NOVNC_VERSION}..." screen -dmS novnc bash -c '/usr/local/novnc/noVNC-${NOVNC_VERSION}/utils/novnc_proxy --vnc localhost:5901 --listen 5801 2>&1 | tee /tmp/novnc.log' DISPLAY=:1 xhost +local: 2>/dev/null From 66b09ef2a8d06c24295cbf49c56e2950f2c6ce3a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 09:17:29 +0000 Subject: [PATCH 3/6] Add comprehensive VNC health check script and integrate as Docker HEALTHCHECK Agent-Logs-Url: https://github.com/LCAS/aoc_container_base/sessions/ca8bbf03-ea7a-4a24-a2ff-de0d7e97b8bd Co-authored-by: cooperj <28831674+cooperj@users.noreply.github.com> --- compose.cuda.yml | 3 ++- compose.yml | 3 ++- docker/vnc-healthcheck.sh | 20 ++++++++++++++++++++ vnc.dockerfile | 6 ++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 docker/vnc-healthcheck.sh diff --git a/compose.cuda.yml b/compose.cuda.yml index 6942181..6f2acc8 100644 --- a/compose.cuda.yml +++ b/compose.cuda.yml @@ -25,9 +25,10 @@ services: - ros_net ipc: shareable # Allow other containers to access the IPC of the VNC container to allow data to go into it's X11 healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5801/vnc.html"] + test: ["CMD", "/vnc-healthcheck.sh"] interval: 10s timeout: 5s + start_period: 60s # allow the VNC stack time to fully initialize retries: 5 # ── ROS Container ──────────────────────────────────────────────────────────── diff --git a/compose.yml b/compose.yml index 95acdf0..6247f0d 100644 --- a/compose.yml +++ b/compose.yml @@ -25,9 +25,10 @@ services: - ros_net ipc: shareable # Allow other containers to access the IPC of the VNC container to allow data to go into it's X11 healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5801/vnc.html"] + test: ["CMD", "/vnc-healthcheck.sh"] interval: 10s timeout: 5s + start_period: 60s # allow the VNC stack time to fully initialize retries: 5 # ── ROS Container ──────────────────────────────────────────────────────────── diff --git a/docker/vnc-healthcheck.sh b/docker/vnc-healthcheck.sh new file mode 100644 index 0000000..afb2622 --- /dev/null +++ b/docker/vnc-healthcheck.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# VNC container health check +# Verifies that all VNC stack components are operational: +# 1. X11 display :1 is available (catches corrupt x11 volume state) +# 2. noVNC web interface is serving on port 5801 + +# Check X11 display is responding +if ! xdpyinfo -display :1 >/dev/null 2>&1; then + echo "UNHEALTHY: X11 display :1 is not available" >&2 + exit 1 +fi + +# Check noVNC web interface (also confirms TurboVNC is running since noVNC proxies to it) +if ! curl -sf http://localhost:5801/vnc.html >/dev/null; then + echo "UNHEALTHY: noVNC web interface is not accessible on port 5801" >&2 + exit 1 +fi + +echo "HEALTHY: X11 display :1 and noVNC are operational" +exit 0 diff --git a/vnc.dockerfile b/vnc.dockerfile index 45d7573..c0d73fa 100644 --- a/vnc.dockerfile +++ b/vnc.dockerfile @@ -77,6 +77,12 @@ COPY vnc-entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] +COPY vnc-healthcheck.sh /vnc-healthcheck.sh +RUN chmod +x /vnc-healthcheck.sh +# start_period allows the VNC stack time to fully initialize before health checks start counting failures +HEALTHCHECK --interval=10s --timeout=5s --start-period=60s --retries=5 \ + CMD ["/vnc-healthcheck.sh"] + # Copy in wallpaper COPY ./wallpapers/*.jpg /usr/share/backgrounds/xfce/ From 2f5c6f8eaa4ad9ee4ef35c6ca0408bab59ac78b9 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Tue, 5 May 2026 12:05:25 +0100 Subject: [PATCH 4/6] fix: restore sudo access to lcas user from vnc This allows us to clear the x11 volume on crashes Co-authored-by: Copilot --- docker/vnc-entrypoint.sh | 3 +-- vnc.dockerfile | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docker/vnc-entrypoint.sh b/docker/vnc-entrypoint.sh index 5db2fa9..fcdae5e 100644 --- a/docker/vnc-entrypoint.sh +++ b/docker/vnc-entrypoint.sh @@ -92,8 +92,7 @@ if ! start_turbovnc; then echo "--- End of VNC server log ---" >&2 fi echo "" >&2 - echo "To recover manually, remove the x11 volume and restart:" >&2 - echo " docker compose down -v && docker compose up" >&2 + echo "To recover manually, remove the x11 volume and restart containers." >&2 exit 1 fi diff --git a/vnc.dockerfile b/vnc.dockerfile index c0d73fa..a781c24 100644 --- a/vnc.dockerfile +++ b/vnc.dockerfile @@ -31,11 +31,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libx11-6 \ x11-utils \ screen \ + sudo \ unzip \ && rm -rf /var/lib/apt/lists/* # Create non-root user -RUN useradd -m -s /bin/bash -G video ${username} +RUN useradd -m -s /bin/bash -G video,sudo ${username} + +# Allow passwordless sudo for users in sudo group +RUN echo '%sudo ALL=(ALL:ALL) NOPASSWD:ALL' > /etc/sudoers.d/99-sudo-nopasswd \ + && chmod 0440 /etc/sudoers.d/99-sudo-nopasswd # Fix /tmp/.X11-unix permissions RUN mkdir -p /tmp/.X11-unix \ From 2a2848b2e10729679375435d38d871989ce71059 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Tue, 5 May 2026 13:11:14 +0100 Subject: [PATCH 5/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- docker/vnc-entrypoint.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docker/vnc-entrypoint.sh b/docker/vnc-entrypoint.sh index fcdae5e..a337dd6 100644 --- a/docker/vnc-entrypoint.sh +++ b/docker/vnc-entrypoint.sh @@ -40,11 +40,17 @@ cleanup_x11() { fi # Ensure the socket directory has the correct sticky-bit permissions - chmod 1777 /tmp/.X11-unix 2>/dev/null || sudo chmod 1777 /tmp/.X11-unix 2>/dev/null || true + if ! chmod 1777 /tmp/.X11-unix 2>/dev/null; then + echo " [x11] ERROR: failed to set permissions on /tmp/.X11-unix; verify the mounted X11 directory is writable and configured with mode 1777." >&2 + return 1 + fi } echo "Checking x11 volume state..." -cleanup_x11 +if ! cleanup_x11; then + echo "Startup aborted due to invalid X11 volume permissions." >&2 + exit 1 +fi # --- Start TurboVNC --- VNC_STARTUP_TIMEOUT=30 # seconds to wait for VNC display to come up From c7523758600435f1e5f3ab49de8a4cb52ad188cf Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Tue, 5 May 2026 13:37:08 +0100 Subject: [PATCH 6/6] fix: resolve chmod issues --- docker/vnc-entrypoint.sh | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/docker/vnc-entrypoint.sh b/docker/vnc-entrypoint.sh index a337dd6..5f40eb9 100644 --- a/docker/vnc-entrypoint.sh +++ b/docker/vnc-entrypoint.sh @@ -12,36 +12,36 @@ cleanup_x11() { local had_stale=false if [ -e /tmp/.X1-lock ]; then - echo " [x11] Found stale lock file /tmp/.X1-lock — removing..." + echo "[x11] Found stale lock file /tmp/.X1-lock — removing..." rm -f /tmp/.X1-lock || sudo rm -f /tmp/.X1-lock if [ -e /tmp/.X1-lock ]; then - echo " [x11] WARNING: failed to remove /tmp/.X1-lock — x11 volume may be in a corrupt state." >&2 + echo "[x11] WARNING: failed to remove /tmp/.X1-lock — x11 volume may be in a corrupt state." >&2 else - echo " [x11] Removed stale lock file." + echo "[x11] Removed stale lock file." had_stale=true fi fi if [ -e /tmp/.X11-unix/X1 ]; then - echo " [x11] Found stale socket /tmp/.X11-unix/X1 — removing..." + echo "[x11] Found stale socket /tmp/.X11-unix/X1 — removing..." rm -f /tmp/.X11-unix/X1 || sudo rm -f /tmp/.X11-unix/X1 if [ -e /tmp/.X11-unix/X1 ]; then - echo " [x11] WARNING: failed to remove /tmp/.X11-unix/X1 — x11 volume may be in a corrupt state." >&2 + echo "[x11] WARNING: failed to remove /tmp/.X11-unix/X1 — x11 volume may be in a corrupt state." >&2 else - echo " [x11] Removed stale socket." + echo "[x11] Removed stale socket." had_stale=true fi fi if $had_stale; then - echo " [x11] Stale X11 files from previous run cleared successfully." + echo "[x11] Stale X11 files from previous run cleared successfully." else - echo " [x11] No stale X11 files found." + echo "[x11] No stale X11 files found." fi # Ensure the socket directory has the correct sticky-bit permissions - if ! chmod 1777 /tmp/.X11-unix 2>/dev/null; then - echo " [x11] ERROR: failed to set permissions on /tmp/.X11-unix; verify the mounted X11 directory is writable and configured with mode 1777." >&2 + if ! sudo chmod 1777 /tmp/.X11-unix 2>/dev/null; then + echo "[x11] ERROR: failed to set permissions on /tmp/.X11-unix; verify the mounted X11 directory is writable and configured with mode 1777." >&2 return 1 fi } @@ -75,13 +75,13 @@ start_turbovnc() { if ! start_turbovnc; then echo "" >&2 echo "ERROR: TurboVNC failed to start within ${VNC_STARTUP_TIMEOUT}s." >&2 - echo " This is often caused by stale files left in the x11 volume from a previous run." >&2 + echo "This is often caused by stale files left in the x11 volume from a previous run." >&2 if [ -s /tmp/vnc.log ]; then echo "--- VNC server log (/tmp/vnc.log) ---" >&2 cat /tmp/vnc.log >&2 echo "--- End of VNC server log ---" >&2 else - echo " (no VNC log available at /tmp/vnc.log)" >&2 + echo "(no VNC log available at /tmp/vnc.log)" >&2 fi echo "" >&2 @@ -154,8 +154,6 @@ echo "xhost +local: applied to :1" xfconf-query -c xfce4-desktop -p "${base}/image-path" -n -t string -s "$WALLPAPER" xfconf-query -c xfce4-desktop -p "${base}/last-image" -n -t string -s "$WALLPAPER" xfconf-query -c xfce4-desktop -p "${base}/last-single-image" -n -t string -s "$WALLPAPER" - - # xfdesktop --reload ) & echo