PostgreSQL state and drift¶
AI-translated from Russian.
From odpm 4.3 onward, PostgreSQL cluster configuration (compose, odoo.conf, data directory, application role) is tracked via .odpm/database/last_run.json. This is separate from Odoo database operations (-d, --db-backup, --db-restore).
Why it exists¶
Database “truth” used to be spread across .env, docker-compose.yml, odoo.conf, the bind-mounted data directory, and the live PostgreSQL cluster. Renaming a service, changing ports, or reusing an old data dir often failed deep inside the container.
odpm now:
- Collects configuration fingerprints.
- Compares them to the last snapshot (
last_run.json). - Surfaces drift in
odpm planand beforecompose up. - Adopts legacy projects without a snapshot on first startup.
.odpm/database/last_run.json¶
| Property | Value |
|---|---|
| Generated by | odpm automatically |
| Git | do not commit (like runtime/config.json) |
| Container mount | .odpm/database → /run/odpm/database (read-write for checker) |
schema_version |
1 |
The snapshot includes:
compose— PostgreSQL service name, image tag, absolute data path, host port;odoo_conf—db_host,db_port,db_user;cluster— non-empty data dir, PostgreSQL major (PG_VERSION), application role and presence.
When the baseline is updated¶
| Event | Writer |
|---|---|
First run without last_run.json |
Adoption — before compose up (role + baseline) |
| Successful credential check in checker | Checker — after TCP and psql as db_user |
Adoption runs once. While the file exists, only drift vs the saved snapshot is reported.
Legacy project adoption¶
If last_run.json is missing (typical with an inherited PostgreSQL data directory), odpm before the full stack:
- Starts PostgreSQL if needed.
- Runs
ensure_app_role— creates or updates the application role (defaultodoo), including single-user bootstrap when no admin login role exists. - Writes the current configuration as baseline.
Adoption does not:
- reassign PostgreSQL owners of existing Odoo databases;
- drop or restore Odoo databases;
- auto-wipe the data directory on PostgreSQL major changes.
See also legacy-project.md.
Drift kinds and severity¶
| KIND | Severity | Behaviour |
|---|---|---|
first_run |
info | No snapshot; baseline adopted on startup |
service_name, db_host_mismatch, host_port |
low | Warning in plan |
odpm_scenario, data_dir_empty_changed |
medium | Interactive prompt or --accept-database-drift |
data_path, postgres_major, app_role_missing |
high | Prompt; blocks container start without resolution |
Prepare step database.drift in odpm plan reflects mismatches before compose is written.
Interactive resolution¶
With a TTY, odpm prompts (accept new data path, create role, show wipe instructions, etc.). Without TTY — error listing KINDs; use --accept-database-drift=KIND (repeatable).
Accepted KIND values:
data_pathpostgres_majorapp_role_missingodpm_scenariodata_dir_empty_changed
See non-interactive runs.
database subcommand¶
odpm database status
odpm database status --format json
odpm database ensure-role
| Command | Purpose |
|---|---|
database status |
Fingerprints, drift, live probes (postgres container, readiness, role) |
database status --format json |
Same as JSON for scripts |
database ensure-role |
Create or update the application role in a running PostgreSQL |
Commands run prepare (without compose up) when needed to read configuration.
.env and odoo.conf¶
POSTGRES_SERVICE_NAME in .env sets the postgres compose service name and the expected db_host in odoo.conf when ODPM_COMPOSE_PREFIX is unset.
ODPM_COMPOSE_PREFIX sets physical built-in service names ({prefix}db, {prefix}odoo), the data volume, and the Docker Compose project name. The last_run.json snapshot stores compose.service_name (postgres), compose.compose_project_name, and compose.odoo_service_name. When the prefix or POSTGRES_SERVICE_NAME changes relative to the snapshot:
- prepare step
template.odoo_confregenerates the config ondb_hostmismatch; - drift
service_name,compose_project_name, ordb_host_mismatchappears in plan.
See .env variables, odoo.conf.
Odoo databases: backup, restore, drop¶
--db-drop, --db-restore, --db-backup operate on Odoo databases inside the cluster, not on last_run.json.
On a legacy cluster a database may exist but be owned by another PostgreSQL user. Standard Odoo exp_drop then skips silently; odpm falls back to direct DROP DATABASE and fails clearly if the database remains.
Example:
odpm -d test_db --db-drop --db-restore my_backup.zip -i -u --set-admin-pass
Troubleshooting¶
odpm database status
odpm plan --skip-start
docker compose logs db-dev # postgres service name from .env (or acme-db when ODPM_COMPOSE_PREFIX=acme)
After changing POSTGRES_SERVICE_NAME or ODPM_COMPOSE_PREFIX, remove orphan containers (with the same project scope odpm uses):
docker compose down --remove-orphans
# odpm passes -p automatically; manually: docker compose -p acme down --remove-orphans
What odpm does not automate¶
- Data migration on PostgreSQL major upgrades (backup + wipe per prompt instructions).
ALTER DATABASE … OWNER TOfor old Odoo DBs — use--db-dropor manualpsql.- Sharing
last_run.jsonacross machines — snapshot is local per environment directory.