Inventaire d'instance neutre et configurable (principal / SETOPS_INVENTAIRE)
Le moteur ne code plus en dur inventories/lab|production : un inventaire par instance, détecté de façon rétro-compatible (principal > production > lab) et surchargeable par SETOPS_INVENTAIRE. Makefile (définitions seules, pas les 47 usages), inventory_gui, instancier, config_proxmox, serveurs, applications. Les instances lab/production existantes marchent à l'identique ; les nouvelles adoptent inventories/principal/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
8b3648e9f9
commit
e2b924cedc
7 changed files with 98 additions and 18 deletions
|
|
@ -3,6 +3,14 @@
|
|||
## 2026-06-30
|
||||
|
||||
### Ajouté
|
||||
- **Inventaire d'instance neutre et configurable (`principal` / `SETOPS_INVENTAIRE`).**
|
||||
Le moteur (Makefile + `inventory_gui`, `instancier`, `config_proxmox`, `serveurs`,
|
||||
`applications`) ne code plus en dur `inventories/lab` / `inventories/production` :
|
||||
il vise **un inventaire par instance**, détecté de façon **rétro-compatible**
|
||||
(`principal` > `production` > `lab`) et surchargeable par `SETOPS_INVENTAIRE`. Les
|
||||
instances existantes (découpage lab/production) continuent de fonctionner à
|
||||
l'identique ; les nouvelles peuvent adopter `inventories/principal/`. Deuxième pierre
|
||||
de la séparation **par instance** (la 1re étant le drapeau `setops_production`).
|
||||
- **Garde-fou de déploiement par instance (`setops_production`).** Le droit de
|
||||
déployer pour de vrai (GUI Vérifier/Déployer, `executer_flux`) ne dépend plus du
|
||||
*nom* de l'inventaire mais d'un drapeau explicite `setops_production` dans
|
||||
|
|
|
|||
12
Makefile
12
Makefile
|
|
@ -6,9 +6,15 @@ export ANSIBLE_SSH_CONTROL_PATH_DIR ?= $(CURDIR)/.ansible/cp
|
|||
export ANSIBLE_SSH_ARGS ?= -F /dev/null -o ControlMaster=no
|
||||
|
||||
export SETOPS_INSTANCE ?= instance
|
||||
INVENTAIRE_LAB ?= $(SETOPS_INSTANCE)/inventories/lab/hosts.yml
|
||||
INVENTAIRE_PRODUCTION ?= $(SETOPS_INSTANCE)/inventories/production/hosts.yml
|
||||
FICHIER_INVENTAIRE ?= $(INVENTAIRE_PRODUCTION)
|
||||
# Inventaire de l'instance : un seul par instance dans le modèle « séparation par
|
||||
# instance ». Détection rétro-compatible : principal > production > lab.
|
||||
# Surchargeable : make … SETOPS_INVENTAIRE=chemin/hosts.yml
|
||||
SETOPS_INVENTAIRE ?= $(firstword $(wildcard $(SETOPS_INSTANCE)/inventories/principal/hosts.yml) $(wildcard $(SETOPS_INSTANCE)/inventories/production/hosts.yml) $(SETOPS_INSTANCE)/inventories/principal/hosts.yml)
|
||||
export SETOPS_INVENTAIRE
|
||||
# Inventaire « modèle » (construction du golden template) : lab > principal > production.
|
||||
INVENTAIRE_LAB ?= $(firstword $(wildcard $(SETOPS_INSTANCE)/inventories/lab/hosts.yml) $(wildcard $(SETOPS_INSTANCE)/inventories/principal/hosts.yml) $(SETOPS_INSTANCE)/inventories/production/hosts.yml)
|
||||
INVENTAIRE_PRODUCTION ?= $(SETOPS_INVENTAIRE)
|
||||
FICHIER_INVENTAIRE ?= $(SETOPS_INVENTAIRE)
|
||||
FICHIER_DEPENDANCES ?= docs/dependances-groupes.yml
|
||||
GROUPE_MODELE ?= modeles_vm
|
||||
GROUPE_DEBIAN ?= serveur_debian
|
||||
|
|
|
|||
|
|
@ -26,7 +26,18 @@ INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
|||
FICHIER = INSTANCE / "plan/applications.yml"
|
||||
FICHIER_BASES = INSTANCE / "plan/bases-donnees.yml"
|
||||
FICHIER_DOMAINES = INSTANCE / "plan/domaines.yml"
|
||||
INVENTAIRE = INSTANCE / "inventories/production/hosts.yml"
|
||||
def _inventaire(instance: Path, *noms: str) -> Path:
|
||||
forced = os.environ.get("SETOPS_INVENTAIRE")
|
||||
if forced:
|
||||
return Path(forced)
|
||||
for nom in noms:
|
||||
p = instance / "inventories" / nom / "hosts.yml"
|
||||
if p.exists():
|
||||
return p
|
||||
return instance / "inventories" / noms[0] / "hosts.yml"
|
||||
|
||||
|
||||
INVENTAIRE = _inventaire(INSTANCE, "principal", "production")
|
||||
|
||||
# Groupes 'serveurs_*' qui sont des capacites de SOCLE (sur toutes les VM),
|
||||
# pas des applications a part entiere.
|
||||
|
|
|
|||
|
|
@ -14,10 +14,25 @@ import yaml
|
|||
|
||||
RACINE = Path(__file__).resolve().parents[1]
|
||||
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
||||
FICHIER_PROXMOX = INSTANCE / "inventories/lab/group_vars/proxmox.yml"
|
||||
# Voûte UNIQUE de l'environnement : tous les secrets (token Proxmox + vault_*) au
|
||||
# même endroit, un seul mot de passe. Gabarit : exemples/vault.exemple.yml.
|
||||
FICHIER_VAULT = INSTANCE / "inventories/lab/group_vars/all/vault.yml"
|
||||
|
||||
|
||||
def _inventaire_dir(instance: Path, *noms: str) -> Path:
|
||||
"""Répertoire de l'inventaire modèle (porte la config Proxmox / le clonage)."""
|
||||
forced = os.environ.get("SETOPS_INVENTAIRE")
|
||||
if forced:
|
||||
return Path(forced).parent
|
||||
for nom in noms:
|
||||
d = instance / "inventories" / nom
|
||||
if (d / "hosts.yml").exists():
|
||||
return d
|
||||
return instance / "inventories" / noms[0]
|
||||
|
||||
|
||||
_INV_DIR = _inventaire_dir(INSTANCE, "lab", "principal", "production")
|
||||
FICHIER_PROXMOX = _INV_DIR / "group_vars/proxmox.yml"
|
||||
# Voûte UNIQUE de l'instance : tous les secrets (token Proxmox + vault_*) au même
|
||||
# endroit, un seul mot de passe. Gabarit : exemples/vault.exemple.yml.
|
||||
FICHIER_VAULT = _INV_DIR / "group_vars/all/vault.yml"
|
||||
GABARIT_VAULT = RACINE / "exemples/vault.exemple.yml"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generateur d'inventaire Set-OPS (Phase 3) : plan -> hosts.yml.
|
||||
|
||||
NON destructif : ecrit dans instance/inventories/production/hosts.genere.yml et compare
|
||||
NON destructif : ecrit hosts.genere.yml a cote de l'inventaire de l'instance et compare
|
||||
SEMANTIQUEMENT (via ansible-inventory --list) avec l'inventaire actuel. Aucune
|
||||
bascule tant que la comparaison n'est pas vide et validee.
|
||||
|
||||
|
|
@ -37,8 +37,21 @@ from inventory_rules import (
|
|||
RACINE = Path(__file__).resolve().parents[1]
|
||||
ROLES = RACINE / "roles"
|
||||
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
||||
INVENTAIRE = INSTANCE / "inventories/production/hosts.yml"
|
||||
GENERE = INSTANCE / "inventories/production/hosts.genere.yml"
|
||||
|
||||
|
||||
def _inventaire(instance: Path, *noms: str) -> Path:
|
||||
for nom in noms:
|
||||
p = instance / "inventories" / nom / "hosts.yml"
|
||||
if p.exists():
|
||||
return p
|
||||
return instance / "inventories" / noms[0] / "hosts.yml"
|
||||
|
||||
|
||||
# Inventaire unique de l'instance (rétro-compat : principal > production).
|
||||
# SETOPS_INVENTAIRE force la cible.
|
||||
_force = os.environ.get("SETOPS_INVENTAIRE")
|
||||
INVENTAIRE = Path(_force) if _force else _inventaire(INSTANCE, "principal", "production")
|
||||
GENERE = INVENTAIRE.with_name("hosts.genere.yml")
|
||||
FICHIER_SERVEURS = INSTANCE / "plan/serveurs.yml"
|
||||
FICHIER_APPLICATIONS = INSTANCE / "plan/applications.yml"
|
||||
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
||||
|
|
|
|||
|
|
@ -38,8 +38,24 @@ from inventory_rules import (
|
|||
|
||||
RACINE = Path(__file__).resolve().parents[1]
|
||||
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
||||
INVENTAIRE_DEFAUT = INSTANCE / "inventories/production/hosts.yml"
|
||||
INVENTAIRE_PRODUCTION = (INSTANCE / "inventories/production/hosts.yml").resolve()
|
||||
|
||||
|
||||
def _inventaire(instance: Path, *noms: str) -> Path:
|
||||
"""Inventaire de l'instance, détection rétro-compatible (premier existant)."""
|
||||
for nom in noms:
|
||||
p = instance / "inventories" / nom / "hosts.yml"
|
||||
if p.exists():
|
||||
return p
|
||||
return instance / "inventories" / noms[0] / "hosts.yml"
|
||||
|
||||
|
||||
# Un seul inventaire par instance (modèle « séparation par instance ») ; on accepte
|
||||
# l'ancien découpage lab/production en rétro-compatibilité. SETOPS_INVENTAIRE force.
|
||||
_force = os.environ.get("SETOPS_INVENTAIRE")
|
||||
INVENTAIRE_DEFAUT = Path(_force) if _force else _inventaire(INSTANCE, "principal", "production")
|
||||
INVENTAIRE_PRODUCTION = INVENTAIRE_DEFAUT.resolve()
|
||||
# Inventaire qui porte la config Proxmox / le clonage (modèle) : lab > principal > production.
|
||||
INVENTAIRE_MODELE = _inventaire(INSTANCE, "lab", "principal", "production")
|
||||
DOSSIER_PLAYBOOKS_GROUPES = RACINE / "playbooks/groupes"
|
||||
FICHIER_DEPENDANCES = RACINE / "docs/dependances-groupes.yml"
|
||||
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
||||
|
|
@ -49,11 +65,11 @@ FICHIER_DOMAINES = INSTANCE / "plan/domaines.yml"
|
|||
FICHIER_SERVEURS = INSTANCE / "plan/serveurs.yml"
|
||||
|
||||
# Intrants de base (panneau GUI). Cibles d'ecriture possedees par le GUI.
|
||||
# Identite : source UNIQUE partagee par tous les envs (symlink depuis chaque
|
||||
# group_vars/all/). Proxmox : fichier lab (le clonage le lit en dur), cles gerees
|
||||
# mises a jour, les autres cles preservees. Les SECRETS n'y entrent jamais.
|
||||
# Identite : source UNIQUE partagee (symlink depuis group_vars/all/). Proxmox :
|
||||
# group_vars de l'inventaire modele, cles gerees mises a jour, autres preservees.
|
||||
# Les SECRETS n'y entrent jamais.
|
||||
INTRANTS_IDENTITE = INSTANCE / "inventories/partage/intrants-identite.yml"
|
||||
INTRANTS_PROXMOX = INSTANCE / "inventories/lab/group_vars/proxmox.yml"
|
||||
INTRANTS_PROXMOX = INVENTAIRE_MODELE.parent / "group_vars/proxmox.yml"
|
||||
FICHIERS_INTRANTS = {"identite": INTRANTS_IDENTITE, "proxmox": INTRANTS_PROXMOX}
|
||||
|
||||
# (variable, fichier, classe, section, libelle, type)
|
||||
|
|
|
|||
|
|
@ -29,7 +29,18 @@ RACINE = Path(__file__).resolve().parents[1]
|
|||
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
||||
FICHIER = INSTANCE / "plan/serveurs.yml"
|
||||
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
||||
INVENTAIRE = INSTANCE / "inventories/production/hosts.yml"
|
||||
def _inventaire(instance: Path, *noms: str) -> Path:
|
||||
forced = os.environ.get("SETOPS_INVENTAIRE")
|
||||
if forced:
|
||||
return Path(forced)
|
||||
for nom in noms:
|
||||
p = instance / "inventories" / nom / "hosts.yml"
|
||||
if p.exists():
|
||||
return p
|
||||
return instance / "inventories" / noms[0] / "hosts.yml"
|
||||
|
||||
|
||||
INVENTAIRE = _inventaire(INSTANCE, "principal", "production")
|
||||
|
||||
# Champs de placement / dimensionnement NON derivables (proviennent du plan).
|
||||
CHAMPS_PLAN = [("noeud", "noeud"), ("stockage", "stockage"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue