Skip to Content

Generic database restore

Database-specific legacy commands live in _pmiregistry/scripts/restore/.

restore_database.sh restores one PMIVerse Odoo database backup into its original target name. It supports registry aliases, explicit configuration, optional neutralization, and neutralization of an existing database without a restore.

Use --dry-run first. Restore and neutralization are destructive operational actions and must not be run against a real PostgreSQL database or filestore without separate authorization and a verified recovery plan.

Common usage

# Inspect registry resolution without changing anything
/srv/pmiverse/_pmiconfig/scripts/restore/restore_database.sh demo --dry-run

# Inspect explicit resolution
/srv/pmiverse/_pmiconfig/scripts/restore/restore_database.sh \
  --suite 18 \
  --db example \
  --source-file /absolute/path/example_latest.zip \
  --dest /srv/pmiverse/_pmisuite18/data/dumps/example \
  --filestore /srv/pmiverse/_pmisuite18/data/filestore \
  --dry-run

# Restore and apply neutralization after publication
/srv/pmiverse/_pmiconfig/scripts/restore/restore_database.sh demo --neutralize

# Neutralize an existing database without reading or publishing a filestore
/srv/pmiverse/_pmiconfig/scripts/restore/restore_database.sh \
  --suite 18 --db example --only-neutralize

Aliases, database names, and host mappings are maintained in /srv/pmiverse/_pmiregistry/config/pmiverse.conf. The examples above use a synthetic demo alias; substitute an alias from your registry. See the deployment notes for installation-specific assets and the linked legacy restore runbook for per-target behavior.

Host subdirectories exist on the local rsync/restore server. Remote producers still write to data/backups/; restoring directly there requires an explicit source override.

Run the script as the ordinary account that owns the suite resources and has the required PostgreSQL privileges. The script does not invoke sudo.

Important options

  • NAME or --target NAME selects an alias from /srv/pmiverse/_pmiregistry/config/pmiverse.conf.
  • --suite N selects the suite used for unresolved defaults.
  • --db NAME sets the effective PostgreSQL target database.
  • --source-file FILE selects exactly one non-symlink ZIP.
  • --source DIR selects the newest readable non-symlink ZIP in a directory.
  • --dest DIR sets the extraction workspace root.
  • --filestore DIR sets the physical filestore root.
  • --neutralize restores and then applies SQL and ORM neutralization.
  • --only-neutralize mutates only the existing database and requires no backup.
  • --dry-run prints resolved values and exits before lock or target access.

--source and --source-file are mutually exclusive. CLI values take precedence over legacy target variables, registry values, derived suite paths, and built-in defaults.

Backup contract

The selected ZIP must contain exactly one supported database dump:

  • one non-empty dump.sql or other *.sql file; or
  • one valid custom-format *.dump or *.backup file.

An optional filestore may use one of the supported database/filestore layouts. Dump-only archives publish the database and retain the existing live filestore. Absolute entries, traversal components, backslashes, control characters, ZIP symlinks, extracted symlinks, ambiguous dumps, and ambiguous filestores are rejected.

Resource locking

Restore uses two persistent nonblocking advisory resource locks:

  • PostgreSQL lock: /srv/pmiverse/.pmis-restore-locks/.pmis-restore-postgresql-<sha256>.lock, hashing postgresql-local-default:<effective-database-name>.
  • Filestore lock: <physical-filestore-root>/.pmis-restore-filestore-<sha256>.lock, hashing filestore:<canonical-live-filestore-path>.

PostgreSQL is always acquired before filestore. Failure to acquire or verify a lock releases every acquired descriptor before target inspection or mutation. The locks remain held through restoration, publication, post-restore work, neutralization, rollback, and rollback-artifact cleanup. Lock files persist; closing their descriptors releases the advisory locks.

Invocations contend if either the effective database or canonical live filestore is shared. Suite values, aliases, source archives, and workspace paths do not change resource identity. Invocations with different databases and different live filestores may run concurrently. --only-neutralize acquires only the PostgreSQL lock and therefore contends with a normal restore of the same database.

Every restore-capable account must use the same shared PostgreSQL lock root. The script fails closed if that root is unavailable or unsafe. The identity represents the process's local/default PostgreSQL namespace; separate hosts or deliberately different lock roots are not coordinated.

Publication and rollback

The script validates and extracts the source in a unique workspace, restores into a unique temporary database, and stages any incoming filestore before publishing either resource. An existing database and filestore are renamed to unique rollback artifacts and retained until post-restore work and requested neutralization succeed.

On failure or signal, the script reconciles observed database and filesystem state and attempts coordinated rollback. Ambiguous or incomplete rollback preserves uniquely named artifacts and prints recovery guidance instead of guessing. PostgreSQL and filestore publication is coordinated rollback, not a single cross-system atomic transaction.

For the full resolution rules, archive layouts, neutralization behavior, and troubleshooting guidance, see /srv/pmiverse/_pmiconfig/docs/scripts/restore_database.md.