La revision a commence par un balayage par motifs — chemins morts, cibles make absentes, comptes derives. Il a trouve une trentaine d ecarts et rate presque tout le reste : un motif ne voit que ce qui s exprime en motif. make hote-planifier en est l exemple. La cible EXISTE, donc le controle passait au vert. C est une cible depreciee qui refuse et sort en 2, recommandee par AGENTS.md, et qui contredit la REGLE D OR du meme fichier trois ecrans plus haut. Il fallait lire pour la voir. 74 documents lus un par un. 66 corriges, 8 exacts. CE QUI ETAIT FRANCHEMENT FAUX AGENTS.md, la source d autorite, annoncait la flotte pas encore executee contre des VM reelles. Elle a ete rasee et remontee depuis zero trois fois. ecosysteme-chezlepro.md, le document montre a un client, portait la meme phrase : il se sous-vendait gravement. courriel-conception.md s ouvrait sur aucun role n est encore ecrit, au-dessus de son propre paragraphe 1 qui les nomme. autorisation.md se terminait sur rien n est construit alors qu il rapporte des mesures datees du role en fonctionnement. hebergeur-exploitation.md disait rien n est fait d un depot qui existe. filiation-emancipation.md se contredisait a deux ecrans de distance. DES MODELES DECRITS D APRES UN MONDE ANTERIEUR Le resolveur : cinq documents decrivaient un Unbound par VM en opt-in, trois le donnaient en exemple d integration FACULTATIVE — il est universel depuis le 2026-08-24. L adressage de nomenclature-vm.md : reseau unique, VLAN 11-15, VMID a cinq chiffres. Le nommage SDN de sdn-evpn.md contre le code : c est le wiki qui avait raison. CE QUI CASSE AU PREMIER ESSAI Le nom du gabarit dore etait faux a quatre endroits, dont la procedure qui le FABRIQUE et le critere R2 de l epreuve d operateur independant. preparer-un-site-hebergeur.md avertissait qu une VM faite a la main serait detruite : raser derive du plan, il ne la detruira jamais — le risque est l inverse. Un mot de passe d essai en clair dans un depot public. DEUX PREUVES ETENDUES, ET UNE QUI SE TROMPAIT ELLE-MEME P57 couvre les groupes : elle a signale aussitot 29 groupes annonces au-dessus d un tableau qui en cite 40. P29 confronte le tableau de authentification.md aux declarations reelles : 12 annonces, 21 reels. Et P57 imposait un chiffre faux — 56 preuves alors que le depot en porte 57, la conditionnelle vivant hors de tout comptage. Un garde-fou qui fait respecter une erreur ajoute l assurance a l erreur. CE QUI RESTE, ET QU AUCUNE PREUVE NE TIENT Deux comptes trouves a la main. Et une lacune reelle : rien ne garde les meta/acces.yml — ni qu un service web-sso en porte un, ni que le groupe qu il nomme existe. P29 tient les positions d authentification, personne ne tient les habilitations. make prouver : CONFORME, 56 OK, 0 echec, 1 saute. 0 lien mort. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
10 KiB
Multi-instances — un moteur, N écosystèmes
Pour qui : le mainteneur — la séparation entre le moteur et une instance.
Set-OPS sépare le moteur (ce dépôt : rôles, playbooks, scripts, GUI) de l'instance (un dépôt distinct : le plan d'un écosystème + son inventaire généré + ses secrets). Un seul moteur pilote autant d'instances que voulu.
« lab vs prod » n'est qu'un cas particulier : ce sont deux instances. Le même mécanisme sert un bac à sable, une production, ou les écosystèmes de plusieurs tenants — c'est le socle multi-tenant souverain.
Une instance = un écosystème autonome
Chaque instance est un dépôt séparé, monté dans le moteur par symlink (instance →).
Elle possède tout ce qui lui est propre :
<instance>/
├── plan/ ← la « méta-classe » (cf. meta-classe.md)
│ ├── nomenclature.yml réseau, VLAN, fonctions
│ ├── serveurs.yml VM = fonction + état + overrides
│ ├── applications.yml
│ ├── bases-donnees.yml
│ └── domaines.yml
└── inventories/principal/ ← un seul inventaire par instance
├── hosts.yml généré (make instancier-appliquer)
└── group_vars/
├── all/
│ ├── 00-instance.yml setops_plan_dir, setops_production
│ ├── 10-intrants.yml identité (domaine_interne, fuseau)
│ └── vault.yml 🔒 voûte UNIQUE de l'instance (chiffrée)
├── proxmox.yml cible Proxmox de l'instance
└── modeles_vm.yml construction du golden template
Isolation totale entre instances : plan, inventaire, voûte, identité
(domaine_interne), réseau (seed index → adressage dérivé distinct) et cible
Proxmox distincts. Une instance ne peut pas toucher l'infra d'une autre.
Gérer la flotte
Une seule instance est active à la fois — celle que pointe le symlink instance.
Toutes les commandes make (instancier, deployer, creer-vm, prouver…) visent l'active.
Voir la flotte — qui existe, laquelle est active (★), leur index, plage VLAN,
statut fédéré/local et production ; signale toute collision d'index :
make instances
INSTANCE INDEX VLAN FEDERE PROD
OPS-Chezlepro-lab 13 1131-1136 LOCAL non
* OPS-Chezlepro 17 1171-1176 oui oui
OPS-Technolibre 23 1231-1236 oui non
OPS-Patient0 29 1291-1296 oui ?
* = instance active (symlink 'instance'). Basculer : make instance-utiliser NOM=<depot>
(Sortie réelle du 2026-09-06. Ne pas se fier aux index d'un exemple : ils bougent —
celui de Chezlepro a changé au moins une fois, Technolibre est passé de 11 à 23. Le seul
endroit qui dit vrai est plan/nomenclature.yml de chaque dépôt, et cette commande.)
Basculer l'active — le symlink, avec garde-fous (le dossier existe, instance est
bien un symlink) :
make instance-courante # quelle instance est montée ?
make instance-utiliser NOM=OPS-Technolibre # bascule (l'inventaire suit le lien)
Rien à « recharger » : l'inventaire vit dans le dépôt de l'instance, il suit le lien. Le GUI (onglet Réseau) montre la même flotte et les collisions — et sait basculer, par le bouton « Activer » de chaque instance. (Ce paragraphe affirmait le contraire — « la bascule reste au CLI » — jusqu'au 2026-09-06 ; c'était vrai avant que le bouton n'existe.)
Deux réflexes. (1) Avant tout déploiement, make instance-courante : la seule vraie
façon de se tromper est de déployer sur la mauvaise flotte (la colonne prod est là pour
ça). (2) Un index unique par instance fédérée — make instances le crie, la preuve
P21 le refuse dans le harnais, mais choisis-le distinct dès la création.
Sans toucher au symlink (utile en CI ou pour du parallèle) :
make inventaire-ui SETOPS_INSTANCE=../OPS-ClientX
# ou viser un inventaire précis :
make deployer SETOPS_INVENTAIRE=../OPS-ClientX/inventories/principal/hosts.yml HOTE=…
L'inventaire est détecté de façon rétro-compatible : principal > production >
lab (les anciennes instances à double inventaire continuent de marcher).
Comment le moteur découvre les instances
Par convention de disposition, pas par un registre. Il n'y a ni base de données ni
fichier qui liste les instances. scripts/instances.py et scripts/devis_reseau.py font
simplement :
FRERES = RACINE.parent # le dossier qui CONTIENT Set-OPS-public
FRERES.glob("*/plan/nomenclature.yml") # tout dépôt frère ayant un plan
Une instance est donc un dossier : (1) frère du moteur (../OPS-Chezlepro,
../OPS-Technolibre…), (2) portant un plan/nomenclature.yml, (3) avec un index.
De là : active = ce que résout le symlink instance ; fédérée = index présent
et federe ≠ false. Les modèles (exemples/modeles/… ici, Set-OPS-modeles/… pour les modèles privés) sont un cran plus
profond — le glob ne les attrape pas, volontairement.
Conséquence : « inscrire » une instance = la déposer à côté des autres. Rien à éditer,
aucune synchronisation, donc aucune dérive « inscrite mais absente ». Le revers — la flotte
étant « ce qui est là » — est qu'un simple dossier frère (le bac à sable) y apparaît :
d'où le drapeau federe: false pour l'écarter du réseau convergé, et make instances +
P21 pour garder un regard et un filet.
setops_production — un attribut, pas une catégorie
Le déploiement réel est permis sur toute instance (un bac à sable déploie sur son
infra). Le drapeau setops_production (dans group_vars/all/) ne bloque rien : il
marque la PRODUCTION pour exiger une confirmation renforcée au déploiement (badge
rouge « PROD », bouton Déployer rouge, re-saisie du nom d'hôte). Une instance bac à
sable met false et affiche « bac à sable ».
Créer une nouvelle instance
- Créer un dépôt d'instance frère de
Set-OPS-public/(ex.../OPS-ClientX), avec la structure ci-dessus. Le plus simple : copier un modèle deexemples/modeles/ou l'instance bac à sable comme point de départ. - Régler l'identité (
10-intrants.yml: domaine distinct), le réseau (nomenclature.yml:indexdistinct — tout l'adressage en dérive, cf. plus bas) et la cible Proxmox (proxmox.yml). - Créer la voûte unique depuis le gabarit (cf.
config-proxmox.md) :cp exemples/vault.exemple.yml …/group_vars/all/vault.ymlpuisansible-vault encrypt. Et poser SA clé — une voûte, une clé :~/.config/setops-vault-ops-clientx, nom dérivé du dossier en minuscules.python3 scripts/voutes.py etatconfirme que le moteur la trouve. make instance-utiliser NOM=OPS-ClientXpuismake instancier-appliquer,make inventaire-ui.
Multi-tenant
Chaque tenant est simplement une instance de plus. Un client =
make instance-utiliser NOM=OPS-<Client>, tout son écosystème instancié par le même
moteur, isolé. C'est la base concrète de la portabilité des tenants.
Garde-fou de positionnement : si le nombre d'instances explose, le besoin d'un registre (lister/choisir, IPAM, secrets centralisés) relève d'outils établis (NetBox, AWX, un coffre type Vault HashiCorp) à adopter aux seuils, pas à réimplémenter dans le moteur. Cf.
positionnement.md.
Adressage fédéré : tout dérive du seed index
Pour que plusieurs écosystèmes coexistent sur une même fabric sans collision, chaque
instance reçoit un index (unique champ d'adressage de plan/nomenclature.yml :
index: N). Rien d'autre n'est écrit à la main — la nomenclature ne garde que le
modèle (libellés de zones + placement des fonctions) ; supernet, sous-réseaux,
passerelles, VLAN et VMID se dérivent (scripts/inventory_rules.py : supernet_de,
base3_de, passerelle_de, vlan_de). Changer index rederive tout le réseau — et la
preuve P20 interdit tout adressage stocké.
Ce que index dérive (modèle à 6 zones) :
| Élément | Formule | Exemple (index 13) |
|---|---|---|
| Supernet | 10.<index>.0.0/16 |
10.13.0.0/16 |
| Sous-réseau de zone | 10.<index>.(15+zone).0/24 |
10.13.16.0/24 (Frontière) |
| Passerelle | …(15+zone).1 |
10.13.16.1 |
| VLAN sur le trunk | 1000 + index×10 + zone |
1131-1136 |
| VMID (ip-miroir) | VLAN · octet-hôte · séq (9 chiffres) |
113102101 |
Les VLAN de deux index différents ne peuvent mathématiquement pas se chevaucher
(l'espacement ×10 laisse de la marge). Deux instances de même index, elles, ont les
mêmes VLAN/VMID : c'est la collision que make instances et P21 attrapent.
Bacs à sable. Un bac à sable local (labo) a lui aussi un index, mais on le marque
federe: false : il est alors exclu du réseau convergé (devis, make instances le
montre « local »). Il garde son adressage dérivé et reste déployable sur son infra.
Plafond : le 2ᵉ octet IPv4. valider_index borne l'index à 0–255
(INDEX_MIN/INDEX_MAX, scripts/inventory_rules.py) — la garde est posée à la source
de la dérivation, donc aucune fonction ne peut fabriquer une adresse hors bornes, d'où
qu'on l'appelle. En pratique, éviter 0 : 10.0.x porte déjà les réseaux de service du
site. Le décalage de +10, retiré le 2026-08-12, confisquait dix valeurs — et surtout, il
empêchait de lire l'index directement dans l'adresse. Le VLAN (≤ 4094) autoriserait
jusqu'à 308, le VMID bien plus : c'est donc l'adressage IP qui plafonne. Au-delà d'une poignée d'instances
co-localisées, confier l'allocation à un IPAM (NetBox) plutôt qu'au moteur — cf.
positionnement.md.
Voir aussi
meta-classe.md— le plan d'une instance instancie sa flotte.config-proxmox.md— voûte unique + cible Proxmox par instance.intrants-communs.md— intrants de base d'une instance.