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
|
## 2026-06-30
|
||||||
|
|
||||||
### Ajouté
|
### 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
|
- **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
|
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
|
*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 ANSIBLE_SSH_ARGS ?= -F /dev/null -o ControlMaster=no
|
||||||
|
|
||||||
export SETOPS_INSTANCE ?= instance
|
export SETOPS_INSTANCE ?= instance
|
||||||
INVENTAIRE_LAB ?= $(SETOPS_INSTANCE)/inventories/lab/hosts.yml
|
# Inventaire de l'instance : un seul par instance dans le modèle « séparation par
|
||||||
INVENTAIRE_PRODUCTION ?= $(SETOPS_INSTANCE)/inventories/production/hosts.yml
|
# instance ». Détection rétro-compatible : principal > production > lab.
|
||||||
FICHIER_INVENTAIRE ?= $(INVENTAIRE_PRODUCTION)
|
# 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
|
FICHIER_DEPENDANCES ?= docs/dependances-groupes.yml
|
||||||
GROUPE_MODELE ?= modeles_vm
|
GROUPE_MODELE ?= modeles_vm
|
||||||
GROUPE_DEBIAN ?= serveur_debian
|
GROUPE_DEBIAN ?= serveur_debian
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,18 @@ INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
||||||
FICHIER = INSTANCE / "plan/applications.yml"
|
FICHIER = INSTANCE / "plan/applications.yml"
|
||||||
FICHIER_BASES = INSTANCE / "plan/bases-donnees.yml"
|
FICHIER_BASES = INSTANCE / "plan/bases-donnees.yml"
|
||||||
FICHIER_DOMAINES = INSTANCE / "plan/domaines.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),
|
# Groupes 'serveurs_*' qui sont des capacites de SOCLE (sur toutes les VM),
|
||||||
# pas des applications a part entiere.
|
# pas des applications a part entiere.
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,25 @@ import yaml
|
||||||
|
|
||||||
RACINE = Path(__file__).resolve().parents[1]
|
RACINE = Path(__file__).resolve().parents[1]
|
||||||
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
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.
|
def _inventaire_dir(instance: Path, *noms: str) -> Path:
|
||||||
FICHIER_VAULT = INSTANCE / "inventories/lab/group_vars/all/vault.yml"
|
"""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"
|
GABARIT_VAULT = RACINE / "exemples/vault.exemple.yml"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Generateur d'inventaire Set-OPS (Phase 3) : plan -> hosts.yml.
|
"""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
|
SEMANTIQUEMENT (via ansible-inventory --list) avec l'inventaire actuel. Aucune
|
||||||
bascule tant que la comparaison n'est pas vide et validee.
|
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]
|
RACINE = Path(__file__).resolve().parents[1]
|
||||||
ROLES = RACINE / "roles"
|
ROLES = RACINE / "roles"
|
||||||
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
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_SERVEURS = INSTANCE / "plan/serveurs.yml"
|
||||||
FICHIER_APPLICATIONS = INSTANCE / "plan/applications.yml"
|
FICHIER_APPLICATIONS = INSTANCE / "plan/applications.yml"
|
||||||
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,24 @@ from inventory_rules import (
|
||||||
|
|
||||||
RACINE = Path(__file__).resolve().parents[1]
|
RACINE = Path(__file__).resolve().parents[1]
|
||||||
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
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"
|
DOSSIER_PLAYBOOKS_GROUPES = RACINE / "playbooks/groupes"
|
||||||
FICHIER_DEPENDANCES = RACINE / "docs/dependances-groupes.yml"
|
FICHIER_DEPENDANCES = RACINE / "docs/dependances-groupes.yml"
|
||||||
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.yml"
|
||||||
|
|
@ -49,11 +65,11 @@ FICHIER_DOMAINES = INSTANCE / "plan/domaines.yml"
|
||||||
FICHIER_SERVEURS = INSTANCE / "plan/serveurs.yml"
|
FICHIER_SERVEURS = INSTANCE / "plan/serveurs.yml"
|
||||||
|
|
||||||
# Intrants de base (panneau GUI). Cibles d'ecriture possedees par le GUI.
|
# Intrants de base (panneau GUI). Cibles d'ecriture possedees par le GUI.
|
||||||
# Identite : source UNIQUE partagee par tous les envs (symlink depuis chaque
|
# Identite : source UNIQUE partagee (symlink depuis group_vars/all/). Proxmox :
|
||||||
# group_vars/all/). Proxmox : fichier lab (le clonage le lit en dur), cles gerees
|
# group_vars de l'inventaire modele, cles gerees mises a jour, autres preservees.
|
||||||
# mises a jour, les autres cles preservees. Les SECRETS n'y entrent jamais.
|
# Les SECRETS n'y entrent jamais.
|
||||||
INTRANTS_IDENTITE = INSTANCE / "inventories/partage/intrants-identite.yml"
|
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}
|
FICHIERS_INTRANTS = {"identite": INTRANTS_IDENTITE, "proxmox": INTRANTS_PROXMOX}
|
||||||
|
|
||||||
# (variable, fichier, classe, section, libelle, type)
|
# (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"))
|
INSTANCE = Path(os.environ.get("SETOPS_INSTANCE") or (RACINE / "instance"))
|
||||||
FICHIER = INSTANCE / "plan/serveurs.yml"
|
FICHIER = INSTANCE / "plan/serveurs.yml"
|
||||||
FICHIER_NOMENCLATURE = INSTANCE / "plan/nomenclature.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 de placement / dimensionnement NON derivables (proviennent du plan).
|
||||||
CHAMPS_PLAN = [("noeud", "noeud"), ("stockage", "stockage"),
|
CHAMPS_PLAN = [("noeud", "noeud"), ("stockage", "stockage"),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue