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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user