Create an Odoo database
create_database.py creates a new Odoo 18 Community database, configures the
built-in administrator, and installs selected modules without demo data. It
always includes base and web. Dependencies and auto-installed modules follow
Odoo's normal installation rules. Final business setup remains in the Odoo UI.
Prerequisites
Run with the intended Odoo virtualenv as the Odoo service account. Its PostgreSQL
role needs CREATEDB and its filesystem account needs access to the configured
data directory. The Odoo configuration supplies the PostgreSQL connection,
addons_path, and data_dir; this command does not use the shared database alias
registry. Defaults target _pmisuite18; override --config and --odoo-root for
another Odoo 18 instance. Dependencies must already be installed.
Keep the new database inaccessible to all Odoo services and other writers until creation succeeds, by stopping the relevant service or excluding the target through its database selection. Initialization has intermediate commits and temporarily uses Odoo's initial accounts. This command starts no HTTP server or cron workers, but selected addons can execute installation hooks with external effects. Review and authorize the module selection before execution.
Preview and create
Only the database name is required. With the intended Odoo virtualenv activated:
/srv/pmiverse/_pmiconfig/scripts/create/create_database.py example_new
This uses the built-in administrator (base.user_admin, normally user ID 2)
with login admin, installs the module list from the shared config, and generates
its password in /srv/pmiverse/_pmiprivate/example_new_init_pass. Supply
--admin-login only to override the login. Existing credential files are still
refused unless explicitly selected as input with --admin-password-file.
Preview needs only Python's standard library. It reads the shared module defaults
when --modules is omitted, but does not load Odoo, read the Odoo configuration
or password file, generate/save a password, contact PostgreSQL, or check module
availability. It shows the default password output path when no input file is given:
/srv/pmiverse/_pmisuite18/venv/bin/python \
/srv/pmiverse/_pmiconfig/scripts/create/create_database.py example_new \
--admin-login admin@example.invalid \
--company-name 'Example Company' --country SI \
--modules contacts,sale_management --dry-run
When --modules is omitted, the command reads modules from [create_database]
in ../../config/create_database.conf,
relative to this checkout regardless of the working directory. The initial list
is base,web; edit it to set the shared default modules. For example:
[create_database]
modules = base,web,contacts,sale_management
An explicit --modules contacts replaces the configured list, while
--modules '' selects only the mandatory base and web. Both sources use the
same validation and deduplication. Missing or malformed defaults stop the command
before Odoo loads unless --modules explicitly overrides them. --help does not
read defaults. The separate --config option still selects the Odoo runtime
configuration; it does not select this shared defaults file.
Remove --dry-run to create the database. Without --admin-password-file, the
command generates a cryptographically random password (32 random bytes encoded
as URL-safe text) and saves it to
/srv/pmiverse/_pmiprivate/<database>_init_pass, for example
/srv/pmiverse/_pmiprivate/example_new_init_pass. The filename contains the
literal suffix _init_pass, not the password. There is no interactive prompt.
The directory is created with mode 0700 if absent, and the file with mode
0600. An existing directory must be owned by the executing service account
and have no group/other permissions; the script does not change its permissions.
The account needs permission to create this directory, or an administrator must
prepare it separately. Symlink directories and existing output files (including
symlinks) are refused. Password persistence completes before database creation;
failure to save it stops creation. Only the path is printed, never the password.
To supply your own password instead, use
--admin-password-file /secure/path/admin-password: an owner-only regular UTF-8
file owned by the executing account (typically mode 0600). Symlinks are refused;
one trailing newline is allowed. This reads the supplied file and creates no
default password file. Passwords are never command-line arguments.
Retrieve the saved password as its owning account and hand it to the end user
through a secure channel. Manage or remove the file separately after handoff.
Generated files are retained on subsequent provisioning failures and may not
correspond to a usable account in an incomplete database. Inspect them before
retrying; a retry never overwrites them. To intentionally reuse a saved password
after resolving the database failure, pass its path with --admin-password-file.
--admin-login defaults to admin; --admin-name defaults to Administrator.
An email-shaped login also sets the
administrator's email. This updates base.user_admin through the ORM, preserving
its normal Odoo permissions and password hashing. It does not change Odoo's
database-manager master password (admin_passwd).
--company-name is optional. --country sets the company's country and default
currency before installing the selected modules, which matters for fiscal
localization. If omitted, Odoo's initial company settings remain. The initial
language is US English; additional languages and user preferences can be set in
the UI. No jurisdiction, tax configuration, outbound mail, or payment provider
is inferred.
Handoff and failure handling
Success means the requested modules are installed and the active administrator
has Settings access. Ensure the runtime service uses the same checkout, addon
paths, database connection, and data directory, and permits the new name through
db_name/dbfilter. Start or enable the service, then open
/web/login?db=example_new on its normal URL. Complete company/legal details,
localization and taxes, users/access, application settings, and integrations.
Review the initial currency and fiscal localization before recording transactions.
Existing databases or filestore paths, including dangling symlinks, are refused.
There is no overwrite, resume, drop, or automatic rollback mode. A failure exits
nonzero and retains any partially created database and filestore for inspection;
keep them offline. A second invocation refuses the retained target. Clean it up
only after inspection and separate authorization, or choose a fresh name.
Creation uses Odoo's PostgreSQL creation routine and template0; a concurrent
database creation is rejected by PostgreSQL and is never adopted.
--help lists the full interface. Shared Bash completion includes options and
file paths but does not suggest existing database names for the new target.
Editing this repository installs no shortcut or service and creates no database.
Development validation
The implementation guide explains the shared helpers, configuration precedence, initialization phases, failure boundaries, and a focused test command. This module also supplies password I/O and offline runtime loading to administrator recovery; changes to those helpers must preserve both workflows.
tests/test_create_database.py uses synthetic Odoo/ORM doubles and private
temporary files. It exercises creation order, administrator setup, module-state
verification, collision refusal, password handling, and retained partial failure.
tests/test_script_cli.py -k create_database checks help and completion in its
isolated sandbox. These checks do not replace an explicitly authorized disposable
Odoo/PostgreSQL integration run.