This repository has been archived on 2026-06-26. You can view files and clone it, but cannot push or open issues or pull requests.
Set-OPS/docs/plan-et-generation.md
Daniel Allaire b775b7f99d Neutraliser le moteur pour partage public (100% neutre)
Suppression de toute trace Chezlepro de l'outil (roles, scripts, docs
publiques, exemples, LICENSE). Prouve par scan exhaustif : git grep vide
pour chezlepro, asgard/TrueNAS, supernet reel 10.1.x.

Corrige 5 defauts de genericite fonctionnels (motd, app.ini Forgejo,
organisation openldap, nom AC step-ca, et IP reelles codees en dur dans
les defaults de roles -> plage d'exemple 10.0.x). LICENSE -> Alliance
Boreale. Fichiers mainteneur + CHANGELOG conserves (par decision).

La separation moteur/instance tient : OPS-Chezlepro surcharge deja ses
vraies valeurs de topologie. Verifie : make verifier exit 0 (4 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 19:58:00 -04:00

179 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Le plan et la génération d'inventaire (méta-classe)
Set-OPS ne s'édite plus comme un inventaire à la main : on **décrit un plan**, et
l'inventaire Ansible en est **généré**. Le dépôt est la définition ; chaque VM en
est une instance. Ce document décrit le modèle, les registres, les commandes et
le flux de travail.
> Règle d'or : **`instance/inventories/production/hosts.yml` est GÉNÉRÉ. Ne jamais l'éditer
> à la main.** On édite le *plan* puis on régénère (`make instancier-appliquer`).
---
## 1. Le modèle : deux ancres, cinq liens
L'écosystème = des **serveurs** (VM) et des **applications**, reliés à leurs
**bases**, leurs **domaines** et leurs dépendances :
```
serveur (VM) ──fournit──▶ capacités (= groupes/rôles Ansible)
application ──tourne_sur──▶ serveur (une VM peut porter N applications)
application ──requiert──▶ application(s) (DNS, PKI, BD…)
application ──utilise──▶ base(s) (via le DSN)
application ──expose──▶ domaine(s) public(s) (le FQDN, derrière l'edge)
base ──hébergée_sur──▶ serveur de BD
```
L'**application** est l'entité pivot : tout ce qui décrit « ce qui tourne et à
quoi c'est connecté » pend d'elle. Le **groupe** Ansible n'est plus une cible de
liaison — seulement une **capacité** qu'une VM fournit (le rôle appliqué).
---
## 2. Les registres (source unique de vérité)
Tous sous `docs/`, machine-lisibles, validés, consommés par le GUI, le CLI et Ansible.
| Registre | Décrit | Champs clés |
| --- | --- | --- |
| `nomenclature.yml` | nommage & adressage | `fonctions` (catégorie/service), `categories` (VLAN/sous-réseau/passerelle), `supernet` |
| `serveurs.yml` | les VM du plan | `fonction`, `etat` (actif/planifie), placement Proxmox (`noeud`/`stockage`/`disque`/`memoire`/`coeurs`), `integrations` (les `clients_*`) |
| `applications.yml` | les applications | `groupe` (capacité/rôle), `hote` (VM), `port`, `requiert`, `expose`, (+ bases via consommateur) |
| `bases-donnees.yml` | serveurs de BD + bases | `serveurs_bd` ; `bases_donnees` : `serveur`/`base`/`proprietaire`/`secret`(Vault), `consommateur` + `portee` (`application`/`groupe`/`hote`), `usage` |
| `domaines.yml` | zones DNS publiques | `domaines_publics` : `autorite`, `edge`, `secondaires`, `dnssec`, `mail` |
| `dependances-groupes.yml` | prérequis entre groupes | `requiert_groupes_actifs` |
### Dérivations clés
- **Nommage/adressage** : tout part de la `fonction` de l'hôte (`web-frontal-03`).
`VMID = 9·catégorie·service·NN`, `VLAN = catégorie.vlan`,
`IP = 10.0.<vlan>.(service×10 + NN)`. Voir `docs/nomenclature-vm.md`.
- **DSN** (lien application↔base) : `<type>://<proprietaire>:<secret>@<hôte>:<port>/<base>`.
Une application reçoit les bases où `(portee=application ET consommateur=elle)`
OU `(portee=groupe ET consommateur=son groupe)` OU `(portee=hote ET consommateur=son hôte)`.
- **Exposition DNS** : `application.expose: [fqdn]` + l'`edge` du domaine parent →
`serveur_nginx` génère le vhost (`application → hôte → IP:port`).
---
## 3. La génération (méta-classe)
`make instancier` produit `hosts.yml` **depuis le plan** :
- **host vars** : `ansible_host`/`ansible_user` + `proxmox_*` (IP/VMID/VLAN/passerelle
**dérivés** de la nomenclature ; placement/taille depuis `serveurs.yml`).
- **groupes** d'une VM = socle (`serveur_debian` + `serveur_durci`)
+ **services** (les `groupe` des applications de l'hôte)
+ **intégrations** (`serveurs.yml: integrations`)
+ **état** (`hotes_actifs` / `hotes_planifies`).
La comparaison est **sémantique** (via `ansible-inventory --list`, formatage
ignoré). « **Diff vide** » = le plan reproduit exactement l'inventaire courant ;
c'est le feu vert pour appliquer.
---
## 4. Le flux de travail
```
éditer le PLAN ──▶ make instancier (revoir le diff) ──▶ make instancier-appliquer ──▶ déployer
(GUI ou CLI) (que va-t-il changer ?) (régénère hosts.yml) (make deployer)
```
### Via le GUI — `make inventaire-ui`
Cinq vues :
| Vue | Rôle |
| --- | --- |
| **Inventaire** | **lecture seule** (inventaire généré) — vue d'ensemble des hôtes |
| **Serveurs** | éditer les VM du plan : fonction/état/placement/intégrations (VMID·IP·VLAN dérivés en direct) ; bouton **« Appliquer le plan »** |
| **Chaîne** | vue holistique par hôte : groupes → rôles, et par application ses `expose` / `requiert` / bases (DSN) |
| **Applications** | éditer les applications : groupe/hôte/port/requiert/expose |
| **Bases** | éditer serveurs de BD et bases (portée + consommateur), DSN affiché |
Édition → **Sauvegarder** (écrit le registre) → **Appliquer le plan** (régénère
`hosts.yml`). L'écriture directe de l'inventaire est refusée (409).
### Via le CLI / `make`
Chaque registre a son script miroir et ses cibles `make` :
| Domaine | Lister | Vérifier | Bootstrap (depuis l'inventaire) |
| --- | --- | --- | --- |
| Serveurs | `make serveurs` | `make serveurs-verifier` | `make serveurs-bootstrap` |
| Applications | `make applications` | `make applications-verifier` | `make applications-bootstrap` |
| Bases | `make bases` | `make bases-verifier` | — |
| Domaines | `make domaines` | `make domaines-verifier` | — |
Génération :
```bash
make instancier # génère hosts.genere.yml (gitignoré) + diff sémantique
make instancier-appliquer # régénère hosts.yml (refuse si diff non vide ; FORCE=1 pour forcer)
```
Validation globale : `make inventaire-verifier` (ansible-inventory + tous les
registres + **`node --check` du JS du GUI**).
---
## 5. Garde-fous
- **Validateurs** : chaque registre est validé (références connues, énumérations,
unicité). Un `expose` sans domaine parent, un `requiert` fantôme, une `portee`
inconnue, une `fonction` absente → rejet.
- **Diff vide** : `instancier-appliquer` refuse d'écraser l'inventaire si le plan
ne le reproduit pas (sauf `FORCE=1` pour un changement intentionnel).
- **`node --check`** : le JS embarqué du GUI est vérifié (`scripts/verifier_gui.py`,
intégré à `make inventaire-verifier`) — une erreur de syntaxe JS casse toute la page.
- **git** : `hosts.yml` est versionné ; `git diff` / `git checkout` est le filet.
- **Secrets** : jamais en clair ; `secret:` nomme une variable Ansible Vault.
---
## 6. Réutilisation de la règle (Ansible)
La règle de résolution vit **une seule fois**, en Python (`scripts/inventory_rules.py`),
et est exposée à Ansible par un *filter plugin* (`filter_plugins/registres.py`) :
`bases_de_application`, `applications_de_hote`, `expositions_des_applications`,
`chaine_connexion`. Les playbooks par application (`serveur_web_dorsal`/`_frontaux`)
itèrent ainsi sur les applications de l'hôte et résolvent leurs DSN.
---
## 7. Amorçage / reconstruction
Pour (re)construire le plan depuis un inventaire existant :
```bash
make serveurs-bootstrap # VM -> instance/plan/serveurs.yml (fonction/état/placement/integrations)
make applications-bootstrap # services serveurs_* (hors socle) -> instance/plan/applications.yml
make instancier # vérifier le diff vide
```
C'est ainsi que le plan a été initialisé sans perte, avec diff vide vérifié.
---
## 8. Moteur et instance : deux dépôts
Le **moteur** (ce dépôt, `Set-OPS`) est générique et partageable ; il ne contient
aucune donnée d'instance. Une **instance** (le plan + l'inventaire d'un loup) vit
dans son **propre dépôt** (ex. `OPS-monatelier`).
Le moteur localise l'instance via **`SETOPS_INSTANCE`** (défaut : `instance`). Deux
modèles :
- **Modèle A — dépôts frères** (en cours) : moteur et instance côte à côte ; un
symlink `instance -> ../OPS-monatelier` (gitignoré) fait que le défaut résout
l'instance sans configuration. Idéal quand on développe le moteur *et* l'instance.
- **Modèle B — moteur en sous-module** (futur, pour la meute) : l'instance épingle
une version du moteur ; `SETOPS_INSTANCE` pointe la racine de l'instance.
Pour brancher une instance (modèle A) :
```bash
cd Set-OPS
ln -s ../OPS-monatelier instance # ou : export SETOPS_INSTANCE=/chemin/instance
make inventaire-verifier # lit l'instance via le symlink
```
Le moteur écrit `hosts.yml` (généré) **dans le dépôt d'instance**, jamais dans le sien.