Solder la dette doc apres le decouplage moteur/instance

Rafraichir les chemins dans docs secondaires, README de roles, messages,
docstrings : inventories/ -> instance/inventories/, docs/<plan>.yml ->
instance/plan/<plan>.yml. Correction de chemins de playbooks perimes
(preexistants) dans CLAUDE.md/SOLUTION.md : vm_templates/..._prepare|
verify|cleanup -> modeles_vm/..._preparer|verifier|nettoyer, et
confirm_template_cleanup -> template_cleanup_confirm.

Valide : diff vide, ansible-lint 0 echec, make inventaire-verifier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-06-24 10:04:14 -04:00
parent 780b1e6b24
commit 95698a36c0
33 changed files with 68 additions and 67 deletions

View file

@ -3,6 +3,7 @@
## 2026-06-23 ## 2026-06-23
### Modifié ### Modifié
- **Dette doc soldée après le découpage moteur/instance.** Rafraîchissement des chemins dans les docs secondaires, README de rôles, messages et docstrings : `inventories/...``instance/inventories/...`, `docs/<plan>.yml``instance/plan/<plan>.yml`. Correction au passage de chemins de playbooks périmés (préexistants) dans `CLAUDE.md`/`SOLUTION.md` : `playbooks/vm_templates/debian13_proxmox_prepare|verify|cleanup.yml``playbooks/modeles_vm/debian13_proxmox_preparer|verifier|nettoyer.yml`, et `confirm_template_cleanup``template_cleanup_confirm`. Validé : diff vide, `ansible-lint` 0 échec, `make inventaire-verifier`.
- **Découpage moteur/instance — Phase 3 (modèle A) : deux dépôts.** Le contenu de `instance/` (plan + inventaire) part dans un **dépôt d'instance dédié** (`OPS-Chezlepro` pour Chezlepro, sur la forge). `Set-OPS` devient le **moteur pur** (rôles, scripts, playbooks, guides, exemples). L'instance est **montée via un symlink** `instance -> ../OPS-Chezlepro` (gitignoré) : le défaut `SETOPS_INSTANCE=instance` la résout sans configuration. Le moteur lit le plan et **régénère `hosts.yml` dans le dépôt d'instance**. `.ansible-lint` exclut `instance/`. Validé : diff vide, `ansible-lint` 0 échec, `make inventaire-verifier`, `instancier-appliquer`. **Modèle A (dépôts frères)** retenu jusqu'à preuve du concept ; le **modèle B (moteur en sous-module)** pour la meute viendra ensuite. Le moteur ne contient plus aucune donnée Chezlepro. - **Découpage moteur/instance — Phase 3 (modèle A) : deux dépôts.** Le contenu de `instance/` (plan + inventaire) part dans un **dépôt d'instance dédié** (`OPS-Chezlepro` pour Chezlepro, sur la forge). `Set-OPS` devient le **moteur pur** (rôles, scripts, playbooks, guides, exemples). L'instance est **montée via un symlink** `instance -> ../OPS-Chezlepro` (gitignoré) : le défaut `SETOPS_INSTANCE=instance` la résout sans configuration. Le moteur lit le plan et **régénère `hosts.yml` dans le dépôt d'instance**. `.ansible-lint` exclut `instance/`. Validé : diff vide, `ansible-lint` 0 échec, `make inventaire-verifier`, `instancier-appliquer`. **Modèle A (dépôts frères)** retenu jusqu'à preuve du concept ; le **modèle B (moteur en sous-module)** pour la meute viendra ensuite. Le moteur ne contient plus aucune donnée Chezlepro.
- **Découpage moteur/instance — Phase 2b : sortir l'inventaire dans `instance/inventories/`.** L'inventaire (hôtes générés, `group_vars`, vault) quitte `inventories/` pour `instance/inventories/`. Suivent : `ansible.cfg`, le `Makefile` (`export SETOPS_INSTANCE ?= instance`, chemins dérivés), les scripts (`INSTANCE / "inventories/..."`), `config_proxmox.py`, `.gitignore`. Les docs primaires (`AGENTS.md`, `README.md`, `docs/plan-et-generation.md`, `docs/architecture-set-ops.md`) reflètent le layout `instance/`. Non destructif : diff vide, `ansible-lint` 0 échec, `make inventaire-verifier` OK. *(Docs secondaires à rafraîchir ; Phase 3 : deux dépôts.)* - **Découpage moteur/instance — Phase 2b : sortir l'inventaire dans `instance/inventories/`.** L'inventaire (hôtes générés, `group_vars`, vault) quitte `inventories/` pour `instance/inventories/`. Suivent : `ansible.cfg`, le `Makefile` (`export SETOPS_INSTANCE ?= instance`, chemins dérivés), les scripts (`INSTANCE / "inventories/..."`), `config_proxmox.py`, `.gitignore`. Les docs primaires (`AGENTS.md`, `README.md`, `docs/plan-et-generation.md`, `docs/architecture-set-ops.md`) reflètent le layout `instance/`. Non destructif : diff vide, `ansible-lint` 0 échec, `make inventaire-verifier` OK. *(Docs secondaires à rafraîchir ; Phase 3 : deux dépôts.)*
- **Découpage moteur/instance — Phase 2a : sortir le plan dans `instance/plan/`.** Les 5 registres (`serveurs`, `applications`, `bases-donnees`, `domaines`, `nomenclature`) quittent `docs/` pour `instance/plan/`. Les scripts les localisent via **`SETOPS_INSTANCE`** (variable d'env, défaut `<dépôt>/instance`) ; les rôles/playbooks via **`setops_plan_dir`** (group_vars d'instance). `docs/` ne garde que les guides `.md` + `dependances-groupes.yml` (moteur). `.ansible-lint` exclut `instance/plan/` (registres de données). Non destructif : diff vide, `ansible-lint` 0 échec, `include_vars` via `setops_plan_dir` testé. *(Phase 2b : sortir l'inventaire ; Phase 3 : deux dépôts.)* - **Découpage moteur/instance — Phase 2a : sortir le plan dans `instance/plan/`.** Les 5 registres (`serveurs`, `applications`, `bases-donnees`, `domaines`, `nomenclature`) quittent `docs/` pour `instance/plan/`. Les scripts les localisent via **`SETOPS_INSTANCE`** (variable d'env, défaut `<dépôt>/instance`) ; les rôles/playbooks via **`setops_plan_dir`** (group_vars d'instance). `docs/` ne garde que les guides `.md` + `dependances-groupes.yml` (moteur). `.ansible-lint` exclut `instance/plan/` (registres de données). Non destructif : diff vide, `ansible-lint` 0 échec, `include_vars` via `setops_plan_dir` testé. *(Phase 2b : sortir l'inventaire ; Phase 3 : deux dépôts.)*

View file

@ -61,7 +61,7 @@ Avant de dire quun changement est prêt, exécuter au minimum le `--syntax-ch
Pour le template Debian 13 Proxmox : Pour le template Debian 13 Proxmox :
```bash ```bash
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_prepare.yml --syntax-check ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml --syntax-check
``` ```
Si `ansible-lint` est disponible : Si `ansible-lint` est disponible :

View file

@ -22,25 +22,25 @@ Les rôles sont nommés clairement, sans sous-arborescence complexe.
## Commande principale pour construire le template ## Commande principale pour construire le template
```bash ```bash
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_prepare.yml --ask-pass --ask-become-pass ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml --ask-pass --ask-become-pass
``` ```
Après que sudo sans mot de passe fonctionne : Après que sudo sans mot de passe fonctionne :
```bash ```bash
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_prepare.yml ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_preparer.yml
``` ```
## Vérification ## Vérification
```bash ```bash
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_verify.yml ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_verifier.yml
``` ```
## Nettoyage final avant conversion ## Nettoyage final avant conversion
```bash ```bash
ansible-playbook -i inventories/lab/hosts.yml playbooks/vm_templates/debian13_proxmox_cleanup.yml -e confirm_template_cleanup=true ansible-playbook -i instance/inventories/lab/hosts.yml playbooks/modeles_vm/debian13_proxmox_nettoyer.yml -e template_cleanup_confirm=true
``` ```
Ensuite : Ensuite :

View file

@ -14,7 +14,7 @@ La nomenclature des VM et des VMID est documentée dans `docs/nomenclature-vm.md
Un service central peut partager un hôte avec d'autres services de la même fonction opérationnelle (plusieurs applications par VM). La relation stricte est entre groupe et playbook, pas entre groupe et VM. Un service central peut partager un hôte avec d'autres services de la même fonction opérationnelle (plusieurs applications par VM). La relation stricte est entre groupe et playbook, pas entre groupe et VM.
> Modèle à jour : chaque service est une **application** (`docs/applications.yml`). Voir `docs/plan-et-generation.md`. > Modèle à jour : chaque service est une **application** (`instance/plan/applications.yml`). Voir `docs/plan-et-generation.md`.
## Services centraux ## Services centraux

View file

@ -22,7 +22,7 @@ chezlepro.internal
Elle est definie dans : Elle est definie dans :
```text ```text
inventories/production/group_vars/serveur_powerdns.yml instance/inventories/production/group_vars/serveur_powerdns.yml
``` ```
## Enregistrement automatique ## Enregistrement automatique

View file

@ -62,11 +62,11 @@ Vérifications utiles depuis le poste Ansible :
```bash ```bash
ssh ansible@10.1.99.99 ssh ansible@10.1.99.99
ansible -i inventories/lab/hosts.yml modeles_vm -m ping ansible -i instance/inventories/lab/hosts.yml modeles_vm -m ping
ansible -i inventories/lab/hosts.yml modeles_vm -m setup ansible -i instance/inventories/lab/hosts.yml modeles_vm -m setup
``` ```
Adapter l'utilisateur et l'adresse IP selon `inventories/lab/hosts.yml`. Adapter l'utilisateur et l'adresse IP selon `instance/inventories/lab/hosts.yml`.
### Prérequis côté dépôt ### Prérequis côté dépôt
@ -86,7 +86,7 @@ modeles_vm
Les variables du template sont dans : Les variables du template sont dans :
```text ```text
inventories/lab/group_vars/modeles_vm.yml instance/inventories/lab/group_vars/modeles_vm.yml
``` ```
### Commande de préparation ### Commande de préparation
@ -132,7 +132,7 @@ Un résultat `changed=0` à la relance est le signal que le playbook est idempot
| Symptôme | Cause probable | Action | | Symptôme | Cause probable | Action |
| --- | --- | --- | | --- | --- | --- |
| `UNREACHABLE` | IP, SSH, utilisateur ou clé SSH incorrecte. | Vérifier `inventories/lab/hosts.yml`, cloud-init et tester `ssh`. | | `UNREACHABLE` | IP, SSH, utilisateur ou clé SSH incorrecte. | Vérifier `instance/inventories/lab/hosts.yml`, cloud-init et tester `ssh`. |
| échec `become` | Sudo NOPASSWD absent ou utilisateur non autorisé. | Corriger l'accès sudo initial, puis relancer `make preparer-modele`. | | échec `become` | Sudo NOPASSWD absent ou utilisateur non autorisé. | Corriger l'accès sudo initial, puis relancer `make preparer-modele`. |
| échec APT | DNS, passerelle, miroir Debian ou verrou APT. | Vérifier réseau, DNS et processus APT en cours. | | échec APT | DNS, passerelle, miroir Debian ou verrou APT. | Vérifier réseau, DNS et processus APT en cours. |
| erreur handler SSH | Handler manquant ou nom `notify` incohérent. | Vérifier les handlers du rôle SSH avant de relancer. | | erreur handler SSH | Handler manquant ou nom `notify` incohérent. | Vérifier les handlers du rôle SSH avant de relancer. |

View file

@ -83,7 +83,7 @@ Réseau interne unique : `10.1.0.0/16`. Segmentation par fonction, un `/24` et u
Adresse d'hôte (4ᵉ octet) : **`service × 10 + NN`**. `.1` = passerelle ; `.2``.9` réservés. Exemple : `web-dorsal-01` (catégorie 5, service 4, NN 01) → `10.1.15.41`. Adresse d'hôte (4ᵉ octet) : **`service × 10 + NN`**. `.1` = passerelle ; `.2``.9` réservés. Exemple : `web-dorsal-01` (catégorie 5, service 4, NN 01) → `10.1.15.41`.
Tout se dérive de la fonction de l'hôte, et la source unique machine-lisible est **`docs/nomenclature.yml`** : Tout se dérive de la fonction de l'hôte, et la source unique machine-lisible est **`instance/plan/nomenclature.yml`** :
```text ```text
hostname = <fonction>-<NN> hostname = <fonction>-<NN>
@ -94,13 +94,13 @@ IP = 10.1.<vlan>.(service × 10 + NN)
`make inventaire-ui` lit ce registre et **propose** automatiquement VMID, VLAN, IP et passerelle quand on nomme un hôte. La sécurité entre zones se fera par règles inter-zones (nftables / edge), pas par l'adressage. `make inventaire-ui` lit ce registre et **propose** automatiquement VMID, VLAN, IP et passerelle quand on nomme un hôte. La sécurité entre zones se fera par règles inter-zones (nftables / edge), pas par l'adressage.
Contrainte : `NN` de 01 à 09 par fonction (l'octet hôte reste dans le bloc du service). Au-delà, ouvrir une nouvelle fonction/service dans `docs/nomenclature.yml`. Contrainte : `NN` de 01 à 09 par fonction (l'octet hôte reste dans le bloc du service). Au-delà, ouvrir une nouvelle fonction/service dans `instance/plan/nomenclature.yml`.
La segmentation `10.1.0.0/16` remplace l'ancienne plage d'essais `192.168.12.x`. La segmentation `10.1.0.0/16` remplace l'ancienne plage d'essais `192.168.12.x`.
## Variables de provisioning d'hôte ## Variables de provisioning d'hôte
Le **plan** est la source de vérité du provisioning. Le placement et le dimensionnement d'une VM vivent dans `docs/serveurs.yml` (vue **Serveurs** du GUI) ; VMID / IP / VLAN / passerelle sont **dérivés** de la fonction. Ces variables d'hôte sont alors **générées** dans l'inventaire (ne pas les éditer à la main) : Le **plan** est la source de vérité du provisioning. Le placement et le dimensionnement d'une VM vivent dans `instance/plan/serveurs.yml` (vue **Serveurs** du GUI) ; VMID / IP / VLAN / passerelle sont **dérivés** de la fonction. Ces variables d'hôte sont alors **générées** dans l'inventaire (ne pas les éditer à la main) :
| Variable | Sens | Type | | Variable | Sens | Type |
| --- | --- | --- | | --- | --- | --- |
@ -117,16 +117,16 @@ Le **plan** est la source de vérité du provisioning. Le placement et le dimens
| `proxmox_memoire` | mémoire en Mo | int | | `proxmox_memoire` | mémoire en Mo | int |
| `proxmox_coeurs` | nombre de cœurs | int | | `proxmox_coeurs` | nombre de cœurs | int |
Ces valeurs sont **générées** dans l'inventaire depuis `docs/serveurs.yml` + la nomenclature (`make instancier-appliquer`). Une valeur vide n'est pas écrite, pour garder l'inventaire propre. Ces valeurs sont **générées** dans l'inventaire depuis `instance/plan/serveurs.yml` + la nomenclature (`make instancier-appliquer`). Une valeur vide n'est pas écrite, pour garder l'inventaire propre.
## État d'un hôte (planifié / actif) ## État d'un hôte (planifié / actif)
Chaque VM porte un `etat` dans `docs/serveurs.yml` : Chaque VM porte un `etat` dans `instance/plan/serveurs.yml` :
- `planifie` — prévue mais non encore déployée → groupe `hotes_planifies` à la génération ; - `planifie` — prévue mais non encore déployée → groupe `hotes_planifies` à la génération ;
- `actif` — réellement joignable par Ansible → groupe `hotes_actifs`. - `actif` — réellement joignable par Ansible → groupe `hotes_actifs`.
L'état se change dans la vue **Serveurs** du GUI (ou `docs/serveurs.yml`), puis on L'état se change dans la vue **Serveurs** du GUI (ou `instance/plan/serveurs.yml`), puis on
régénère l'inventaire : régénère l'inventaire :
```bash ```bash
@ -135,4 +135,4 @@ make instancier-appliquer
Les déploiements groupés limitent automatiquement l'exécution à `<groupe demandé> & hotes_actifs`, ce qui permet de décrire l'écosystème complet (hôtes planifiés inclus) sans tenter de configurer une VM qui n'existe pas encore. Les déploiements groupés limitent automatiquement l'exécution à `<groupe demandé> & hotes_actifs`, ce qui permet de décrire l'écosystème complet (hôtes planifiés inclus) sans tenter de configurer une VM qui n'existe pas encore.
> Les anciennes commandes `make hote-planifier` / `hote-ajouter` éditaient `hosts.yml` directement ; l'inventaire étant désormais **généré**, elles sont supplantées par le plan (`docs/serveurs.yml`). > Les anciennes commandes `make hote-planifier` / `hote-ajouter` éditaient `hosts.yml` directement ; l'inventaire étant désormais **généré**, elles sont supplantées par le plan (`instance/plan/serveurs.yml`).

View file

@ -30,7 +30,7 @@ souverain et léger**. Cet assemblage-là est propre à Set-OPS.
## 2. Ce que Set-OPS fait sciemment maison (et pourquoi) ## 2. Ce que Set-OPS fait sciemment maison (et pourquoi)
- **Le plan déclaratif** (`docs/serveurs.yml`, `applications.yml`, `bases-donnees.yml`, - **Le plan déclaratif** (`instance/plan/serveurs.yml`, `applications.yml`, `bases-donnees.yml`,
`domaines.yml`, `nomenclature.yml`) et le **générateur d'inventaire** (`make instancier`). `domaines.yml`, `nomenclature.yml`) et le **générateur d'inventaire** (`make instancier`).
- Le **modèle application-hub** : bindings DSN (portée application/groupe/hôte) et - Le **modèle application-hub** : bindings DSN (portée application/groupe/hôte) et
exposition DNS, taillés exactement pour nos concepts. exposition DNS, taillés exactement pour nos concepts.

View file

@ -738,13 +738,13 @@ Après conversion du modèle, le flux normal passe par `make` et l'API Proxmox.
Les paramètres communs Proxmox sont dans : Les paramètres communs Proxmox sont dans :
```text ```text
inventories/lab/group_vars/proxmox.yml instance/inventories/lab/group_vars/proxmox.yml
``` ```
Les secrets d'API doivent être dans un fichier Vault non versionné : Les secrets d'API doivent être dans un fichier Vault non versionné :
```text ```text
inventories/lab/group_vars/proxmox.vault.yml instance/inventories/lab/group_vars/proxmox.vault.yml
``` ```
Créer le clone et l'ajouter à l'inventaire : Créer le clone et l'ajouter à l'inventaire :

View file

@ -169,9 +169,9 @@ Cette commande limite le playbook au croisement entre le groupe demandé et `hot
## 9. Variables template et conformité ## 9. Variables template et conformité
Les variables du template servent à construire le golden template dans `inventories/lab/group_vars/modeles_vm.yml`. Les variables du template servent à construire le golden template dans `instance/inventories/lab/group_vars/modeles_vm.yml`.
Les variables de conformité servent aux VM déployées dans `inventories/production/group_vars/serveur_debian.yml`. Les variables de conformité servent aux VM déployées dans `instance/inventories/production/group_vars/serveur_debian.yml`.
Différence attendue : Différence attendue :

View file

@ -12,5 +12,5 @@
domaine_interne: "acme.internal" domaine_interne: "acme.internal"
# Le reste de l'identite vit dans le PLAN de l'instance : # Le reste de l'identite vit dans le PLAN de l'instance :
# - docs/nomenclature.yml : supernet (ex. 10.1.0.0/16) + liste de fonctions # - instance/plan/nomenclature.yml : supernet (ex. 10.1.0.0/16) + liste de fonctions
# - docs/serveurs.yml / applications.yml / domaines.yml : le plan rempli # - instance/plan/serveurs.yml / applications.yml / domaines.yml : le plan rempli

View file

@ -13,7 +13,7 @@
tasks: tasks:
# Couche application : une VM dorsale peut porter PLUSIEURS applications. # Couche application : une VM dorsale peut porter PLUSIEURS applications.
# On itere donc sur les applications mappees a cet hote (docs/applications.yml), # On itere donc sur les applications mappees a cet hote (instance/plan/applications.yml),
# chacune resolvant ses bases via son DSN (regle partagee, filter plugin). # chacune resolvant ses bases via son DSN (regle partagee, filter plugin).
- name: Charger les registres applications et bases - name: Charger les registres applications et bases
ansible.builtin.include_vars: ansible.builtin.include_vars:
@ -39,5 +39,5 @@
- name: Avertir si l'hote ne porte aucune application - name: Avertir si l'hote ne porte aucune application
ansible.builtin.debug: ansible.builtin.debug:
msg: "Aucune application declaree sur cet hote (docs/applications.yml). Couche dorsale : API, traitement." msg: "Aucune application declaree sur cet hote (instance/plan/applications.yml). Couche dorsale : API, traitement."
when: applications_hote | length == 0 when: applications_hote | length == 0

View file

@ -13,7 +13,7 @@
tasks: tasks:
# Couche presentation : une VM frontale peut porter PLUSIEURS applications. # Couche presentation : une VM frontale peut porter PLUSIEURS applications.
# On itere sur les applications mappees a cet hote (docs/applications.yml), # On itere sur les applications mappees a cet hote (instance/plan/applications.yml),
# chacune resolvant ses bases via son DSN (regle partagee, filter plugin). # chacune resolvant ses bases via son DSN (regle partagee, filter plugin).
- name: Charger les registres applications et bases - name: Charger les registres applications et bases
ansible.builtin.include_vars: ansible.builtin.include_vars:
@ -39,5 +39,5 @@
- name: Avertir si l'hote ne porte aucune application - name: Avertir si l'hote ne porte aucune application
ansible.builtin.debug: ansible.builtin.debug:
msg: "Aucune application declaree sur cet hote (docs/applications.yml). Couche presentation, derriere serveur_nginx." msg: "Aucune application declaree sur cet hote (instance/plan/applications.yml). Couche presentation, derriere serveur_nginx."
when: applications_hote | length == 0 when: applications_hote | length == 0

View file

@ -28,7 +28,7 @@ python3 -c 'import proxmoxer'
Les paramètres non sensibles sont dans : Les paramètres non sensibles sont dans :
```text ```text
inventories/lab/group_vars/proxmox.yml instance/inventories/lab/group_vars/proxmox.yml
``` ```
Assistant terminal : Assistant terminal :
@ -40,14 +40,14 @@ make config
Les secrets d'API doivent être dans un fichier Vault non versionné : Les secrets d'API doivent être dans un fichier Vault non versionné :
```text ```text
inventories/lab/group_vars/proxmox.vault.yml instance/inventories/lab/group_vars/proxmox.vault.yml
``` ```
Créer le fichier depuis l'exemple, puis le chiffrer : Créer le fichier depuis l'exemple, puis le chiffrer :
```bash ```bash
cp inventories/lab/group_vars/proxmox.vault.yml.example inventories/lab/group_vars/proxmox.vault.yml cp instance/inventories/lab/group_vars/proxmox.vault.yml.example instance/inventories/lab/group_vars/proxmox.vault.yml
ansible-vault encrypt inventories/lab/group_vars/proxmox.vault.yml ansible-vault encrypt instance/inventories/lab/group_vars/proxmox.vault.yml
``` ```
Créer un clone Debian depuis le modèle : Créer un clone Debian depuis le modèle :

View file

@ -10,9 +10,9 @@
ansible.builtin.stat: ansible.builtin.stat:
path: "{{ item }}" path: "{{ item }}"
loop: loop:
- "{{ playbook_dir }}/../../inventories/lab/group_vars/proxmox.yml" - "{{ playbook_dir }}/../../instance/inventories/lab/group_vars/proxmox.yml"
- "{{ playbook_dir }}/../../inventories/lab/group_vars/proxmox.vault.yml" - "{{ playbook_dir }}/../../instance/inventories/lab/group_vars/proxmox.vault.yml"
- "{{ playbook_dir }}/../../inventories/lab/group_vars/proxmox.local.yml" - "{{ playbook_dir }}/../../instance/inventories/lab/group_vars/proxmox.local.yml"
register: proxmox_fichiers_variables register: proxmox_fichiers_variables
- name: Charger les variables Proxmox non sensibles disponibles - name: Charger les variables Proxmox non sensibles disponibles
@ -37,7 +37,7 @@
- name: Expliquer l echec de chargement du Vault - name: Expliquer l echec de chargement du Vault
ansible.builtin.fail: ansible.builtin.fail:
msg: >- msg: >-
Impossible de charger inventories/lab/group_vars/proxmox.vault.yml. Impossible de charger instance/inventories/lab/group_vars/proxmox.vault.yml.
Si le fichier est chiffre avec Ansible Vault, fournir son mot de passe Si le fichier est chiffre avec Ansible Vault, fournir son mot de passe
ou definir ANSIBLE_VAULT_PASSWORD_FILE avant de relancer make creer-vm. ou definir ANSIBLE_VAULT_PASSWORD_FILE avant de relancer make creer-vm.

View file

@ -5,7 +5,7 @@ Forge Git **Forgejo** (binaire officiel) — dépôts Git, CI, revue de code.
## Rôle ## Rôle
- Installe le binaire Forgejo (version épinglée, lien symbolique courant), utilisateur `git`. - Installe le binaire Forgejo (version épinglée, lien symbolique courant), utilisateur `git`.
- Crée l'arborescence (`/var/lib/forgejo`, `/etc/forgejo`). - Crée l'arborescence (`/var/lib/forgejo`, `/etc/forgejo`).
- **Base PostgreSQL via le registre** (`docs/bases-donnees.yml`, entrée `forgejo`). - **Base PostgreSQL via le registre** (`instance/plan/bases-donnees.yml`, entrée `forgejo`).
- `app.ini` : serveur derrière nginx (`HTTP_ADDR=127.0.0.1`, `ROOT_URL` https), DB, secrets, mailer vers `serveur_sendmail`, inscription désactivée, `INSTALL_LOCK` (pas d'assistant web). - `app.ini` : serveur derrière nginx (`HTTP_ADDR=127.0.0.1`, `ROOT_URL` https), DB, secrets, mailer vers `serveur_sendmail`, inscription désactivée, `INSTALL_LOCK` (pas d'assistant web).
- Service systemd + création du **compte administrateur** initial (une fois). - Service systemd + création du **compte administrateur** initial (une fois).

View file

@ -24,7 +24,7 @@
that: that:
- serveur_forgejo_entree.base is defined - serveur_forgejo_entree.base is defined
- serveur_forgejo_entree.secret is defined - serveur_forgejo_entree.secret is defined
fail_msg: "Aucune base avec consommateur '{{ serveur_forgejo_groupe }}' dans docs/bases-donnees.yml." fail_msg: "Aucune base avec consommateur '{{ serveur_forgejo_groupe }}' dans instance/plan/bases-donnees.yml."
- name: Resoudre le mot de passe de base (Vault) - name: Resoudre le mot de passe de base (Vault)
ansible.builtin.set_fact: ansible.builtin.set_fact:

View file

@ -8,7 +8,7 @@ Icinga DB** (avec son Redis dédié et sa base PostgreSQL). **Icinga Web 2 est d
- Ajoute le **dépôt apt officiel Icinga** (trousseau + source signée) et installe - Ajoute le **dépôt apt officiel Icinga** (trousseau + source signée) et installe
`icinga2`, `icingadb`, `icingadb-redis`. `icinga2`, `icingadb`, `icingadb-redis`.
- `icinga2 api setup` + activation de la fonctionnalité `icingadb`. - `icinga2 api setup` + activation de la fonctionnalité `icingadb`.
- **Base PostgreSQL via le registre** (`docs/bases-donnees.yml`, entrée `icingadb`) : - **Base PostgreSQL via le registre** (`instance/plan/bases-donnees.yml`, entrée `icingadb`) :
PostgreSQL crée la base/compte, ce rôle importe le **schéma** et écrit PostgreSQL crée la base/compte, ce rôle importe le **schéma** et écrit
`/etc/icingadb/config.yml` (BD + Redis). `/etc/icingadb/config.yml` (BD + Redis).

View file

@ -39,7 +39,7 @@
that: that:
- serveur_icinga_entree.base is defined - serveur_icinga_entree.base is defined
- serveur_icinga_entree.secret is defined - serveur_icinga_entree.secret is defined
fail_msg: "Aucune base avec consommateur '{{ serveur_icinga_groupe }}' dans docs/bases-donnees.yml." fail_msg: "Aucune base avec consommateur '{{ serveur_icinga_groupe }}' dans instance/plan/bases-donnees.yml."
- name: Resoudre le mot de passe de base (Vault) - name: Resoudre le mot de passe de base (Vault)
ansible.builtin.set_fact: ansible.builtin.set_fact:

View file

@ -5,13 +5,13 @@ SSO / IAM **Keycloak** (distribution Quarkus) — hub d'authentification central
## Rôle ## Rôle
- Installe un JRE, télécharge et extrait la distribution Keycloak dans `/opt/keycloak`. - Installe un JRE, télécharge et extrait la distribution Keycloak dans `/opt/keycloak`.
- Configure la **base PostgreSQL via le registre** `docs/bases-donnees.yml` (entrée `keycloak`). - Configure la **base PostgreSQL via le registre** `instance/plan/bases-donnees.yml` (entrée `keycloak`).
- Publie derrière `serveur_nginx` (TLS à l'edge) : `hostname`, `proxy-headers=xforwarded`, `http-enabled=true`. - Publie derrière `serveur_nginx` (TLS à l'edge) : `hostname`, `proxy-headers=xforwarded`, `http-enabled=true`.
- Secrets (mot de passe BD + admin bootstrap) dans `/etc/keycloak/keycloak.env` (`0640`, `no_log`). - Secrets (mot de passe BD + admin bootstrap) dans `/etc/keycloak/keycloak.env` (`0640`, `no_log`).
- `kc.sh build --db=postgres` (une fois par version) puis service systemd `start --optimized`. - `kc.sh build --db=postgres` (une fois par version) puis service systemd `start --optimized`.
## Premier consommateur du registre de BD ## Premier consommateur du registre de BD
L'entrée `keycloak` de `docs/bases-donnees.yml` fait que : L'entrée `keycloak` de `instance/plan/bases-donnees.yml` fait que :
1. `serveur_postgresql` crée la base `keycloak` + le compte propriétaire `keycloak`. 1. `serveur_postgresql` crée la base `keycloak` + le compte propriétaire `keycloak`.
2. Ce rôle lit **la même entrée** pour bâtir sa connexion (`db-url-database`, `db-username`, mot de passe = `vault_bd_keycloak`). 2. Ce rôle lit **la même entrée** pour bâtir sa connexion (`db-url-database`, `db-username`, mot de passe = `vault_bd_keycloak`).

View file

@ -23,7 +23,7 @@
- serveur_keycloak_entree.base is defined - serveur_keycloak_entree.base is defined
- serveur_keycloak_entree.proprietaire is defined - serveur_keycloak_entree.proprietaire is defined
- serveur_keycloak_entree.secret is defined - serveur_keycloak_entree.secret is defined
fail_msg: "Aucune base avec consommateur '{{ serveur_keycloak_groupe }}' dans docs/bases-donnees.yml." fail_msg: "Aucune base avec consommateur '{{ serveur_keycloak_groupe }}' dans instance/plan/bases-donnees.yml."
- name: Resoudre le mot de passe de base de donnees (Vault) - name: Resoudre le mot de passe de base de donnees (Vault)
ansible.builtin.set_fact: ansible.builtin.set_fact:

View file

@ -20,7 +20,7 @@ serveur_nginx_redirection_http: true # 80 -> 443
serveur_nginx_desactiver_defaut: false # retirer le site Debian par defaut serveur_nginx_desactiver_defaut: false # retirer le site Debian par defaut
# Sites de reverse proxy declares a la main. Vide par defaut. # Sites de reverse proxy declares a la main. Vide par defaut.
# S'AJOUTENT aux vhosts derives automatiquement de docs/domaines.yml. # S'AJOUTENT aux vhosts derives automatiquement de instance/plan/domaines.yml.
serveur_nginx_sites: [] serveur_nginx_sites: []
# - nom: forge # - nom: forge
# domaine: forge.{{ domaine_interne }} # domaine: forge.{{ domaine_interne }}
@ -29,10 +29,10 @@ serveur_nginx_sites: []
# cle: "/etc/ssl/.../forge.key" # cle: "/etc/ssl/.../forge.key"
# Groupe edge auquel ce role s'identifie (pour filtrer le champ "edge" de # Groupe edge auquel ce role s'identifie (pour filtrer le champ "edge" de
# docs/domaines.yml). Permet plusieurs edges distincts a terme. # instance/plan/domaines.yml). Permet plusieurs edges distincts a terme.
serveur_nginx_groupe: "serveur_nginx" serveur_nginx_groupe: "serveur_nginx"
# Deriver automatiquement des vhosts depuis docs/domaines.yml (bloc "exposition"). # Deriver automatiquement des vhosts depuis instance/plan/domaines.yml (bloc "exposition").
# Pour chaque exposition de type "web" dont l'edge vise ce groupe, un vhost est # Pour chaque exposition de type "web" dont l'edge vise ce groupe, un vhost est
# genere : amont = entree "amont" explicite, sinon http://<IP interne de la # genere : amont = entree "amont" explicite, sinon http://<IP interne de la
# cible>:<port>. Une exposition non resolvable (cible sans hote actif, ou sans # cible>:<port>. Une exposition non resolvable (cible sans hote actif, ou sans

View file

@ -1,5 +1,5 @@
# Vhosts derives des applications (champ 'expose' de docs/applications.yml, # Vhosts derives des applications (champ 'expose' de instance/plan/applications.yml,
# edge depuis docs/domaines.yml) — gere par Set-OPS (role serveur_nginx). # edge depuis instance/plan/domaines.yml) — gere par Set-OPS (role serveur_nginx).
# Ne pas editer a la main. # Ne pas editer a la main.
# #
# Un FQDN expose produit un vhost si l'hote de l'application est resolvable : # Un FQDN expose produit un vhost si l'hote de l'application est resolvable :

View file

@ -41,12 +41,12 @@ serveur_postgresql_bases:
``` ```
## Registre partagé des bases applicatives ## Registre partagé des bases applicatives
En plus des listes explicites, le rôle lit **`docs/bases-donnees.yml`** (registre En plus des listes explicites, le rôle lit **`instance/plan/bases-donnees.yml`** (registre
déclaratif) et crée chaque base + son compte propriétaire dont `serveur` vaut déclaratif) et crée chaque base + son compte propriétaire dont `serveur` vaut
`serveur_postgresql`. Le mot de passe vient de la variable Vault nommée par le `serveur_postgresql`. Le mot de passe vient de la variable Vault nommée par le
champ `secret`. Le rôle applicatif lit le même registre pour bâtir sa chaîne de champ `secret`. Le rôle applicatif lit le même registre pour bâtir sa chaîne de
connexion — secret partagé, source unique. Patron : 1 appli → 1 base → 1 owner → connexion — secret partagé, source unique. Patron : 1 appli → 1 base → 1 owner →
1 chaîne de connexion. Voir l'en-tête de `docs/bases-donnees.yml`. 1 chaîne de connexion. Voir l'en-tête de `instance/plan/bases-donnees.yml`.
## Prérequis ## Prérequis
- Collection `community.postgresql` (`ansible-galaxy collection install community.postgresql`). - Collection `community.postgresql` (`ansible-galaxy collection install community.postgresql`).

View file

@ -24,7 +24,7 @@ serveur_postgresql_methode_auth: "scram-sha-256"
serveur_postgresql_parametres: {} serveur_postgresql_parametres: {}
# Nom du groupe serveur (pour filtrer le registre des bases applicatives). # Nom du groupe serveur (pour filtrer le registre des bases applicatives).
# Le registre lui-meme (bases_donnees) est charge depuis docs/bases-donnees.yml. # Le registre lui-meme (bases_donnees) est charge depuis instance/plan/bases-donnees.yml.
serveur_postgresql_groupe: "serveur_postgresql" serveur_postgresql_groupe: "serveur_postgresql"
# Provisioning applicatif explicite. Vide par defaut : aucune base ni compte cree. # Provisioning applicatif explicite. Vide par defaut : aucune base ni compte cree.

View file

@ -91,7 +91,7 @@
label: "{{ item.nom }}" label: "{{ item.nom }}"
when: serveur_postgresql_bases | length > 0 when: serveur_postgresql_bases | length > 0
# --- Provisioning depuis le registre partage docs/bases-donnees.yml --- # --- Provisioning depuis le registre partage instance/plan/bases-donnees.yml ---
- name: Charger le registre des bases applicatives - name: Charger le registre des bases applicatives
ansible.builtin.include_vars: ansible.builtin.include_vars:

View file

@ -18,7 +18,7 @@ serveur_step_ca_password: "{{ vault_step_ca_password }}"
serveur_step_ca_provisioner_password: "{{ vault_step_ca_provisioner_password }}" serveur_step_ca_provisioner_password: "{{ vault_step_ca_provisioner_password }}"
``` ```
À placer dans `inventories/production/group_vars/serveur_step_ca/vault.yml` (chiffré), À placer dans `instance/inventories/production/group_vars/serveur_step_ca/vault.yml` (chiffré),
les variables en clair référençant ces secrets dans `.../serveur_step_ca/main.yml`. les variables en clair référençant ces secrets dans `.../serveur_step_ca/main.yml`.
## Variables principales ## Variables principales

View file

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Lit et valide le registre des applications Set-OPS (docs/applications.yml).""" """Lit et valide le registre des applications Set-OPS (instance/plan/applications.yml)."""
from __future__ import annotations from __future__ import annotations
@ -130,7 +130,7 @@ def main() -> int:
registre = bootstrap(registre) registre = bootstrap(registre)
valider_applications(registre, domaines) valider_applications(registre, domaines)
ecrire(registre) ecrire(registre)
print(f"docs/applications.yml genere depuis l'inventaire ({len(registre['applications'])} applications).") print(f"instance/plan/applications.yml genere depuis l'inventaire ({len(registre['applications'])} applications).")
elif args.commande == "ajouter": elif args.commande == "ajouter":
app = {"groupe": args.groupe, "hote": args.hote} app = {"groupe": args.groupe, "hote": args.hote}
if args.port is not None: if args.port is not None:

View file

@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Lit et valide le registre des domaines publics Set-OPS (docs/domaines.yml).""" """Lit et valide le registre des domaines publics Set-OPS (instance/plan/domaines.yml)."""
from __future__ import annotations from __future__ import annotations

View file

@ -7,7 +7,7 @@ bascule tant que la comparaison n'est pas vide et validee.
Derivation : Derivation :
- host vars : ansible_host/ansible_user + proxmox_* (IP/VMID/VLAN/passerelle - host vars : ansible_host/ansible_user + proxmox_* (IP/VMID/VLAN/passerelle
derives de la nomenclature ; placement/taille depuis docs/serveurs.yml) ; derives de la nomenclature ; placement/taille depuis instance/plan/serveurs.yml) ;
- groupes : socle (serveur_debian/durcis) + groupes de service derives des - groupes : socle (serveur_debian/durcis) + groupes de service derives des
applications de l'hote + groupe d'etat (hotes_actifs/hotes_planifies). applications de l'hote + groupe d'etat (hotes_actifs/hotes_planifies).
- Les integrations clients_* ne sont PAS derivables du plan a ce stade : la - Les integrations clients_* ne sont PAS derivables du plan a ce stade : la
@ -85,8 +85,8 @@ def generer() -> dict:
def ecrire(path: Path = GENERE) -> None: def ecrire(path: Path = GENERE) -> None:
entete = ("# Inventaire GENERE depuis le plan (make instancier / instancier-appliquer).\n" entete = ("# Inventaire GENERE depuis le plan (make instancier / instancier-appliquer).\n"
"# NE PAS editer a la main : edite docs/serveurs.yml + docs/applications.yml.\n" "# NE PAS editer a la main : edite instance/plan/serveurs.yml + instance/plan/applications.yml.\n"
"# Source : docs/serveurs.yml + docs/applications.yml + docs/nomenclature.yml.\n") "# Source : instance/plan/serveurs.yml + instance/plan/applications.yml + instance/plan/nomenclature.yml.\n")
with path.open("w", encoding="utf-8") as fichier: with path.open("w", encoding="utf-8") as fichier:
fichier.write(entete) fichier.write(entete)
yaml.safe_dump(generer(), fichier, default_flow_style=False, sort_keys=True, allow_unicode=True) yaml.safe_dump(generer(), fichier, default_flow_style=False, sort_keys=True, allow_unicode=True)

View file

@ -247,7 +247,7 @@ def ecrire_serveurs(path: Path, registre: dict) -> None:
entete = ( entete = (
"# Registre des serveurs (VM) du plan Set-OPS.\n" "# Registre des serveurs (VM) du plan Set-OPS.\n"
"# Edite par make inventaire-ui ou scripts/serveurs.py.\n" "# Edite par make inventaire-ui ou scripts/serveurs.py.\n"
"# VMID/IP/VLAN/passerelle sont DERIVES de la fonction via docs/nomenclature.yml.\n" "# VMID/IP/VLAN/passerelle sont DERIVES de la fonction via instance/plan/nomenclature.yml.\n"
"---\n" "---\n"
) )
with path.open("w", encoding="utf-8") as fichier: with path.open("w", encoding="utf-8") as fichier:
@ -1570,7 +1570,7 @@ class Gestionnaire(BaseHTTPRequestHandler):
try: try:
if chemin == "/api/inventaire": if chemin == "/api/inventaire":
self.repondre_json(409, {"erreur": "hosts.yml est genere depuis le plan. " self.repondre_json(409, {"erreur": "hosts.yml est genere depuis le plan. "
"Edite docs/serveurs.yml et docs/applications.yml " "Edite instance/plan/serveurs.yml et instance/plan/applications.yml "
"(vues Serveurs / Applications), puis « Appliquer le plan »."}) "(vues Serveurs / Applications), puis « Appliquer le plan »."})
elif chemin == "/api/bases": elif chemin == "/api/bases":
valider_bases(donnees, charger_applications(FICHIER_APPLICATIONS)) valider_bases(donnees, charger_applications(FICHIER_APPLICATIONS))

View file

@ -75,7 +75,7 @@ def valider_bases(registre: dict, applications: dict | None = None) -> None:
if portee == "groupe" and not est_groupe_operationnel(base["consommateur"]): if portee == "groupe" and not est_groupe_operationnel(base["consommateur"]):
raise ValueError(f"Base '{cle}': portee groupe mais consommateur '{base['consommateur']}' non operationnel.") raise ValueError(f"Base '{cle}': portee groupe mais consommateur '{base['consommateur']}' non operationnel.")
if portee == "application" and apps and base["consommateur"] not in apps: if portee == "application" and apps and base["consommateur"] not in apps:
raise ValueError(f"Base '{cle}': application consommatrice '{base['consommateur']}' inconnue (docs/applications.yml).") raise ValueError(f"Base '{cle}': application consommatrice '{base['consommateur']}' inconnue (instance/plan/applications.yml).")
couple = f"{base['serveur']}/{base['base']}" couple = f"{base['serveur']}/{base['base']}"
if couple in noms_bases: if couple in noms_bases:
raise ValueError(f"Base en double sur un meme serveur: {couple}") raise ValueError(f"Base en double sur un meme serveur: {couple}")

View file

@ -41,7 +41,7 @@ def ecrire(registre: dict) -> None:
"# Registre des serveurs (VM) du plan Set-OPS.\n" "# Registre des serveurs (VM) du plan Set-OPS.\n"
"# Bootstrape depuis l'inventaire (make serveurs-bootstrap). L'inventaire\n" "# Bootstrape depuis l'inventaire (make serveurs-bootstrap). L'inventaire\n"
"# reste autorite en Phase 2 ; VMID/IP/VLAN/passerelle sont DERIVES de la\n" "# reste autorite en Phase 2 ; VMID/IP/VLAN/passerelle sont DERIVES de la\n"
"# fonction via docs/nomenclature.yml (non stockes ici).\n" "# fonction via instance/plan/nomenclature.yml (non stockes ici).\n"
"---\n" "---\n"
) )
with FICHIER.open("w", encoding="utf-8") as fichier: with FICHIER.open("w", encoding="utf-8") as fichier:
@ -115,7 +115,7 @@ def main() -> int:
sub = parser.add_subparsers(dest="commande", required=True) sub = parser.add_subparsers(dest="commande", required=True)
sub.add_parser("lister", help="Affiche les serveurs et leur reconciliation avec l'inventaire.") sub.add_parser("lister", help="Affiche les serveurs et leur reconciliation avec l'inventaire.")
sub.add_parser("verifier", help="Valide le registre et signale les divergences.") sub.add_parser("verifier", help="Valide le registre et signale les divergences.")
sub.add_parser("bootstrap", help="(Re)genere docs/serveurs.yml depuis l'inventaire actuel.") sub.add_parser("bootstrap", help="(Re)genere instance/plan/serveurs.yml depuis l'inventaire actuel.")
args = parser.parse_args() args = parser.parse_args()
try: try:
@ -127,7 +127,7 @@ def main() -> int:
registre = bootstrap() registre = bootstrap()
valider_serveurs(registre, charger_nomenclature(FICHIER_NOMENCLATURE)) valider_serveurs(registre, charger_nomenclature(FICHIER_NOMENCLATURE))
ecrire(registre) ecrire(registre)
print(f"docs/serveurs.yml genere depuis l'inventaire ({len(registre['serveurs'])} serveurs).") print(f"instance/plan/serveurs.yml genere depuis l'inventaire ({len(registre['serveurs'])} serveurs).")
except Exception as exc: except Exception as exc:
print(f"erreur: {exc}", file=sys.stderr) print(f"erreur: {exc}", file=sys.stderr)
return 2 return 2