Skip to content

1.9 Step | CloneOdooRepo

Omisen edited this page Aug 15, 2026 · 3 revisions

Clones the Odoo sources into <install_dir>/odoo, reversibly. It lives in src/steps/clone_odoo_repo.rs. The first of the three sub-steps the Bash monolith install_odoo is broken into (clone → venv → pip). Every operation runs as the odoo user (least privilege), not as root.


Splitting a monolithic step

In Bash, install_odoo is one block. Here it becomes three steps with distinct undos:

Sub-step Undo
1.9 CloneOdooRepo rm -rf of the sources (+ the container if empty)
1.10 CreateVirtualenv rm -rf sandbox
1.11 InstallPythonRequirements none (absorbed by 1.10)

Decomposing a monolith into sub-steps with clear undo boundaries — and discovering that one has no undo of its own precisely because another covers it — is a pattern that recurs (nginx, control script).


Life cycle

Phase Behaviour
snapshot detects the state of the sources (detect_odoo_source): absent / git on the right branch / tarball (odoo-bin without .git) / invalid directory
run creates the directory structure as odoo — claiming CreatedByUs there, before touching the network — then clones (with retries and a fallback). Preexisting → skip. dry_run → log
undo CreatedByUs only: rm -rf of the repo and repos/, plus removal of the install_dir container if empty

Snapshot: four states

  • git on the expected branchPreexisting (git-existing), skip.
  • tarball (odoo-bin, no .git) → Preexisting (tarball-existing), skip.
  • a different brancherror: it may hold work in progress. It is not silently regenerated (“remove it by hand … if you want to re-clone”).
  • invalid directory (neither .git nor odoo-bin, under our install_dir) → warning + regeneration.
  • absentCreatedByUs after the run.

Download robustness: retries + fallback

git clone (N retries, attempt*2s backoff, artifacts cleaned between attempts)
   └─ failed after N attempts → tarball fallback (codeload.github.com)
        └─ the tarball failed too → error

Git arguments faithful to Bash: -c http.version=HTTP/1.1 -c core.compression=0 clone … --branch <ver> --single-branch --no-tags --depth <N>. Default depth 5 (GIT_DEPTH), default retries 3 (GIT_CLONE_RETRIES). The source mode (git or tarball) is recorded in the snapshot for the post-mortem.

Both the clone and the tarball are network operations, so they carry a timeout (ODOO_NETWORK_TIMEOUT_SECS, 300s by default, 0 disables it) enforced inside the SystemOps boundary. A timeout consumes one attempt. Local long operations do not get one: cutting them short would do more damage than waiting.

The timeout kills the worker, not the shell in front of it. These commands run through sudo, so the process the installer spawns is sudo and the one doing the work is its child. Killing only the child left git alive, holding the pipes open, and the timeout error — already decided — was never reported: an installation found in the field stuck for seven minutes with not one line of log, indistinguishable from having no timeout at all. Network commands now run in a process group of their own and the expiry kills the group. One consequence, deliberate: a Ctrl-C does not reach them either, so they are carried to completion like any other step in progress, and the log says so.

The temporary tarball is downloaded inside the sources directory, not into /tmp. It is created by us and then handed to the odoo user — because tar reads it as odoo — and O_CREAT on somebody else's file inside a sticky, world-writable directory is refused by fs.protected_regular, root included. So the fallback could never succeed, and nobody had noticed: a fallback only runs when the clone has already failed, and in CI it never does. The sources directory belongs to the user that reads it, is not sticky, and is inside the perimeter the undo removes with rm -rf.


Perimeter: install_dir yes, /opt/odoo no

This step lives inside <install_dir> (/opt/odoo/odoo18, say), one level below /opt/odoo. Here rm -rf is legitimate: it is our sources directory, created entirely by us. /opt/odoo remains 1.1 PrepareOptRoot's business.

The container install_dir is removed only if empty, after the venv and config undos have run first (reverse order) — the same pattern as /opt/odoo. If it holds anything else (including pre-existing material), it is left intact.


Design notes

  • git_clone is a single attempt inside the SystemOps boundary; the retry, backoff and fallback are orchestrated by the step (testable with a mock that fails N times).
  • Best-effort undo on every removal.
  • Tests: absent (clone + undo rm -rf), git-existing (no-op), branch mismatch (error), retries (3 attempts + 2 cleanups), tarball fallback (fires; if it fails too → error).

Clone this wiki locally