Deux corrections de propriété, l'une dans le plan, l'autre dans les intrants. 1. Intégrations universelles (D-33/D-34, P26) Le plan portait 57 lignes d'intégration écrites à la main, dont 28 disaient oui à quelque chose de vrai pour tous les hôtes. Elles n'existaient que pour être oubliées — et elles l'avaient été : dans Chezlepro, backup-01 et infra-pki-01 n'étaient ni supervisés, ni journalisés, ni certifiés. Le rôle déclare désormais sa politique une fois, dans meta/integration.yml ; le plan ne garde que les vrais choix et refuse la recopie. Les exemptions se dérivent du service rendu (sauf_role), jamais d'un nom d'hôte : l'AC ne s'enrôle pas auprès d'elle-même, et l'exemption suit step-ca si on le déplace. Une seule fonction de résolution — integrations_de() — lue par l'inventaire, la voûte et le panneau. Sans le passage par la voûte, les secrets des intégrations universelles auraient cessé d'être exigés et P18 serait passé au vert sur une voûte incomplète. Vérifié : diff vide sur Technolibre (la politique reproduit exactement les 41 lignes retirées) ; sur Chezlepro, exactement les groupes manquants, et pas client_pki sur infra-pki-01. 2. Vue Intégrations : la matrice La fiche montrait les intégrations d'UN serveur ; le trou de Chezlepro n'a pas été trouvé par le panneau mais par le devis de pare-feu. Matrice serveurs x intégrations : colonnes de politique en lecture seule, facultatives cochables sur place, ligne de couverture n/N qui rend le motif visible sans le juger. 3. Propriété des intrants (D-35/D-36, P27) Le cluster Proxmox appartient à l'hébergeur, comme sa fabric et sa frontière. Recopié chez chaque tenant, son inventaire avait déjà divergé : deux listes de stockages contradictoires pour le même matériel. API/nœuds/stockages/ponts vont dans proxmox-hebergeur.yml, à côté d'underlay.yml, dont le chemin se dérive — l'hébergeur reste non déclaré (D-17). Restent au tenant son golden template et ses défauts de placement. Le panneau nomme désormais le propriétaire de chaque section : éditer une section « hébergeur » vaut pour tous ses tenants, et l'écran ne le disait pas. 26 preuves OK, 0 échec. --syntax-check des deux playbooks Proxmox. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
180 lines
8.5 KiB
Markdown
180 lines
8.5 KiB
Markdown
# 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 `client_*` **facultatives** seulement — les universelles viennent du rôle, voir `integrations-vm.md`) |
|
||
| `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 universelles** (politique du rôle : `roles/client_*/meta/integration.yml`)
|
||
+ **intégrations facultatives** (`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.
|