feat(self-update): sync and rebuild UI containers on OTA
self-update.sh previously rebuilt only the backend binary and Vue
frontend. The custom UI containers (archy-bitcoin-ui, archy-lnd-ui,
archy-electrs-ui) were left untouched forever. That meant any change to
docker/<ui>/{Dockerfile, nginx.conf, index.html, ...} never reached a
running node through OTA; it required a manual SSH + rebuild. This is
exactly why the lnd-ui port fix didnt reach .228 in v1.7.43-alpha.
Add a sync-and-rebuild stage:
1. Hash each docker/<ui>/ tree (content-only, path-stable via
`cd && find` so src and dst compare equal when identical).
2. rsync changed trees to /opt/archipelago/docker/<ui>/.
3. For each changed UI: rebuild image as the archipelago user
(rootless podman), then stop+remove+recreate the container using
the canonical spec from scripts/container-specs.sh. Port mappings,
caps, memory, and security opts all come from the spec, so the
runtime cant drift from the tree.
Also install first-boot-containers.sh into /opt/archipelago/scripts/ so
a later reconciler run or reboot picks up current orchestration logic.
Idempotent: if no UI tree changed since the last update, the whole stage
is a no-op beyond the hash compare. Verified end-to-end on .228 with a
synthetic change to lnd-ui: detection, sync, build, recreate, and HTTP
200 on both the direct container port and the host-nginx /app/lnd/
proxy.
This commit is contained in:
@@ -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/<name>/. 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-<ui> and mem_limit <name>.
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user