mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 19:01:39 -04:00
Adding WROLPi Portable Phase 2: persistence partition + DB bootstrap.
wrolpi-portable-bootstrap.service runs at every boot (idempotent throughout) and owns the persistence partition lifecycle: - First boot: creates an ext4 partition labeled 'persistence' in free space at the end of the boot drive (sfdisk --append --no-reread --force because the live medium is mounted from the same disk), bind-mounts source dirs over /var/lib/postgresql, /etc/postgresql, and /media/wrolpi, creates a fresh Postgres cluster, and runs initialize_api_db.sh. - Subsequent boots: live-boot's persistence machinery applies the bind mounts in initramfs (kernel cmdline now includes 'persistence persistence-label=persistence persistence-media=removable'); the script mostly no-ops apart from regenerating the leaf TLS cert. After bootstrap completes the script enables and starts wrolpi-api, wrolpi-app, and wrolpi-kiwix — these stay disabled in the chroot hook so they cannot start until the DB and configs are ready (avoiding the "half-finished state with empty configs" failure mode). Also adds parted, gdisk, dosfstools, and exfatprogs to the package list so the live system can fully diagnose / repair / partition without internet. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
97010914ad
commit
37ac131d64
5 changed files with 170 additions and 1 deletions
|
|
@ -80,7 +80,7 @@ lb config \
|
|||
--clean \
|
||||
--color \
|
||||
--linux-packages "linux-image linux-headers" \
|
||||
--bootappend-live "boot=live components quiet splash noswap live-config.username=wrolpi live-config.user-fullname=WROLPi live-config.hostname=wrolpi" \
|
||||
--bootappend-live "boot=live components quiet splash noswap persistence persistence-storage=filesystem persistence-media=removable persistence-label=persistence live-config.username=wrolpi live-config.user-fullname=WROLPi live-config.hostname=wrolpi" \
|
||||
--iso-volume "WROLPi Portable v${VERSION}" \
|
||||
--iso-application "WROLPi Portable v${VERSION}" \
|
||||
--iso-preparer WROLPi \
|
||||
|
|
|
|||
|
|
@ -158,6 +158,13 @@ systemctl enable wrolpi-controller.service
|
|||
# Enable weekly certificate renewal check.
|
||||
systemctl enable wrolpi-cert-renew.timer
|
||||
|
||||
# Bootstrap service: creates the persistence partition on first boot,
|
||||
# Postgres cluster + DB on every boot (idempotent). The wrolpi-* runtime
|
||||
# services (api/app/kiwix) are enabled BY this bootstrap, not here, so they
|
||||
# cannot start until persistence + DB are ready.
|
||||
chmod +x /usr/local/sbin/wrolpi-portable-bootstrap.sh
|
||||
systemctl enable wrolpi-portable-bootstrap.service
|
||||
|
||||
# Plymouth — replace Debian-branded splash with a minimal theme. live-build's
|
||||
# initramfs regeneration at the end of the chroot phase will pick up this
|
||||
# change so the new theme is used at boot.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
[Unit]
|
||||
Description=WROLPi Portable bootstrap (persistence partition + DB)
|
||||
Documentation=https://github.com/lrnselfreliance/wrolpi
|
||||
After=local-fs.target systemd-tmpfiles-setup.service
|
||||
Before=postgresql.service wrolpi-api.service wrolpi-app.service wrolpi-kiwix.service wrolpi-controller.service wrolpi-first-startup.service wrolpi.target
|
||||
Wants=local-fs.target
|
||||
RequiresMountsFor=/usr/lib/live/mount/medium
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/local/sbin/wrolpi-portable-bootstrap.sh
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
TimeoutStartSec=600
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
#!/usr/bin/env bash
|
||||
# WROLPi Portable bootstrap — runs at every boot via
|
||||
# wrolpi-portable-bootstrap.service. Idempotent throughout.
|
||||
#
|
||||
# First boot: the persistence partition does not yet exist. This script
|
||||
# creates it in the free space at the end of the boot drive, formats it as
|
||||
# ext4 with label `persistence`, writes a persistence.conf so future boots
|
||||
# pick it up automatically via live-boot, bind-mounts the source dirs over
|
||||
# /var/lib/postgresql, /etc/postgresql, and /media/wrolpi, creates a fresh
|
||||
# Postgres cluster, runs initialize_api_db.sh, and enables the WROLPi
|
||||
# runtime services.
|
||||
#
|
||||
# Subsequent boots: live-boot's persistence machinery has already done the
|
||||
# bind mounts (because the kernel cmdline includes `persistence
|
||||
# persistence-label=persistence persistence-media=removable`). Cluster and
|
||||
# DB already exist. Most steps no-op; we always regenerate the leaf TLS
|
||||
# certificate to pick up the current hostname/IP, and we always ensure the
|
||||
# wrolpi-* services are enabled and started.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
log() { echo "[wrolpi-portable-bootstrap] $*"; }
|
||||
|
||||
# --- Identify the boot drive ---------------------------------------------
|
||||
|
||||
# live-boot uses one of these mount points depending on version / config.
|
||||
BOOT_PART=""
|
||||
for mp in /usr/lib/live/mount/medium /run/live/medium /lib/live/mount/medium; do
|
||||
if BOOT_PART=$(findmnt -nr -o SOURCE "$mp" 2>/dev/null) && [ -n "$BOOT_PART" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z "$BOOT_PART" ]; then
|
||||
log "ERROR: could not locate live medium mount point"
|
||||
exit 1
|
||||
fi
|
||||
BOOT_DRIVE=$(lsblk -no PKNAME "$BOOT_PART")
|
||||
BOOT_DRIVE="/dev/${BOOT_DRIVE}"
|
||||
log "live medium $BOOT_PART on $BOOT_DRIVE"
|
||||
|
||||
# --- Find or create persistence partition --------------------------------
|
||||
|
||||
PERSIST_PART=$(blkid -L persistence 2>/dev/null || true)
|
||||
if [ -z "$PERSIST_PART" ]; then
|
||||
log "no persistence partition found; creating one on $BOOT_DRIVE"
|
||||
# Compute next 1-MiB-aligned start sector after the last existing partition.
|
||||
LAST_END=$(sfdisk -d "$BOOT_DRIVE" | awk '/^\/dev\// {n=$4+$6} END{print n}')
|
||||
START=$(( ((LAST_END + 2047) / 2048) * 2048 ))
|
||||
# --no-reread --force: required because the live medium is mounted from
|
||||
# this same drive. Adding a new partition entry past the mounted one is
|
||||
# safe; we use partx -a below to inform the running kernel without forcing
|
||||
# a re-read of the whole partition table.
|
||||
echo "start=$START, type=83" | sfdisk --append --no-reread --force "$BOOT_DRIVE"
|
||||
partx -a "$BOOT_DRIVE" 2>/dev/null || true
|
||||
udevadm settle || true
|
||||
PERSIST_PART=$(blkid -L persistence 2>/dev/null || true)
|
||||
if [ -z "$PERSIST_PART" ]; then
|
||||
PERSIST_PART=$(lsblk -lnpo NAME "$BOOT_DRIVE" | tail -1)
|
||||
fi
|
||||
if ! [ -b "$PERSIST_PART" ]; then
|
||||
log "ERROR: failed to locate the newly created persistence partition"
|
||||
exit 1
|
||||
fi
|
||||
log "formatting $PERSIST_PART as ext4 with label 'persistence'"
|
||||
mkfs.ext4 -L persistence -F "$PERSIST_PART"
|
||||
fi
|
||||
|
||||
# --- Mount persistence and prepare source-dir layout ---------------------
|
||||
|
||||
mkdir -p /mnt/persistence
|
||||
mountpoint -q /mnt/persistence || mount "$PERSIST_PART" /mnt/persistence
|
||||
|
||||
mkdir -p /mnt/persistence/postgresql-data \
|
||||
/mnt/persistence/postgresql-config \
|
||||
/mnt/persistence/wrolpi
|
||||
|
||||
chown postgres:postgres /mnt/persistence/postgresql-data /mnt/persistence/postgresql-config
|
||||
chmod 0700 /mnt/persistence/postgresql-data
|
||||
chown wrolpi:wrolpi /mnt/persistence/wrolpi
|
||||
|
||||
# Write persistence.conf so live-boot's initramfs persistence machinery can
|
||||
# apply these bind mounts before systemd starts on subsequent boots.
|
||||
cat > /mnt/persistence/persistence.conf <<EOF
|
||||
/var/lib/postgresql union,source=postgresql-data
|
||||
/etc/postgresql union,source=postgresql-config
|
||||
/media/wrolpi union,source=wrolpi
|
||||
EOF
|
||||
|
||||
# --- Bind mounts (idempotent — only mount if not already mounted) -------
|
||||
|
||||
bind_if_unmounted() {
|
||||
local src=$1 dest=$2
|
||||
mkdir -p "$dest"
|
||||
mountpoint -q "$dest" || mount --bind "$src" "$dest"
|
||||
}
|
||||
|
||||
bind_if_unmounted /mnt/persistence/postgresql-data /var/lib/postgresql
|
||||
bind_if_unmounted /mnt/persistence/postgresql-config /etc/postgresql
|
||||
bind_if_unmounted /mnt/persistence/wrolpi /media/wrolpi
|
||||
|
||||
# --- Postgres cluster ----------------------------------------------------
|
||||
|
||||
if ! pg_lsclusters -h | awk '{print $1,$2}' | grep -q "^15 main$"; then
|
||||
log "creating Postgres cluster 15/main on persistence"
|
||||
pg_createcluster 15 main
|
||||
fi
|
||||
systemctl start postgresql@15-main.service
|
||||
|
||||
# --- WROLPi DB schema + initial config import ----------------------------
|
||||
|
||||
if ! sudo -iu postgres psql -lqt | cut -d \| -f 1 | grep -qw wrolpi; then
|
||||
log "initializing WROLPi database"
|
||||
/opt/wrolpi/scripts/initialize_api_db.sh
|
||||
fi
|
||||
|
||||
# --- Certificates --------------------------------------------------------
|
||||
# CA persists in /media/wrolpi/config/ssl/ (created on first run). Leaf
|
||||
# cert is regenerated every boot so SANs reflect the current hostname/IP.
|
||||
|
||||
/opt/wrolpi/scripts/generate_certificates.sh
|
||||
|
||||
# --- Caddy: swap onboarding stub for the full Caddyfile if needed --------
|
||||
|
||||
if ! diff -q /opt/wrolpi/etc/raspberrypios/Caddyfile /etc/caddy/Caddyfile >/dev/null 2>&1; then
|
||||
log "swapping onboarding Caddyfile for the full Caddyfile"
|
||||
cp /opt/wrolpi/etc/raspberrypios/Caddyfile /etc/caddy/Caddyfile
|
||||
systemctl restart caddy || true
|
||||
fi
|
||||
|
||||
# --- /media/wrolpi ownership + config dir --------------------------------
|
||||
|
||||
chown wrolpi:wrolpi /media/wrolpi 2>/dev/null || true
|
||||
mkdir -p /media/wrolpi/config
|
||||
chown wrolpi:wrolpi /media/wrolpi/config
|
||||
|
||||
# --- Enable and start the WROLPi runtime services -----------------------
|
||||
|
||||
systemctl enable --now wrolpi-api.service wrolpi-app.service wrolpi-kiwix.service
|
||||
|
||||
log "bootstrap complete"
|
||||
|
|
@ -11,8 +11,10 @@ catdoc
|
|||
chromium
|
||||
cpufrequtils
|
||||
curl
|
||||
dosfstools
|
||||
ethtool
|
||||
exfat-fuse
|
||||
exfatprogs
|
||||
fdupes
|
||||
ffmpeg
|
||||
firefox-esr
|
||||
|
|
@ -21,6 +23,7 @@ fonts-noto-hinted
|
|||
fonts-noto-unhinted
|
||||
gcc
|
||||
gcc-doc
|
||||
gdisk
|
||||
git
|
||||
git-doc
|
||||
gnupg-agent
|
||||
|
|
@ -54,6 +57,7 @@ nicstat
|
|||
nodejs
|
||||
npm
|
||||
ntfs-3g
|
||||
parted
|
||||
pkg-config
|
||||
postgresql-15
|
||||
postgresql-doc
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue