mattermost: add PikaPods migration helper (DB dump + files import)

New opt-in prompt on fresh/new installs (skipped on "update" reruns,
where an existing instance is already in real use and importing over
it would be destructive): "Migrating from an existing Mattermost
instance (e.g. PikaPods)?" -- if yes, generates
migrate-from-pikapods.sh in the instance's own directory, same
generated-helper pattern as Immich's import-photos.sh.

Checked PikaPods' own docs before writing this rather than guessing
at their export mechanics: they expose per-pod SFTP (file access) and
a Database-access toggle that hands you an Adminer link for a full
SQL dump -- their own documented backup/migration flow is stop the
pod, SFTP the files, export the DB via Adminer. The generated script
assumes that shape (plain-text SQL dump + a files directory) and says
so in its header, including that PikaPods' exact SFTP layout wasn't
verified against a live pod so the files-argument path needs the
user's own confirmation.

What the script does: stops the mattermost container (leaves the DB
container running), drops and recreates the database owned by the
same existing role -- so .env's credentials are never touched or
regenerated, avoiding the "restored data, mismatched password" bug
class fixed elsewhere in this repo -- imports the dump via psql,
rsyncs the files directory into ./data, restarts. Requires typing
"YES" to proceed since it's destructive to whatever's currently in
the fresh instance's database.

Correctly parameterized per-instance: pulled from install_mattermost's
own MM_CONTAINER/DB_CONTAINER variables, so it's already correct for
either the first instance or an additional named one.

Verified end-to-end: prompt fires correctly at the right point in the
flow, generated script is syntactically valid, and the container
names/paths it's parameterized with match the actual instance being
installed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBtExJcqxnokyZZKmphdug
This commit is contained in:
Claude
2026-08-09 21:45:26 +00:00
parent 344bdf4a0f
commit 5f36b14f93
+120
View File
@@ -592,6 +592,126 @@ MD
log_warning "WebRTC (voice/video calls) requires HTTPS. Configure Caddy and update SITE_URL."
fi
# ── Migration helper (new/fresh installs only — not "update" reruns,
# where an existing instance is already in real use and importing over
# it would be destructive) ────────────────────────────────────────────
if [ "$MODE" != "update" ]; then
echo ""
local MIGRATING=""
prompt_yn "Migrating from an existing Mattermost instance (e.g. PikaPods)? (y/n):" "n" MIGRATING
if [[ "$MIGRATING" =~ ^[Yy]$ ]]; then
cat > "$DIR/migrate-from-pikapods.sh" << 'MIGRATE_HEAD'
#!/bin/bash
################################################################################
# migrate-from-pikapods.sh — generated by ubuntu-post-install
#
# Imports a Mattermost database dump + file storage exported from another
# instance (e.g. PikaPods) into THIS freshly-created instance, replacing its
# empty database and populating its file storage.
#
# PikaPods export procedure (Pod Settings): enable SFTP + Database access,
# STOP the pod first (flushes anything still in memory to disk), SFTP the
# pod's files down, then use the Adminer link PikaPods gives you to export
# the database as a plain SQL dump. See docs.pikapods.com/manage/backup.
#
# This script assumes a PLAIN-TEXT SQL dump (what Adminer produces by
# default). If you have a custom-format pg_dump instead, use `pg_restore`
# in place of the `psql < dump` step below.
#
# IMPORTANT: point the files argument at the SUBDIRECTORY that holds
# Mattermost's own file storage inside whatever you downloaded via SFTP
# (commonly named `data`), not the whole SFTP root — PikaPods' exact
# layout wasn't verified against a live pod, so confirm this yourself
# before running.
#
# Usage:
# ./migrate-from-pikapods.sh <path-to-sql-dump> <path-to-files-dir>
################################################################################
MIGRATE_HEAD
cat >> "$DIR/migrate-from-pikapods.sh" << MIGRATE_VARS
PROJECT_DIR="$DIR"
MM_CONTAINER="$MM_CONTAINER"
DB_CONTAINER="$DB_CONTAINER"
DB_NAME="mattermost"
DB_USER="mattermost"
MIGRATE_VARS
cat >> "$DIR/migrate-from-pikapods.sh" << 'MIGRATE_BODY'
set -uo pipefail
cd "$PROJECT_DIR" || exit 1
SQL_DUMP="${1:-}"
FILES_DIR="${2:-}"
if [ -z "$SQL_DUMP" ] || [ -z "$FILES_DIR" ]; then
echo "Usage: $0 <path-to-sql-dump> <path-to-files-dir>"
exit 1
fi
[ -f "$SQL_DUMP" ] || { echo "SQL dump not found: $SQL_DUMP"; exit 1; }
[ -d "$FILES_DIR" ] || { echo "Files directory not found: $FILES_DIR"; exit 1; }
[ -f "docker-compose.yml" ] || { echo "Run this from $PROJECT_DIR (docker-compose.yml not found here)."; exit 1; }
echo ""
echo "┌─────────────────────────────────────────────────────────────────┐"
echo "│ MATTERMOST MIGRATION — THIS REPLACES THE CURRENT DATABASE │"
echo "└─────────────────────────────────────────────────────────────────┘"
echo ""
echo " Target instance: $PROJECT_DIR"
echo " SQL dump: $SQL_DUMP"
echo " Files: $FILES_DIR (copied into ./data)"
echo ""
read -r -p " Type YES to proceed: " CONFIRM
[ "$CONFIRM" = "YES" ] || { echo "Aborted — no changes made."; exit 0; }
echo ""
echo "Stopping $MM_CONTAINER (keeping $DB_CONTAINER running)..."
docker compose stop mattermost
echo "Waiting for $DB_CONTAINER to accept connections..."
tries=0
until docker exec "$DB_CONTAINER" pg_isready -U "$DB_USER" >/dev/null 2>&1 || [ "$tries" -ge 30 ]; do
sleep 1; tries=$((tries + 1))
done
echo "Dropping and recreating '$DB_NAME' (owned by the existing '$DB_USER' role — .env credentials are untouched)..."
if ! docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d postgres -c "DROP DATABASE IF EXISTS $DB_NAME;" \
|| ! docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d postgres -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;"; then
echo "Failed to reset the database — check: docker compose logs db"
exit 1
fi
echo "Importing $SQL_DUMP..."
if ! docker exec -i "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" < "$SQL_DUMP" > /tmp/mm-migrate-import.log 2>&1; then
echo "Import reported errors — check /tmp/mm-migrate-import.log before continuing."
echo "(Some warnings, e.g. about extensions already existing, are expected and harmless."
echo " Look for actual failures — missing tables, permission errors — before deciding.)"
fi
echo "Copying files into ./data..."
mkdir -p ./data
rsync -a "$FILES_DIR"/ ./data/ 2>/dev/null || cp -a "$FILES_DIR"/. ./data/
echo "Starting Mattermost..."
docker compose up -d
echo ""
echo "Done. Verify before treating this as live:"
echo " - Open the site and confirm you can log in as an existing (migrated) user"
echo " - Spot-check a channel with history and a message that has an attached file"
echo " - Check System Console → users/teams counts look right"
echo ""
echo "Import log: /tmp/mm-migrate-import.log"
MIGRATE_BODY
chmod +x "$DIR/migrate-from-pikapods.sh"
chown "$ACTUAL_USER:$ACTUAL_USER" "$DIR/migrate-from-pikapods.sh"
log_success "Migration helper written: $DIR/migrate-from-pikapods.sh"
log_info "Run it once you have both a SQL dump and the files directory from PikaPods."
fi
fi
local START=""
prompt_yn "Start Mattermost now? (y/n):" "y" START
if [ "$START" = "y" ] || [ "$START" = "Y" ]; then