Skip to content

1.12 Step | GenerateConfig

Omisen edited this page Aug 14, 2026 · 4 revisions

Generates odoo<N>.conf from the template, reversibly. It lives in src/steps/generate_config.rs. A port of generate_config from lib/config.sh. The template is embedded in the binary (include_str!): no dependency on external files at runtime.

Two novelties compared with the earlier steps: the first undo that restores instead of removing, and the care taken so that the master password is never world-readable.


The first “restoring” undo

Until now, the undo of a Preexisting step was a no-op (not ours, we do not touch it). Here it is different: run overwrites a pre-existing odoo.conf, so the undo has to restore the original.

Phase Behaviour
snapshot does the file already exist? → Preexisting/Untracked
run if Preexisting, back it up to odoo<N>.conf.bak.<timestamp> before overwriting (the path is saved in the snapshot); then render and write
undo CreatedByUsrm -f (we created it); Preexisting → restore the backup over the destination file

In the Preexisting case the undo does NOT leave the overwritten file and does NOT delete it: it puts exactly the customer's original back in place, from the backup. It is the first undo that restores rather than destroys.

A test proves it with a round trip on a real disk: after the undo, the file is byte-for-byte the original.


The master password is never world-readable

The file contains admin_passwd (and db_password). It must never pass through a file readable by other users, not for an instant. The pattern (faithful to Bash, confirmed in analysis):

1. render → write to a PRIVATE temp (mode 0600, owned by root)   ← password never readable by others
2. move   → move the temp to its destination (same filesystem, atomic)
3. chown odoo:odoo
4. chmod 0640                                                     ← readable only by odoo and root

The plaintext password enters only render_config (the Secret's single expose()) and from there the file's contents; it is never logged nor printed in the summary. The mock in the tests records the write as “private” without capturing its contents.


Rendering + normalisation

  • ${VAR} placeholders are substituted with the Context's values (version, port, db_user/name, addons_path, data_dir, limits, proxy_mode, logfile, …). The data_dir is no longer a plain template value: the formula lives in generate_config::data_dir and the same function is used by 1.12b SetupDataDir to create that directory reversibly. Two identical format!s in two files would be the premise of a rollback cleaning the wrong directory.
  • Empty directives → False: every key = left without a value becomes key = False (Odoo rejects empty values). So empty db_host, db_port, db_password and logfile end up as False rather than dangling.
  • Validation after rendering: the [options] section is present, addons_path and http_port have values, and no ${...} placeholder is left. Otherwise → error, and no incoherent file.

render_config, normalize_empty_directives and validate_rendered are pure functions, tested separately.


Design notes

  • The temp file is written in the same directory as the destination, so move is an atomic rename on one filesystem.
  • Best-effort undo: if the backup is missing, it logs a warning and carries on without destroying anything.
  • Final permissions 0640 odoo:odoo.
  • Tests: CreatedByUs (generates 640, undo removes), Preexisting (the undo restores the backup), rendering (empty→False, no leftovers), validation (leftover placeholder or missing section → error).

Clone this wiki locally