2026-09-16 00:41:43 -04:00
|
|
|
# © 2026 TechnoLibre (http://www.technolibre.ca)
|
|
|
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
|
#
|
|
|
|
|
# Dépendances système d'ERPLibre, pour NixOS.
|
|
|
|
|
#
|
|
|
|
|
# Le pendant DÉCLARATIF des quatre install_<distro>_dependency.sh. Ceux-là
|
|
|
|
|
# posent des paquets par apt, dnf, pacman ou zypper ; ici rien ne s'installe
|
|
|
|
|
# par une commande — ce qui doit rester se déclare, et ce fichier est cette
|
|
|
|
|
# déclaration. Un « nixos-rebuild switch » l'applique ; ce qui aurait été posé
|
|
|
|
|
# à la main disparaîtrait à la reconstruction suivante.
|
|
|
|
|
#
|
|
|
|
|
# Déposé en /etc/nixos/erplibre.nix par script/install/install_nixos_dependency.sh,
|
|
|
|
|
# qui l'ajoute aussi aux « imports » de la configuration de la machine.
|
|
|
|
|
#
|
|
|
|
|
# DEUX options portent tout le reste, et sans elles rien de ce dépôt ne
|
|
|
|
|
# fonctionne sur NixOS :
|
|
|
|
|
#
|
|
|
|
|
# services.envfs.enable — NixOS ne peuple pas /bin ni /usr/bin. Or le
|
|
|
|
|
# Makefile force « SHELL := /bin/bash » (toute cible make échouerait avant
|
|
|
|
|
# sa première ligne) et lib_python_provider.sh ne cherche l'interpréteur du
|
|
|
|
|
# système qu'en /usr/bin/pythonX.Y, jamais dans le PATH. envfs fabrique ces
|
|
|
|
|
# deux répertoires à la volée depuis le PATH : les scripts du dépôt marchent
|
|
|
|
|
# alors sans être réécrits.
|
|
|
|
|
#
|
|
|
|
|
# programs.nix-ld.enable — les binaires téléchargés (roues manylinux de pip,
|
|
|
|
|
# CPython précompilé de mise, archives amont) sont liés à
|
|
|
|
|
# /lib64/ld-linux-x86-64.so.2, qui n'existe pas ici. nix-ld le fournit et
|
|
|
|
|
# leur donne les bibliothèques listées plus bas.
|
|
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
# ── Ce que /bin, /usr/bin et l'éditeur de liens doivent porter ──────────
|
|
|
|
|
services.envfs.enable = true;
|
|
|
|
|
|
|
|
|
|
programs.nix-ld.enable = true;
|
|
|
|
|
# Les bibliothèques que réclament les roues manylinux d'Odoo : psycopg2 veut
|
|
|
|
|
# libpq, lxml veut libxml2/libxslt, cryptography veut openssl, pillow veut
|
|
|
|
|
# zlib et freetype. Une roue qui n'en trouve pas une échoue à l'IMPORT, pas
|
|
|
|
|
# à l'installation — donc bien après, et sans rapport apparent.
|
|
|
|
|
programs.nix-ld.libraries = with pkgs; [
|
|
|
|
|
stdenv.cc.cc.lib
|
|
|
|
|
zlib
|
|
|
|
|
openssl
|
|
|
|
|
libxml2
|
|
|
|
|
libxslt
|
|
|
|
|
libffi
|
|
|
|
|
libpq
|
|
|
|
|
freetype
|
|
|
|
|
fontconfig
|
|
|
|
|
libjpeg
|
|
|
|
|
glib
|
|
|
|
|
expat
|
|
|
|
|
bzip2
|
|
|
|
|
xz
|
|
|
|
|
ncurses
|
|
|
|
|
readline
|
|
|
|
|
sqlite
|
|
|
|
|
util-linux
|
|
|
|
|
openldap
|
|
|
|
|
cyrus_sasl
|
|
|
|
|
cups
|
|
|
|
|
libmysqlclient
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
# ── La base de données ───────────────────────────────────────────────────
|
|
|
|
|
# Le compte de service est SUPERUSER comme sur les autres distributions :
|
|
|
|
|
# ERPLibre crée et détruit des bases (migrations, copies neutralisées), ce
|
|
|
|
|
# qu'un rôle ordinaire ne peut pas faire.
|
|
|
|
|
services.postgresql = {
|
|
|
|
|
enable = true;
|
|
|
|
|
# PostGIS comme les quatre autres scripts de distribution le posent. Ici
|
|
|
|
|
# c'est une extension DU SERVEUR, pas un paquet du système : déclarée
|
|
|
|
|
# ailleurs, elle ne serait pas chargeable par « CREATE EXTENSION ».
|
|
|
|
|
extensions = ps: with ps; [ postgis ];
|
|
|
|
|
ensureUsers = [
|
|
|
|
|
{
|
|
|
|
|
name = "@EL_USER@";
|
|
|
|
|
ensureClauses.superuser = true;
|
|
|
|
|
ensureClauses.createdb = true;
|
|
|
|
|
ensureClauses.login = true;
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
# ── Les outils ───────────────────────────────────────────────────────────
|
|
|
|
|
# python3.12 : la version qu'attend ERPLibre (.python-odoo-version). envfs
|
|
|
|
|
# la rend visible en /usr/bin/python3.12, où lib_python_provider.sh la
|
|
|
|
|
# cherche — ni mise ni pyenv n'ont alors à télécharger quoi que ce soit.
|
|
|
|
|
#
|
|
|
|
|
# Les sorties « .dev » portent les en-têtes : sans elles, une roue absente
|
|
|
|
|
# du dépôt amont devrait se compiler et ne trouverait ni libpq-fe.h ni
|
|
|
|
|
# openssl/ssl.h. Elles ne servent qu'à ce cas, et ne coûtent que du disque.
|
|
|
|
|
environment.systemPackages = with pkgs; [
|
|
|
|
|
python312
|
|
|
|
|
python312Packages.pip
|
|
|
|
|
python312Packages.virtualenv
|
|
|
|
|
uv
|
|
|
|
|
nodejs_22
|
|
|
|
|
postgresql
|
|
|
|
|
postgresql.dev
|
|
|
|
|
git
|
|
|
|
|
gnumake
|
|
|
|
|
gcc
|
|
|
|
|
pkg-config
|
|
|
|
|
openssl
|
|
|
|
|
openssl.dev
|
|
|
|
|
zlib
|
|
|
|
|
zlib.dev
|
|
|
|
|
libxml2
|
|
|
|
|
libxml2.dev
|
|
|
|
|
libxslt
|
|
|
|
|
libxslt.dev
|
|
|
|
|
libffi
|
|
|
|
|
libffi.dev
|
|
|
|
|
# python-ldap n'a PAS de roue amont : il compile, et réclame lber.h
|
|
|
|
|
# (openldap) plus sasl.h. Sans ces sorties « .dev », « poetry install »
|
|
|
|
|
# s'arrête sur « fatal error: lber.h: No such file or directory ».
|
|
|
|
|
openldap
|
|
|
|
|
openldap.dev
|
|
|
|
|
cyrus_sasl
|
|
|
|
|
cyrus_sasl.dev
|
|
|
|
|
# « pg_config » est une dérivation à PART dans nixpkgs : il n'est ni dans
|
|
|
|
|
# postgresql ni dans sa sortie « .dev », et psycopg2 s'arrête sur
|
|
|
|
|
# « Error: pg_config executable not found ».
|
|
|
|
|
postgresql.pg_config
|
|
|
|
|
# pycups veut cups/http.h, mysqlclient veut mysql.h. Les quatre autres
|
|
|
|
|
# scripts posent les mêmes (libcups2-dev, cups-devel,
|
|
|
|
|
# mariadb-connector-c-devel, mariadb-libs).
|
|
|
|
|
cups
|
|
|
|
|
# « cups.lib » porte libcups.so, que « out » n'a pas : sans elle la
|
|
|
|
|
# compilation de pycups PASSE et l'édition de liens échoue sur « -lcups ».
|
|
|
|
|
cups.lib
|
|
|
|
|
cups.dev
|
|
|
|
|
libmysqlclient
|
|
|
|
|
libmysqlclient.dev
|
|
|
|
|
# « less » est le PAGINATEUR ; « nodePackages.less » est lessc, le
|
|
|
|
|
# compilateur LESS des assets Odoo. Les quatre autres scripts les posent
|
|
|
|
|
# tous deux, l'un par le gestionnaire du système et l'autre par « npm
|
|
|
|
|
# install -g » — geste impossible ici, le préfixe npm étant le store, en
|
|
|
|
|
# lecture seule. nixpkgs les porte : ils se déclarent comme le reste.
|
|
|
|
|
less
|
|
|
|
|
nodePackages.less
|
|
|
|
|
nodePackages.rtlcss
|
|
|
|
|
sshpass
|
|
|
|
|
curl
|
|
|
|
|
wget
|
|
|
|
|
unzip
|
|
|
|
|
wkhtmltopdf
|
[FIX] nixos : pare-feu ouvert, et ce qu'on appelle par son nom déclaré
NixOS active un pare-feu par défaut ; aucune des quatre autres images
cloud n'en active. Le service écoutait bien et répondait en local, mais
l'hôte ne recevait RIEN — pas un refus, un silence jusqu'au délai — et le
suivi déclarait Odoo absent sur une machine où il tournait. Mesuré : 000
après 12 s, puis 303 en 9 ms.
Un système déclaratif n'a que ce qui est écrit : xmlsec1, sans lequel
Odoo refuse d'installer auth_saml ; parallel et shfmt, appelés par leur
nom nu ; growpart, dont l'absence faisait rendre 0 à un agrandissement qui
n'agrandissait rien ; et l'agent invité, qui venait de l'image.
--- EN ---
NixOS enables a firewall by default; none of the four other cloud images
does. The service did listen and answered locally, but the host received
NOTHING — not a refusal, silence until the timeout — and the monitor
declared Odoo absent on a machine where it was running. Measured: 000
after 12 s, then 303 in 9 ms.
A declarative system has only what is written: xmlsec1, without which Odoo
refuses to install auth_saml; parallel and shfmt, called by bare name;
growpart, whose absence made a disk grow return 0 while growing nothing;
and the guest agent, which came from the image.
Assisted-by: Claude Opus 5
2026-09-16 00:43:40 -04:00
|
|
|
# « xmlsec » pose bin/xmlsec1, que les CINQ autres plateformes posent
|
|
|
|
|
# aussi. Le manifeste d'auth_saml (OCA server-auth, présent dans
|
|
|
|
|
# l'addons_path) déclare « bin: ["xmlsec1"] », et Odoo REFUSE d'installer
|
|
|
|
|
# ou de mettre à niveau le module tant que le binaire n'est pas dans le
|
|
|
|
|
# PATH : « Unable to find 'xmlsec1' in path », en boîte de dialogue.
|
|
|
|
|
xmlsec
|
|
|
|
|
# « parallel » et « shfmt » sont appelés par leur NOM NU, l'un par
|
|
|
|
|
# script/database/db_drop_all.py, l'autre par script/maintenance/
|
|
|
|
|
# format_bash.sh. Sans parallel, « make db_drop_all » annonce des bases
|
|
|
|
|
# détruites qui ne l'ont pas été — une opération destructrice qui rend un
|
|
|
|
|
# succès qu'elle n'a pas obtenu.
|
|
|
|
|
parallel
|
|
|
|
|
shfmt
|
|
|
|
|
# « cloud-utils » porte growpart, qu'aucune autre voie ne fournit ici.
|
|
|
|
|
# L'agrandissement du disque s'écrit « sudo growpart … || true » : sans le
|
|
|
|
|
# binaire, il rend 0 sans rien agrandir, et la VM garde la taille de son
|
|
|
|
|
# image pendant que le déploiement annonce la taille demandée.
|
|
|
|
|
cloud-utils
|
2026-09-16 00:41:43 -04:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
# Le profil du système ne porte PAS « /include » : la liste par défaut de
|
|
|
|
|
# ce qui y est lié ne contient ni les en-têtes ni les fichiers pkg-config.
|
|
|
|
|
# Sans cette ligne, déclarer une sortie « .dev » ne met rien nulle part, et
|
|
|
|
|
# « fatal error: lber.h: No such file or directory » reste entier.
|
|
|
|
|
environment.pathsToLink = [ "/include" "/lib/pkgconfig" ];
|
|
|
|
|
|
[FIX] install nixos : l'amorçage, les en-têtes, les manuels écartés
L'amorçage d'ERPLibre n'atteignait pas NixOS : le Makefile force
« SHELL := /bin/bash », que l'image ne porte pas, et le fournisseur de
Python ne cherche l'interpréteur du système qu'en /usr/bin/pythonX.Y.
Les deux répondent une fois envfs déclaré.
Ce qui n'a pas de roue amont se compile et réclame ses en-têtes : ils sont
liés au profil du système, leurs bibliothèques vont au chargeur, et
pg_config — dérivation à part dans nixpkgs — est nommé. La sortie « doc »
de CPython est écartée : sa construction est un Sphinx de 3 000 pages qui
domine le temps d'installation d'une VM de 4 Go.
--- EN ---
ERPLibre's bootstrap did not reach NixOS: the Makefile forces "SHELL :=
/bin/bash", which the image lacks, and the Python provider only looks for
the system interpreter at /usr/bin/pythonX.Y. Both answer once envfs is
declared.
What has no upstream wheel compiles and demands its headers: they are
linked into the system profile, their libraries reach the loader, and
pg_config — a separate derivation in nixpkgs — is named. CPython's "doc"
output is left out: building it is a 3000-page Sphinx run that dominates
install time on a 4 GB VM.
Assisted-by: Claude Opus 5
2026-09-16 00:42:13 -04:00
|
|
|
# Les manuels HTML, et EUX SEULS, sont écartés.
|
|
|
|
|
#
|
|
|
|
|
# NixOS installe la sortie « doc » de CHAQUE paquet du système
|
|
|
|
|
# (environment.extraOutputsToInstall vaut « man info doc »). Celle de
|
|
|
|
|
# CPython n'est pas dans le cache binaire : le premier « nixos-rebuild »
|
|
|
|
|
# la BÂTIT — un Sphinx qui lit puis écrit 3 000 pages. Sur une VM de 4 Go
|
|
|
|
|
# et 4 cœurs, cela domine le temps d'installation ; sur une de 2 Go, la
|
|
|
|
|
# machine cesse de répondre pendant la construction.
|
|
|
|
|
#
|
|
|
|
|
# « documentation.doc » et non « documentation » : les pages de manuel et
|
|
|
|
|
# info restent, elles se lisent depuis un terminal et ne coûtent rien.
|
|
|
|
|
documentation.doc.enable = false;
|
|
|
|
|
|
2026-09-16 00:41:43 -04:00
|
|
|
# « sessionVariables » et NON « variables » : la seconde n'écrit que dans
|
|
|
|
|
# /etc/set-environment, que seul un shell de CONNEXION lit. Or le
|
|
|
|
|
# déploiement installe par « ssh hôte 'commande' », qui n'en est pas un —
|
|
|
|
|
# la variable y serait vide. sessionVariables passe par pam_env, que toute
|
|
|
|
|
# session traverse, y compris celle-là.
|
|
|
|
|
environment.sessionVariables = {
|
|
|
|
|
CPATH = "/run/current-system/sw/include";
|
|
|
|
|
LIBRARY_PATH = "/run/current-system/sw/lib";
|
|
|
|
|
PKG_CONFIG_PATH = "/run/current-system/sw/lib/pkgconfig";
|
[ADD] cache qemu : NixOS apprend l'autorité, et le hors ligne s'ouvre
NixOS était SOUSTRAIT du cache faute d'ancre de confiance par fichier, ce
qui lui fermait le hors ligne : le magasin est alors la seule source, et
l'exception ne laisse rien. Une déclaration arriverait trop tard, la
première reconstruction étant le premier téléchargement.
L'autorité est donc POINTÉE, consommateur par consommateur, et
l'environnement se perd à trois frontières : nix-daemon, activé par
socket, qu'un fragment sous /run/systemd/system atteint ; sudo, que
« env_keep » traverse — le nix de root parle droit au magasin local et
télécharge lui-même ; et la session ssh, ouverte une seconde avant que
cloud-init n'écrive le faisceau. Vérifié : installation complète, 0 refus.
--- EN ---
NixOS was EXEMPTED from the cache for want of a per-file trust anchor,
which closed offline deployment to it: the store is then the only source,
and an exemption leaves nothing. A declaration would come too late, the
first rebuild being the first download.
The authority is therefore POINTED AT, consumer by consumer, and the
environment is lost at three boundaries: nix-daemon, socket-activated,
reached by a drop-in under /run/systemd/system; sudo, crossed by
« env_keep » — root's nix talks straight to the local store and downloads
itself; and the ssh session, opened one second before cloud-init writes
the bundle. Checked: a complete install, 0 refusals.
Assisted-by: Claude Opus 5
2026-09-16 21:33:10 -04:00
|
|
|
} // lib.optionalAttrs ("@EL_CA_BUNDLE@" != "") {
|
|
|
|
|
# L'autorité du cache de téléchargement, pour TOUTE session d'après
|
|
|
|
|
# l'installation — un « git pull » échouerait sinon sur un certificat
|
|
|
|
|
# qu'il ne reconnaît pas, comme le clone avant elle.
|
|
|
|
|
#
|
|
|
|
|
# La commande d'installation porte ces mêmes variables elle-même : elle
|
|
|
|
|
# tourne AVANT la première reconstruction, et aucun chemin PAM n'est
|
|
|
|
|
# inscriptible d'ici là. Les deux moitiés se relaient.
|
|
|
|
|
#
|
|
|
|
|
# « optionalAttrs » et non une valeur de repli : sur une machine sans
|
|
|
|
|
# cache le faisceau n'existe pas, et y pointer SSL_CERT_FILE couperait
|
|
|
|
|
# TLS partout.
|
|
|
|
|
SSL_CERT_FILE = "@EL_CA_BUNDLE@";
|
|
|
|
|
CURL_CA_BUNDLE = "@EL_CA_BUNDLE@";
|
|
|
|
|
GIT_SSL_CAINFO = "@EL_CA_BUNDLE@";
|
|
|
|
|
REQUESTS_CA_BUNDLE = "@EL_CA_BUNDLE@";
|
|
|
|
|
NODE_EXTRA_CA_CERTS = "@EL_CA_BUNDLE@";
|
|
|
|
|
PIP_CERT = "@EL_CA_BUNDLE@";
|
2026-09-16 00:41:43 -04:00
|
|
|
};
|
[FIX] nixos : le service ERPLibre déclaré, démarré quand Odoo est là
Trois obstacles enchaînés, aucun visible sans une vraie machine. /etc est
généré depuis le store : le « tee » d'une unité y rend « Read-only file
system », et l'installation échouait à sa DERNIÈRE étape, après que le
clone, le venv et un démarrage d'Odoo avaient réussi. ExecStart=/bin/bash
rendait 203/EXEC, /bin étant un montage FUSE que systemd ne voit pas ; et
le PATH d'une unité n'a pas bash, que réclament les shebangs de run.sh.
Déclarée, l'unité est démarrée par la reconstruction — qui a lieu pendant
« make install_os », quand la source d'Odoo n'arrive qu'après : une
condition la fait sauter plutôt qu'échouer 21 fois de suite. Mesuré :
service actif, 8069 servi par lui, login en 303.
--- EN ---
Three chained obstacles, none visible without a real machine. /etc is
generated from the store: « tee » of a unit there returns « Read-only file
system », and the install failed at its LAST step, after the clone, the
venv and an Odoo start had all succeeded. ExecStart=/bin/bash returned
203/EXEC, /bin being a FUSE mount systemd does not see; and a unit's PATH
carries no bash, which run.sh's shebangs ask for.
Declared, the unit is started by the rebuild — which happens during
« make install_os », while Odoo's source lands later: a condition makes it
skip rather than fail 21 times over. Measured: service active, 8069 served
by it, login in 303.
Assisted-by: Claude Opus 5
2026-09-16 21:31:50 -04:00
|
|
|
|
[FIX] nixos : afficher le guide de connexion, appliquer la locale
Le déploiement écrit /etc/motd partout et compte sur pam_motd pour le
montrer — vrai des quatre images cloud, faux ici : sshd rend « printmotd
no » et le PAM n'en contient aucun. Le guide était écrit, complet, et
personne ne le lisait. Il gagne un bloc propre à NixOS, dont le piège
qu'il existe pour dire — /etc/nixos/erplibre.nix est réécrit par
« make install_os », et ce qu'on y ajoute disparaît sans un mot.
La locale demandée ne s'appliquait pas : cloud-init passe par locale-gen
et update-locale, absents ici. Mesuré — fr_CA demandé, en_US obtenu. Rien
n'est imposé à une NixOS qu'on avait déjà.
--- EN ---
Deployment writes /etc/motd everywhere and relies on pam_motd to show it —
true of the four cloud images, false here: sshd returns "printmotd no" and
the PAM stack holds none. The guide was written, complete, and nobody read
it. It gains a NixOS block, including the trap it exists to name —
/etc/nixos/erplibre.nix is rewritten by "make install_os", and what you
add there vanishes without a word.
The requested locale did not apply: cloud-init goes through locale-gen and
update-locale, absent here. Measured — fr_CA asked, en_US obtained.
Nothing is imposed on a NixOS one already had.
Assisted-by: Claude Opus 5
2026-09-16 00:44:00 -04:00
|
|
|
# Les réglages régionaux demandés au déploiement.
|
|
|
|
|
#
|
|
|
|
|
# Le FUSEAU marche déjà sans cela : cloud-init pose /etc/localtime, que
|
|
|
|
|
# NixOS laisse mutable tant que « time.timeZone » n'est pas déclaré.
|
|
|
|
|
# Mesuré sur une VM installée — le lien pointe bien la zone demandée. Le
|
|
|
|
|
# déclarer ne répare donc rien ; il fait passer la garantie du côté du
|
|
|
|
|
# module, comme pour l'agent invité.
|
|
|
|
|
#
|
|
|
|
|
# La LOCALE, elle, ne marchait pas : cloud-init l'applique par locale-gen
|
|
|
|
|
# et update-locale, qui n'existent pas ici, et la VM gardait le défaut de
|
|
|
|
|
# NixOS. Mesuré : « fr_CA.UTF-8 » demandé, « en_US.UTF-8 » obtenu.
|
|
|
|
|
#
|
|
|
|
|
# « mkIf » plutôt qu'une valeur de repli : sur une machine où rien n'a été
|
|
|
|
|
# demandé — une NixOS que l'on avait déjà, installée par « --hote » —
|
|
|
|
|
# l'option n'est PAS définie, et le réglage de son propriétaire reste.
|
|
|
|
|
# Écrire un défaut ici l'écraserait sans le dire.
|
|
|
|
|
#
|
|
|
|
|
# CE QUE CELA COÛTE, mesuré : une locale autre que celle du défaut change
|
|
|
|
|
# l'ensemble des locales prises en charge, donc la dérivation de
|
|
|
|
|
# glibc-locales, qui n'est alors pas dans le cache binaire et se BÂTIT. La
|
|
|
|
|
# première reconstruction est longue, et silencieuse — il vaut mieux le
|
|
|
|
|
# savoir que de la prendre pour un blocage.
|
|
|
|
|
i18n.defaultLocale = lib.mkIf ("@EL_LOCALE@" != "") "@EL_LOCALE@";
|
|
|
|
|
time.timeZone = lib.mkIf ("@EL_TZ@" != "") "@EL_TZ@";
|
|
|
|
|
|
|
|
|
|
# Le guide de connexion, AFFICHÉ.
|
|
|
|
|
#
|
|
|
|
|
# Le déploiement écrit /etc/motd dans toutes les distributions, et compte
|
|
|
|
|
# sur pam_motd pour le montrer — c'est vrai des quatre images cloud, où
|
|
|
|
|
# sshd est en « PrintMotd no » et où ajouter l'inverse afficherait le guide
|
|
|
|
|
# DEUX FOIS. Ici, ni l'un ni l'autre : mesuré sur une VM installée, sshd
|
|
|
|
|
# rend « printmotd no » et /etc/pam.d/sshd ne contient AUCUN pam_motd. Le
|
|
|
|
|
# fichier est donc écrit, complet, et personne ne le lit.
|
|
|
|
|
#
|
|
|
|
|
# sshd et non pam_motd : le double affichage qu'on redoute ailleurs ne peut
|
|
|
|
|
# pas se produire tant que le PAM d'ici n'en contient pas, et c'est le seul
|
|
|
|
|
# des deux qui ne demande rien de plus que cette ligne.
|
|
|
|
|
services.openssh.settings.PrintMotd = true;
|
|
|
|
|
|
[FIX] nixos : pare-feu ouvert, et ce qu'on appelle par son nom déclaré
NixOS active un pare-feu par défaut ; aucune des quatre autres images
cloud n'en active. Le service écoutait bien et répondait en local, mais
l'hôte ne recevait RIEN — pas un refus, un silence jusqu'au délai — et le
suivi déclarait Odoo absent sur une machine où il tournait. Mesuré : 000
après 12 s, puis 303 en 9 ms.
Un système déclaratif n'a que ce qui est écrit : xmlsec1, sans lequel
Odoo refuse d'installer auth_saml ; parallel et shfmt, appelés par leur
nom nu ; growpart, dont l'absence faisait rendre 0 à un agrandissement qui
n'agrandissait rien ; et l'agent invité, qui venait de l'image.
--- EN ---
NixOS enables a firewall by default; none of the four other cloud images
does. The service did listen and answered locally, but the host received
NOTHING — not a refusal, silence until the timeout — and the monitor
declared Odoo absent on a machine where it was running. Measured: 000
after 12 s, then 303 in 9 ms.
A declarative system has only what is written: xmlsec1, without which Odoo
refuses to install auth_saml; parallel and shfmt, called by bare name;
growpart, whose absence made a disk grow return 0 while growing nothing;
and the guest agent, which came from the image.
Assisted-by: Claude Opus 5
2026-09-16 00:43:40 -04:00
|
|
|
# L'agent invité, DÉCLARÉ ici plutôt que reçu de l'image.
|
|
|
|
|
#
|
|
|
|
|
# L'image épinglée l'active déjà (son configuration.nix porte la ligne), et
|
|
|
|
|
# c'est précisément le problème : la garantie appartient alors au tiers qui
|
|
|
|
|
# rebâtit l'image, pas au dépôt. Les quatre autres distributions reçoivent
|
|
|
|
|
# l'agent par le runcmd du déploiement, qui appelle leur gestionnaire de
|
|
|
|
|
# paquets — geste impossible sur un système déclaratif. Ici, c'est cette
|
|
|
|
|
# ligne ou rien.
|
|
|
|
|
#
|
|
|
|
|
# Sans agent, la voie Proxmox perd sa source PRIMAIRE d'adresse et retombe
|
|
|
|
|
# sur « ip neigh ». Déclarer l'option deux fois est sans effet : une option
|
|
|
|
|
# booléenne ne rompt l'évaluation que sur des valeurs DIFFÉRENTES. Hors
|
|
|
|
|
# QEMU, l'unité ne démarre pas — elle n'a pas de section [Install] et
|
|
|
|
|
# attend une règle udev sur le port virtio.
|
|
|
|
|
services.qemuGuest.enable = true;
|
|
|
|
|
|
|
|
|
|
# Ce que l'agent doit trouver dans son PATH.
|
|
|
|
|
#
|
|
|
|
|
# Une unité systemd n'hérite pas du profil du système : celle-ci ne porte
|
|
|
|
|
# que coreutils, findutils, grep, sed et systemd. Or « guest-exec » exécute
|
|
|
|
|
# les commandes du produit DANS ce PATH, et l'agrandissement du disque
|
|
|
|
|
# commence par « findmnt -no SOURCE / » — absent, donc code 127 dès la
|
|
|
|
|
# première ligne.
|
|
|
|
|
systemd.services.qemu-guest-agent.path = with pkgs; [
|
|
|
|
|
util-linux
|
|
|
|
|
e2fsprogs
|
|
|
|
|
cloud-utils
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
# Le port d'Odoo, OUVERT.
|
|
|
|
|
#
|
|
|
|
|
# NixOS active un pare-feu par défaut ; aucune des images cloud des quatre
|
|
|
|
|
# autres distributions n'en active un. Le service écoute bien sur
|
|
|
|
|
# 0.0.0.0:8069 et répond en local, mais l'extérieur ne reçoit RIEN — pas un
|
|
|
|
|
# refus, un silence, donc une attente jusqu'au délai. Ce qui sonde depuis
|
|
|
|
|
# l'hôte conclut « Odoo absent » sur une machine où il tourne, et le journal
|
|
|
|
|
# de l'installation ne porte aucune trace de la cause : elle est dans le
|
|
|
|
|
# pare-feu, pas dans l'application.
|
|
|
|
|
#
|
|
|
|
|
# 8069 SEUL. Le port websocket est configuré à 8072, mais Odoo ne le lie
|
|
|
|
|
# qu'en mode multi-processus, que cette configuration n'emploie pas : rien
|
|
|
|
|
# n'y écoute, et l'ouvrir donnerait un port béant sans service derrière.
|
|
|
|
|
# PostgreSQL n'écoute déjà que sur la boucle locale et n'a rien à ouvrir.
|
|
|
|
|
networking.firewall.allowedTCPPorts = [ 8069 ];
|
|
|
|
|
|
[FIX] nixos : le service ERPLibre déclaré, démarré quand Odoo est là
Trois obstacles enchaînés, aucun visible sans une vraie machine. /etc est
généré depuis le store : le « tee » d'une unité y rend « Read-only file
system », et l'installation échouait à sa DERNIÈRE étape, après que le
clone, le venv et un démarrage d'Odoo avaient réussi. ExecStart=/bin/bash
rendait 203/EXEC, /bin étant un montage FUSE que systemd ne voit pas ; et
le PATH d'une unité n'a pas bash, que réclament les shebangs de run.sh.
Déclarée, l'unité est démarrée par la reconstruction — qui a lieu pendant
« make install_os », quand la source d'Odoo n'arrive qu'après : une
condition la fait sauter plutôt qu'échouer 21 fois de suite. Mesuré :
service actif, 8069 servi par lui, login en 303.
--- EN ---
Three chained obstacles, none visible without a real machine. /etc is
generated from the store: « tee » of a unit there returns « Read-only file
system », and the install failed at its LAST step, after the clone, the
venv and an Odoo start had all succeeded. ExecStart=/bin/bash returned
203/EXEC, /bin being a FUSE mount systemd does not see; and a unit's PATH
carries no bash, which run.sh's shebangs ask for.
Declared, the unit is started by the rebuild — which happens during
« make install_os », while Odoo's source lands later: a condition makes it
skip rather than fail 21 times over. Measured: service active, 8069 served
by it, login in 303.
Assisted-by: Claude Opus 5
2026-09-16 21:31:50 -04:00
|
|
|
# Le service ERPLibre, DÉCLARÉ et non écrit.
|
|
|
|
|
#
|
|
|
|
|
# Sur toute autre distribution l'installation dépose l'unité par
|
|
|
|
|
# « tee /etc/systemd/system/erplibre.service ». Ici /etc est généré depuis
|
|
|
|
|
# le store et monté en lecture seule : le tee échoue sur « Read-only file
|
|
|
|
|
# system », et l'installation entière rend 1 à sa dernière étape, après que
|
|
|
|
|
# tout le reste a réussi.
|
|
|
|
|
#
|
|
|
|
|
# « wantedBy » est l'équivalent déclaratif de « systemctl enable » :
|
|
|
|
|
# l'activation par lien symbolique écrirait elle aussi dans /etc.
|
|
|
|
|
#
|
|
|
|
|
# L'interpréteur vient du STORE et non de /bin. /bin et /usr/bin sont ici
|
|
|
|
|
# un montage FUSE d'envfs, et systemd résout l'exécutable d'ExecStart
|
|
|
|
|
# lui-même, hors de portée de ce montage : « /bin/bash » y rend
|
|
|
|
|
# « 203/EXEC, Unable to locate executable ». Avec Restart=always, l'unité
|
|
|
|
|
# boucle alors indéfiniment. La même raison vaut pour /usr/bin/env, donc
|
|
|
|
|
# le shebang de run.sh ne suffirait pas davantage.
|
|
|
|
|
#
|
|
|
|
|
# La première reconstruction déclare le service AVANT qu'ERPLibre ne soit
|
|
|
|
|
# installé, et son démarrage échoue alors — c'est attendu, et c'est
|
|
|
|
|
# exactement le cas que « nixos-rebuild rend 4 » recouvre. L'installation
|
|
|
|
|
# le relance une fois le dépôt en place.
|
|
|
|
|
systemd.services.erplibre = {
|
|
|
|
|
description = "ERPLibre";
|
|
|
|
|
requires = [ "postgresql.service" ];
|
|
|
|
|
after = [ "network.target" "network-online.target" "postgresql.service" ];
|
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
# Une unité systemd ne reçoit PAS le PATH d'une session : le sien ne
|
|
|
|
|
# porte que coreutils, findutils, grep, sed et systemd.
|
|
|
|
|
#
|
|
|
|
|
# bash — run.sh lance odoo_bin.sh et lib_db_select.sh, dont le shebang est
|
|
|
|
|
# « #!/usr/bin/env bash ». env est là, bash non : « env: 'bash': No such
|
|
|
|
|
# file or directory », et run.sh s'arrête avant Odoo.
|
|
|
|
|
#
|
|
|
|
|
# python3 — la sonde de réveil tourne AVANT que odoo_bin.sh n'active le
|
|
|
|
|
# venv, donc avec le python du système. Son échec est silencieux
|
|
|
|
|
# (« 2>/dev/null ») : sans elle, la première page ouverte attendrait le
|
|
|
|
|
# chargement du registre sans que rien ne le dise.
|
|
|
|
|
path = with pkgs; [ bash python312 ];
|
|
|
|
|
# L'unité est déclarée par le module, donc démarrée par la
|
|
|
|
|
# reconstruction — qui a lieu PENDANT « make install_os », alors que la
|
|
|
|
|
# source d'Odoo n'arrive qu'à « make install_odoo_18 ». Sans condition,
|
|
|
|
|
# run.sh échoue sur un odoo-bin absent et « Restart = always » le rejoue
|
|
|
|
|
# toutes les cinq secondes jusqu'à ce que l'installation le pose — vingt
|
|
|
|
|
# et un échecs mesurés sur une pose ordinaire, et un « nixos-rebuild »
|
|
|
|
|
# qui rend 4 parce qu'une unité n'a pas démarré.
|
|
|
|
|
#
|
|
|
|
|
# Une CONDITION, et non une dépendance : systemd saute l'unité en le
|
|
|
|
|
# disant une fois, sans la marquer en échec, et la démarre d'elle-même
|
|
|
|
|
# au prochain déclenchement une fois le fichier là. Le motif évite de
|
|
|
|
|
# figer la version d'Odoo ici, où elle vieillirait en silence.
|
|
|
|
|
unitConfig.ConditionPathExistsGlob = "@EL_DIR@/odoo*/odoo/odoo-bin";
|
|
|
|
|
serviceConfig = {
|
|
|
|
|
Type = "simple";
|
|
|
|
|
User = "@EL_USER@";
|
|
|
|
|
WorkingDirectory = "@EL_DIR@";
|
|
|
|
|
ExecStart = "${pkgs.bash}/bin/bash @EL_DIR@/run.sh";
|
|
|
|
|
Restart = "always";
|
|
|
|
|
RestartSec = 5;
|
|
|
|
|
StandardOutput = "journal+console";
|
|
|
|
|
};
|
|
|
|
|
};
|
2026-09-16 00:41:43 -04:00
|
|
|
}
|