Support TrueNAS 25.x immutable read-only /usr via overlayfs

TrueNAS 25.x mounts /usr as a read-only filesystem. Writing
sitecustomize.py to site-packages and patching the Angular bundle
both fail with EROFS.

Fix: mount a writable overlayfs on each target directory before
writing to it. Upper/work dirs live in /run (tmpfs), so overlays are
volatile per boot and are recreated by apply.sh on every PREINIT run
before middlewared starts.

apply.sh:
- Add _ensure_writable(dir, tag): probes writability; mounts overlay
  in /run/truecloud-{tag}-{upper,work} if the directory is read-only;
  detects if the overlay is already mounted (idempotent)
- Call _ensure_writable before site-packages writes (tag "sc")
- Detect webui dir with bash loop; call _ensure_writable before
  patch_ui.py (tag "ui") — non-fatal if mount fails

uninstall.sh:
- Add overlay unmounting section after file restoration and before
  rm -rf, so the lower layer's originals are exposed immediately
- Move _restore_failed exit 1 to after unmount so overlays are
  cleaned up even on partial failure
- Update "no backup files" message for immutable OS context
This commit is contained in:
2026-06-16 14:54:21 +00:00
parent 9d9326c212
commit 3afca7075e
2 changed files with 75 additions and 8 deletions
+26 -6
View File
@@ -117,6 +117,32 @@ while IFS= read -r backup; do
done < <(find /usr/share/truenas /usr/share/truenas-ui /var/www/truenas \
-name "*.js.pre-truecloud-patch" 2>/dev/null)
if [ "$RESTORED" -eq 0 ]; then
echo " No backup files found."
echo " On an immutable OS the UI patch is volatile and already gone after reboot."
fi
echo ""
# ── Unmount overlays (TrueNAS 25.x immutable OS) ─────────────────────────────
echo "Unmounting truecloud overlays (if any) ..."
_ov_found=0
for _tag in sc ui; do
if mount | grep -qF "truecloud-${_tag} on "; then
_ov_mnt=$(mount | grep "truecloud-${_tag} on " | awk '{print $3}' | head -1)
if umount "$_ov_mnt" 2>/dev/null; then
echo " Unmounted: $_ov_mnt"
else
echo " WARNING: Could not unmount overlay on $_ov_mnt"
fi
_ov_found=1
fi
done
if [ "$_ov_found" -eq 0 ]; then
echo " None active."
fi
echo ""
if [ "$_restore_failed" -eq 1 ]; then
echo ""
echo "ERROR: One or more UI bundle backups could not be restored." >&2
@@ -125,12 +151,6 @@ if [ "$_restore_failed" -eq 1 ]; then
exit 1
fi
if [ "$RESTORED" -eq 0 ]; then
echo " No backup files found."
echo " The UI patch will be undone automatically by the next TrueNAS update."
fi
echo ""
# ── Remove patch directory ────────────────────────────────────────────────────
if [ -d "$PATCH_DIR" ]; then