diff --git a/scripts/self-update.sh b/scripts/self-update.sh index f203a6b5..34a49848 100755 --- a/scripts/self-update.sh +++ b/scripts/self-update.sh @@ -200,6 +200,96 @@ if [ -f "$REPO_DIR/scripts/image-versions.sh" ]; then sudo cp "$REPO_DIR/scripts/image-versions.sh" /opt/archipelago/image-versions.sh fi +# Update first-boot-containers.sh too (the canonical first-boot orchestrator). +# Nodes run it once on install, but keeping a fresh copy on disk means any +# future boot or reconciler invocation uses current port specs and caps. +if [ -f "$REPO_DIR/scripts/first-boot-containers.sh" ]; then + sudo install -m 755 "$REPO_DIR/scripts/first-boot-containers.sh" \ + "$SCRIPTS_DEST/first-boot-containers.sh" +fi + +# Sync UI container source trees (docker/bitcoin-ui, docker/lnd-ui, +# docker/electrs-ui) into /opt/archipelago/docker//. If any file in a +# UI tree changed since last update, rebuild that image and recreate its +# container using the spec from container-specs.sh. This is what prevented +# the lnd-ui port mismatch from reaching nodes through OTA: self-update used +# to update only the backend + frontend, never the UI container images. +UI_DOCKER_DEST="/opt/archipelago/docker" +sudo mkdir -p "$UI_DOCKER_DEST" +UI_REBUILD_LIST="" +for ui in bitcoin-ui lnd-ui electrs-ui; do + src="$REPO_DIR/docker/$ui" + dst="$UI_DOCKER_DEST/$ui" + [ -d "$src" ] || continue + # Hash source tree to decide if rebuild is needed. Any content change + # (Dockerfile, nginx.conf, index.html, assets) triggers a rebuild. + # Hash file contents only (not paths or metadata) so src and dst match + # when their contents are identical regardless of directory prefix. + src_hash=$( (cd "$src" && find . -type f | LC_ALL=C sort | xargs sha256sum 2>/dev/null) | sha256sum | cut -d' ' -f1) + dst_hash="" + if [ -d "$dst" ]; then + dst_hash=$( (cd "$dst" && find . -type f | LC_ALL=C sort | xargs sha256sum 2>/dev/null) | sha256sum | cut -d' ' -f1) + fi + if [ "$src_hash" != "$dst_hash" ]; then + log "UI source changed for $ui; syncing and marking for rebuild" + sudo rsync -a --delete "$src/" "$dst/" + UI_REBUILD_LIST="$UI_REBUILD_LIST $ui" + else + ok "UI source unchanged for $ui" + fi +done + +# Rebuild changed UI images + recreate containers as the archipelago user +# (rootless podman storage lives under ~archipelago). Port mappings and caps +# come from scripts/container-specs.sh so spec drift can't sneak in. +if [ -n "$UI_REBUILD_LIST" ]; then + log "Rebuilding UI containers:$UI_REBUILD_LIST" + # shellcheck disable=SC1091 + # container-specs.sh provides load_spec_archy- and mem_limit . + SPECS="$SCRIPTS_DEST/container-specs.sh" + if [ ! -f "$SPECS" ]; then + warn "container-specs.sh missing at $SPECS; skipping UI rebuild" + else + for ui in $UI_REBUILD_LIST; do + cname="archy-$ui" + log " rebuilding $cname from $UI_DOCKER_DEST/$ui" + # Build image as archipelago user so it lands in the right store. + if ! sudo -u archipelago bash -c " + export XDG_RUNTIME_DIR=/run/user/\$(id -u archipelago) + cd '$UI_DOCKER_DEST/$ui' && + podman build --no-cache -t 'localhost/$ui:local' . >>'$LOG_FILE' 2>&1 + "; then + err " build failed for $ui; keeping existing container" + continue + fi + # Recreate container using spec from container-specs.sh. + if ! sudo -u archipelago bash -c " + export XDG_RUNTIME_DIR=/run/user/\$(id -u archipelago) + source '$SPECS' + load_spec_$cname || { echo 'spec load failed for $cname'; exit 1; } + podman stop '$cname' 2>/dev/null || true + podman rm '$cname' 2>/dev/null || true + PORT_ARG='' + [ -n \"\$SPEC_PORTS\" ] && PORT_ARG=\"-p \$SPEC_PORTS\" + NET_ARG='' + [ \"\$SPEC_NETWORK\" = 'host' ] && NET_ARG='--network host' + CAP_ARGS='--cap-drop ALL' + for c in \$SPEC_CAPS; do CAP_ARGS=\"\$CAP_ARGS --cap-add \$c\"; done + podman run -d --name '$cname' \$PORT_ARG \$NET_ARG \\ + --user 0:0 \$CAP_ARGS \\ + --memory=\"\$SPEC_MEMORY\" \\ + --restart unless-stopped \\ + --security-opt \"\$SPEC_SECURITY\" \\ + 'localhost/$ui:local' >>'$LOG_FILE' 2>&1 + "; then + err " recreate failed for $cname" + continue + fi + ok " $cname rebuilt and running" + done + fi +fi + # Update systemd service if changed if [ -f "$REPO_DIR/image-recipe/configs/archipelago.service" ]; then if ! diff -q "$REPO_DIR/image-recipe/configs/archipelago.service" /etc/systemd/system/archipelago.service &>/dev/null; then