mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 02:48:38 -04:00
The only self-service fix for a permission-broken cluster was reset_api_db.sh, which drops the database. Repair now restores postgres ownership of /var/lib/postgresql and /etc/postgresql and restarts Postgres before configuring the database, same as the reset script but keeping the data. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
222 lines
8.8 KiB
Bash
Executable file
222 lines
8.8 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# This script will attempt to repair a WROLPi installation. It will not use internet.
|
|
|
|
cd /opt/wrolpi || (echo "Cannot repair. /opt/wrolpi does not exist" && exit 1)
|
|
|
|
# Re-execute this script if it wasn't called with sudo.
|
|
if [ $EUID != 0 ]; then
|
|
sudo "$0" "$@"
|
|
exit $?
|
|
fi
|
|
|
|
rpi=false
|
|
if (grep 'Raspberry Pi' /proc/cpuinfo >/dev/null); then
|
|
rpi=true
|
|
fi
|
|
|
|
set -e
|
|
set -x
|
|
|
|
# Stop services if they are running.
|
|
systemctl stop wrolpi-controller.service || :
|
|
systemctl stop wrolpi-api.service || :
|
|
systemctl stop wrolpi-app.service || :
|
|
systemctl stop wrolpi-kiwix.service || :
|
|
systemctl stop caddy || :
|
|
|
|
# Clear Python bytecode cache from virtual environments to fix potential corruption.
|
|
echo "Clearing Python bytecode cache..."
|
|
find /opt/wrolpi/venv -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || :
|
|
find /opt/wrolpi/venv -name "*.pyc" -delete 2>/dev/null || :
|
|
find /opt/wrolpi/controller/venv -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || :
|
|
find /opt/wrolpi/controller/venv -name "*.pyc" -delete 2>/dev/null || :
|
|
find /opt/wrolpi-help/venv -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || :
|
|
find /opt/wrolpi-help/venv -name "*.pyc" -delete 2>/dev/null || :
|
|
|
|
# Create the WROLPi user
|
|
grep wrolpi: /etc/passwd || useradd -md /home/wrolpi wrolpi -s "$(command -v bash)"
|
|
[ -f /home/wrolpi/.pgpass ] || cat >/home/wrolpi/.pgpass <<'EOF'
|
|
127.0.0.1:5432:wrolpi:wrolpi:wrolpi
|
|
EOF
|
|
chmod 0600 /home/wrolpi/.pgpass
|
|
|
|
# Reset any inadvertent changes to the WROLPi repo. Restore ownership in case this repair script fails.
|
|
git config --global --add safe.directory /opt/wrolpi
|
|
git reset HEAD --hard
|
|
chown -R wrolpi:wrolpi /opt/wrolpi
|
|
|
|
# Copy configs to system.
|
|
mkdir -p /etc/caddy
|
|
cp /opt/wrolpi/etc/raspberrypios/Caddyfile /etc/caddy/Caddyfile
|
|
mkdir -p /var/www
|
|
cp /opt/wrolpi/etc/raspberrypios/50x.html /var/www/50x.html
|
|
|
|
# Generate certificate for HTTPS.
|
|
/opt/wrolpi/scripts/generate_certificates.sh
|
|
|
|
# Install map fonts from blob (needed for MapLibre map labels).
|
|
MAP_FONTS_BLOB=/opt/wrolpi-blobs/map-fonts.tar.gz
|
|
if [ -f "${MAP_FONTS_BLOB}" ]; then
|
|
mkdir -p /opt/wrolpi/modules/map/static/fonts
|
|
tar -xzf "${MAP_FONTS_BLOB}" -C /opt/wrolpi/modules/map/static/
|
|
fi
|
|
|
|
# Start Caddy quickly so user can access Controller from React UI
|
|
systemctl start caddy || :
|
|
|
|
# WROLPi needs a few privileged commands.
|
|
cp /opt/wrolpi/etc/raspberrypios/90-wrolpi /etc/sudoers.d/90-wrolpi
|
|
chmod 0440 /etc/sudoers.d/90-wrolpi
|
|
# Verify this new file is valid.
|
|
visudo -c -f /etc/sudoers.d/90-wrolpi
|
|
|
|
# Update the Portable bootstrap on boxes installed from the Live USB; it is
|
|
# otherwise frozen at image-build time.
|
|
LIVE_INCLUDES=/opt/wrolpi/debian-live-config/config/includes.chroot
|
|
if [ -f /usr/local/sbin/wrolpi-bootstrap.sh ]; then
|
|
cp "${LIVE_INCLUDES}/usr/local/sbin/wrolpi-bootstrap.sh" /usr/local/sbin/wrolpi-bootstrap.sh
|
|
chmod 0755 /usr/local/sbin/wrolpi-bootstrap.sh
|
|
if [ -f /etc/systemd/system/wrolpi-bootstrap.service ]; then
|
|
cp "${LIVE_INCLUDES}/etc/systemd/system/wrolpi-bootstrap.service" /etc/systemd/system/wrolpi-bootstrap.service
|
|
fi
|
|
fi
|
|
|
|
# Install the systemd services
|
|
cp /opt/wrolpi/etc/raspberrypios/wrolpi*.service /etc/systemd/system/
|
|
cp /opt/wrolpi/etc/raspberrypios/wrolpi-*.timer /etc/systemd/system/
|
|
cp /opt/wrolpi/etc/raspberrypios/wrolpi.target /etc/systemd/system/
|
|
systemctl enable wrolpi-controller.service
|
|
systemctl enable wrolpi-api.service
|
|
systemctl enable wrolpi-app.service
|
|
systemctl enable wrolpi-kiwix.service
|
|
systemctl enable wrolpi-help.service
|
|
systemctl enable wrolpi-mounts.service
|
|
systemctl enable wrolpi-cert-renew.timer
|
|
|
|
# Repair Controller (offline-safe - no pip install)
|
|
repair_controller() {
|
|
echo "Checking WROLPi Controller..."
|
|
|
|
# Check venv exists
|
|
if [ ! -f /opt/wrolpi/controller/venv/bin/python ]; then
|
|
echo "ERROR: Controller venv missing!"
|
|
echo "Run install.sh or upgrade.sh (requires internet) to reinstall."
|
|
return 1
|
|
fi
|
|
|
|
# Check venv is functional
|
|
if ! /opt/wrolpi/controller/venv/bin/python --version > /dev/null 2>&1; then
|
|
echo "ERROR: Controller venv is corrupted!"
|
|
echo "Run install.sh or upgrade.sh (requires internet) to reinstall."
|
|
return 1
|
|
fi
|
|
|
|
# Check systemd service is installed
|
|
if [ ! -f /etc/systemd/system/wrolpi-controller.service ]; then
|
|
echo "Controller systemd service not installed, copying..."
|
|
cp /opt/wrolpi/etc/raspberrypios/wrolpi-controller.service /etc/systemd/system/
|
|
systemctl daemon-reload
|
|
fi
|
|
|
|
# Ensure service is enabled
|
|
if ! systemctl is-enabled wrolpi-controller > /dev/null 2>&1; then
|
|
echo "Enabling Controller service..."
|
|
systemctl enable wrolpi-controller
|
|
fi
|
|
|
|
echo "Controller repair completed"
|
|
}
|
|
|
|
# Run Controller repair if venv exists (skip on fresh install)
|
|
if [ -d /opt/wrolpi/controller/venv ]; then
|
|
repair_controller || echo "Controller repair failed, continuing..."
|
|
fi
|
|
|
|
# Start Controller so user can monitor repair in UI.
|
|
systemctl start wrolpi-controller
|
|
|
|
/usr/bin/systemctl daemon-reload
|
|
|
|
# WROLPi needs a few privileged commands.
|
|
cp /opt/wrolpi/etc/raspberrypios/90-wrolpi /etc/sudoers.d/90-wrolpi
|
|
chmod 0440 /etc/sudoers.d/90-wrolpi
|
|
# Verify this new file is valid.
|
|
visudo -c -f /etc/sudoers.d/90-wrolpi
|
|
|
|
# Heal Postgres cluster ownership before configuring the database. A stray
|
|
# recursive chown can leave cluster files unreadable by the server: the
|
|
# postmaster stays up but new backends die with FATAL: could not open file
|
|
# "global/pg_filenode.map": Permission denied. Same healing as
|
|
# reset_api_db.sh, but without dropping the database.
|
|
if id postgres >/dev/null 2>&1; then
|
|
[ -d /var/lib/postgresql ] && chown -R postgres:postgres /var/lib/postgresql 2>/dev/null || :
|
|
[ -d /etc/postgresql ] && chown -R postgres:postgres /etc/postgresql 2>/dev/null || :
|
|
systemctl restart postgresql 2>/dev/null || :
|
|
fi
|
|
|
|
# Configure Postgresql. Do this after the API is stopped. Never fatal: a
|
|
# repair/upgrade must complete its system-level work even when the database
|
|
# is down (e.g. it is the reboot after this repair that revives Postgres).
|
|
/opt/wrolpi/scripts/initialize_api_db.sh || \
|
|
echo "WARNING: could not initialize the database; the API will report if it stays down."
|
|
# wrolpi user is superuser so they can import maps.
|
|
sudo -iu postgres psql -c "alter user wrolpi with superuser" || :
|
|
|
|
# Create the media directory. This should be mounted by the maintainer.
|
|
[ -d /media/wrolpi ] || mkdir /media/wrolpi
|
|
# Create config directory if external drive is mounted, and is empty.
|
|
if grep -qs /media/wrolpi /proc/mounts && [ -z "$(ls -A /media/wrolpi)" ] && [ ! -d /media/wrolpi/config ]; then
|
|
mkdir /media/wrolpi/config
|
|
fi
|
|
|
|
# Build the frontend app.
|
|
(cd /opt/wrolpi/app && npm run build)
|
|
|
|
# Change owner of the media directory, ignore any errors because the drive may be fat/exfat/etc.
|
|
chown wrolpi:wrolpi /media/wrolpi 2>/dev/null || echo "Ignoring failure to change media directory permissions."
|
|
# Ensure the config directory is owned by wrolpi so the API can write config files.
|
|
[ -d /media/wrolpi/config ] && chown -R wrolpi:wrolpi /media/wrolpi/config 2>/dev/null || :
|
|
# On Portable (live-boot) systems the Postgres cluster lives under config/postgresql,
|
|
# bind-mounted over /var/lib/postgresql — so the config chown above just swept it. Restore
|
|
# ownership only when that bind is active; on installed systems Postgres lives on the root
|
|
# filesystem and any config/postgresql directory is inert (dead weight or a user's backup).
|
|
if mountpoint -q /var/lib/postgresql 2>/dev/null && id postgres >/dev/null 2>&1; then
|
|
chown -R postgres:postgres /var/lib/postgresql /etc/postgresql 2>/dev/null || :
|
|
fi
|
|
|
|
# Remove immutable flag from blob files before chown (may not exist or may not be set).
|
|
chattr -i /opt/wrolpi-blobs/* 2>/dev/null || :
|
|
|
|
chown -R wrolpi:wrolpi /home/wrolpi /opt/wrolpi*
|
|
|
|
# Protect blob files from accidental modification or deletion.
|
|
# These files are critical for initializing WROLPi.
|
|
if [ -d /opt/wrolpi-blobs ] && ls /opt/wrolpi-blobs/* >/dev/null 2>&1; then
|
|
chown -R root:root /opt/wrolpi-blobs
|
|
chmod 444 /opt/wrolpi-blobs/*
|
|
chattr +i /opt/wrolpi-blobs/*
|
|
fi
|
|
|
|
# Copy MOTD once the repair has been successful.
|
|
cp /opt/wrolpi/etc/raspberrypios/motd/30-wrolpi.motd /etc/update-motd.d/30-wrolpi
|
|
chmod +x /etc/update-motd.d/*
|
|
|
|
# Copy desktop shortcuts to existing users (new users get them from /etc/skel).
|
|
if [[ ${rpi} == true ]]; then
|
|
for user_home in /home/wrolpi /home/pi; do
|
|
if [ -d "${user_home}/Desktop" ]; then
|
|
cp /opt/wrolpi/etc/raspberrypios/*.desktop "${user_home}/Desktop/"
|
|
chown -R "$(basename ${user_home})":"$(basename ${user_home})" "${user_home}/Desktop/"
|
|
fi
|
|
done
|
|
# Update skeleton for future users.
|
|
mkdir -p /etc/skel/Desktop
|
|
cp /opt/wrolpi/etc/raspberrypios/*.desktop /etc/skel/Desktop/
|
|
fi
|
|
|
|
systemctl restart wrolpi-help
|
|
systemctl start wrolpi.target
|
|
|
|
set +x
|
|
|
|
echo "Repair has completed. You may run /opt/wrolpi/help.sh to check system status."
|