Le modele derive l'adressage par tenant (VLAN 1000+index*10+zone), mais la fabric physique qui porte la flotte (mgmt switches/Proxmox/OOB, iSCSI, Ceph public+cluster) n'appartient a aucun tenant. Elle est desormais codifiee. - scripts/underlay.py + make underlay : charge/affiche/valide underlay.yml (VLAN < 1000, sous-reseaux hors des supernets tenant 10.(10+index).0.0/16). - underlay.yml gitignore (comme le vault) ; gabarit public underlay.yml.example ; surchargeable par SETOPS_UNDERLAY. - devis_reseau : section 0. Underlay + VLAN underlay sur le trunk, selon dialecte. - P23 : underlay.py --verifier ; sautee si underlay.yml absent (comme P16 sans vault). 23/23 preuves. Doc : docs/audit/README.md, wiki page reseau, CHANGELOG. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
697 lines
29 KiB
Makefile
697 lines
29 KiB
Makefile
SHELL := /usr/bin/env bash
|
|
|
|
export ANSIBLE_HOME ?= $(CURDIR)/.ansible
|
|
export ANSIBLE_LOCAL_TEMP ?= $(CURDIR)/.ansible/tmp
|
|
export ANSIBLE_SSH_CONTROL_PATH_DIR ?= $(CURDIR)/.ansible/cp
|
|
export ANSIBLE_SSH_ARGS ?= -F /dev/null -o ControlMaster=no
|
|
|
|
export SETOPS_INSTANCE ?= instance
|
|
# 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
|
|
GROUPE_HOTES_ACTIFS ?= hotes_actifs
|
|
LIMITE ?= $(GROUPE_DEBIAN)
|
|
HOTE ?=
|
|
ADRESSE_IP ?=
|
|
GROUPES ?= $(GROUPE_DEBIAN)
|
|
GROUPE ?= $(GROUPE_DEBIAN)
|
|
UTILISATEUR_ANSIBLE ?= ansible
|
|
VMID_MODELE ?=
|
|
VMID ?=
|
|
NOEUD_PROXMOX ?=
|
|
STOCKAGE_PROXMOX ?=
|
|
FORMAT_DISQUE ?=
|
|
TAILLE_DISQUE ?=
|
|
DISQUE_PROXMOX ?=
|
|
CIDR ?= 24
|
|
PASSERELLE ?=
|
|
DNS ?=
|
|
DHCP ?= false
|
|
CIUSER ?=
|
|
CLE_SSH_PUBLIQUE ?=
|
|
PONT_PROXMOX ?=
|
|
VLAN ?=
|
|
DEMARRER ?=
|
|
CLONE_COMPLET ?=
|
|
|
|
CONFIRMER ?= false
|
|
VERIFICATION ?= false
|
|
DIFF ?= false
|
|
ETIQUETTES ?=
|
|
SAUTER_ETIQUETTES ?=
|
|
VARIABLES ?=
|
|
|
|
OPTIONS_PLAYBOOK :=
|
|
ifneq ($(LIMITE),)
|
|
OPTIONS_PLAYBOOK += --limit $(LIMITE)
|
|
endif
|
|
ifeq ($(VERIFICATION),true)
|
|
OPTIONS_PLAYBOOK += --check
|
|
endif
|
|
ifeq ($(DIFF),true)
|
|
OPTIONS_PLAYBOOK += --diff
|
|
endif
|
|
ifneq ($(ETIQUETTES),)
|
|
OPTIONS_PLAYBOOK += --tags $(ETIQUETTES)
|
|
endif
|
|
ifneq ($(SAUTER_ETIQUETTES),)
|
|
OPTIONS_PLAYBOOK += --skip-tags $(SAUTER_ETIQUETTES)
|
|
endif
|
|
ifneq ($(VARIABLES),)
|
|
OPTIONS_PLAYBOOK += -e $(VARIABLES)
|
|
endif
|
|
|
|
PLAYBOOK_PREPARER_MODELE := playbooks/modeles_vm/debian13_proxmox_preparer.yml
|
|
PLAYBOOK_VERIFIER_MODELE := playbooks/modeles_vm/debian13_proxmox_verifier.yml
|
|
PLAYBOOK_NETTOYER_MODELE := playbooks/modeles_vm/debian13_proxmox_nettoyer.yml
|
|
PLAYBOOK_VERIFIER_HOTE := playbooks/maintenance/verifier_hote_debian.yml
|
|
PLAYBOOK_PROXMOX_CLONER_VM := playbooks/proxmox/cloner_vm_debian.yml
|
|
DOSSIER_PLAYBOOKS_GROUPES := playbooks/groupes
|
|
|
|
.DEFAULT_GOAL := aide
|
|
|
|
.PHONY: ansible-runtime
|
|
ansible-runtime:
|
|
@mkdir -p "$(ANSIBLE_LOCAL_TEMP)"
|
|
@mkdir -p "$(ANSIBLE_SSH_CONTROL_PATH_DIR)"
|
|
|
|
.PHONY: _instance-requise
|
|
_instance-requise:
|
|
@if [[ ! -f "$(SETOPS_INSTANCE)/plan/serveurs.yml" ]]; then \
|
|
printf '%s\n' "Aucune instance configuree : '$(SETOPS_INSTANCE)/plan' introuvable."; \
|
|
printf '%s\n' "Demarre avec QUICKSTART.md. En bref :"; \
|
|
printf '%s\n' " cp -r exemples/modeles/<modele> ../mon-instance && ln -s ../mon-instance instance"; \
|
|
printf '%s\n' " modeles disponibles : $$(ls exemples/modeles 2>/dev/null | grep -v '\.md' | tr '\n' ' ')"; \
|
|
exit 2; \
|
|
fi
|
|
|
|
.PHONY: aide
|
|
aide:
|
|
@printf '%s\n' 'Set-OPS — moteur d ecosystemes numeriques souverains'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Nouveau ? -> QUICKSTART.md (de zero a ton ecosysteme sur Proxmox)'
|
|
@printf '%s\n' 'Flux: editer le plan -> make instancier -> make instancier-appliquer -> make deployer'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'VM'
|
|
@printf '%s\n' ' Creer une VM (VMID/IP/VLAN/passerelle lus dans le plan):'
|
|
@printf '%s\n' ' make creer-vm HOTE=web-frontal-01'
|
|
@printf '%s\n' ' Cloner seulement, sans passer par le plan:'
|
|
@printf '%s\n' ' make cloner-vm HOTE=web-frontal-01 VMID=95301 VLAN=15 ADRESSE_IP=10.0.2.31 PASSERELLE=10.0.2.1'
|
|
@printf '%s\n' ' Configurer Proxmox et le Vault API (parametres: docs/config-proxmox.md):'
|
|
@printf '%s\n' ' make config'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Hotes'
|
|
@printf '%s\n' ' Planifier/modifier un hote: editer le plan, puis regenerer:'
|
|
@printf '%s\n' ' editer instance/plan/serveurs.yml (ou la vue Serveurs du GUI)'
|
|
@printf '%s\n' ' make instancier-appliquer'
|
|
@printf '%s\n' ' Verifier un deploiement a blanc (dry-run):'
|
|
@printf '%s\n' ' make verifier-deploiement HOTE=web-frontal-01'
|
|
@printf '%s\n' ' Remettre un hote en conformite selon ses groupes:'
|
|
@printf '%s\n' ' make deployer HOTE=web-frontal-01'
|
|
@printf '%s\n' ' Afficher un hote:'
|
|
@printf '%s\n' ' make hote-afficher HOTE=web-frontal-01'
|
|
@printf '%s\n' ' Diagnostiquer:'
|
|
@printf '%s\n' ' make verifier-hote LIMITE=web-frontal-01'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Groupes'
|
|
@printf '%s\n' ' Appliquer un groupe complet:'
|
|
@printf '%s\n' ' make deployer-groupe GROUPE=serveur_debian'
|
|
@printf '%s\n' ' Convention:'
|
|
@printf '%s\n' ' groupe serveur_debian -> playbooks/groupes/serveur_debian.yml'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Ecosysteme complet (orchestrateur)'
|
|
@printf '%s\n' ' Ordre de deploiement (couches + graphe):'
|
|
@printf '%s\n' ' make site-verifier # valide la coherence couches/graphe'
|
|
@printf '%s\n' ' python3 scripts/orchestrer.py ordre'
|
|
@printf '%s\n' ' (Re)generer playbooks/site.yml ordonne:'
|
|
@printf '%s\n' ' make site'
|
|
@printf '%s\n' ' CONFIGURER la flotte existante, couche par couche (2b, VM deja creees):'
|
|
@printf '%s\n' ' make deployer-tout CONFIRMER=true # (MODE_CHECK=1 pour un essai a blanc idempotent)'
|
|
@printf '%s\n' ' CREER toutes les VM du plan (2a, clone Proxmox):'
|
|
@printf '%s\n' ' make flotte-creer CONFIRMER=true'
|
|
@printf '%s\n' ' RECONSTRUIRE from-zero = creer les VM PUIS deployer (2a+2b, VM inexistantes):'
|
|
@printf '%s\n' ' make reconstruire CONFIRMER=true # alias: make myDay CONFIRMER=true'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Flux reseau (pare-feu / audit)'
|
|
@printf '%s\n' ' Matrice d audit + apercus nftables resolus (NON actives):'
|
|
@printf '%s\n' ' make flux # -> docs/registre-flux.md + instance/flux-genere/*.nft'
|
|
@printf '%s\n' ' make flux-verifier # valide schema + coherence de matrice'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Wiki pedagogique'
|
|
@printf '%s\n' ' Publier wiki/ dans le wiki Forgejo (source versionnee -> vue browsable):'
|
|
@printf '%s\n' ' make wiki-publier WIKI_REMOTE=https://forge.<domaine>/<proprio>/<depot>.wiki.git'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Inventaires'
|
|
@printf '%s\n' ' Graphe de production:'
|
|
@printf '%s\n' ' make inventaire'
|
|
@printf '%s\n' ' Graphe explicite:'
|
|
@printf '%s\n' ' make inventaire-graphe FICHIER_INVENTAIRE=$(SETOPS_INSTANCE)/inventories/production/hosts.yml'
|
|
@printf '%s\n' ' Verifier les inventaires:'
|
|
@printf '%s\n' ' make inventaire-verifier'
|
|
@printf '%s\n' ' Lister les donnees brutes:'
|
|
@printf '%s\n' ' make inventaire-lister'
|
|
@printf '%s\n' ' Interface locale de gestion:'
|
|
@printf '%s\n' ' make inventaire-ui'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Modele Debian 13 Proxmox'
|
|
@printf '%s\n' ' Construire et verifier:'
|
|
@printf '%s\n' ' make preparer-modele'
|
|
@printf '%s\n' ' make verifier-modele'
|
|
@printf '%s\n' ' Nettoyage final protege:'
|
|
@printf '%s\n' ' make nettoyer-modele CONFIRMER=true'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Validation'
|
|
@printf '%s\n' ' make syntaxe'
|
|
@printf '%s\n' ' make lint'
|
|
@printf '%s\n' ' make verifier'
|
|
@printf '%s\n' ''
|
|
@printf '%s\n' 'Variables frequentes'
|
|
@printf '%s\n' ' HOTE=web-frontal-01 GROUPE=serveur_debian GROUPES="serveur_debian serveur_durci"'
|
|
@printf '%s\n' ' VMID=95301 VLAN=15 ADRESSE_IP=10.0.2.31 PASSERELLE=10.0.2.1'
|
|
@printf '%s\n' ' FICHIER_INVENTAIRE=$(SETOPS_INSTANCE)/inventories/production/hosts.yml FICHIER_DEPENDANCES=docs/dependances-groupes.yml CONFIRMER=true'
|
|
|
|
.PHONY: lint
|
|
lint: ansible-runtime
|
|
ansible-lint
|
|
|
|
.PHONY: syntaxe syntaxe-modele syntaxe-nettoyage syntaxe-verification-modele syntaxe-verification-hote syntaxe-groupes syntaxe-proxmox
|
|
syntaxe: syntaxe-modele syntaxe-verification-modele syntaxe-nettoyage syntaxe-verification-hote syntaxe-groupes syntaxe-proxmox
|
|
|
|
syntaxe-modele: ansible-runtime
|
|
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_PREPARER_MODELE) --syntax-check
|
|
|
|
syntaxe-verification-modele: ansible-runtime
|
|
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_VERIFIER_MODELE) --syntax-check
|
|
|
|
syntaxe-nettoyage: ansible-runtime
|
|
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_NETTOYER_MODELE) --syntax-check
|
|
|
|
syntaxe-verification-hote: ansible-runtime
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) $(PLAYBOOK_VERIFIER_HOTE) --syntax-check
|
|
|
|
syntaxe-groupes: ansible-runtime
|
|
@for playbook in $(DOSSIER_PLAYBOOKS_GROUPES)/*.yml; do \
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$$playbook" --syntax-check; \
|
|
done
|
|
|
|
syntaxe-proxmox: ansible-runtime
|
|
ansible-playbook -i localhost, $(PLAYBOOK_PROXMOX_CLONER_VM) --syntax-check
|
|
|
|
.PHONY: test
|
|
test:
|
|
python3 scripts/tests/test_inventory_host.py
|
|
|
|
.PHONY: verifier
|
|
verifier: lint test inventaire-verifier site-verifier flux-verifier syntaxe
|
|
python3 scripts/prouver.py --verifier
|
|
|
|
# Harnais de preuve : rejoue les preuves automatisables du registre et ecrit
|
|
# docs/audit/preuve-<date>.md (piece justificative horodatee, rejouable).
|
|
# `make verifier` l'appelle en mode --verifier (preuves seules, aucun rapport ecrit).
|
|
.PHONY: prouver
|
|
prouver: ansible-runtime _instance-requise
|
|
python3 scripts/prouver.py
|
|
|
|
.PHONY: inventaire hote-planifier hote-ajouter hote-groupes hote-afficher appliquer deployer deployer-groupe cloner-vm creer-vm config inventaire-ui inventaire-verifier inventaire-lister inventaire-graphe inventaire-hote inventaire-lab inventaire-production instance-utiliser instance-courante
|
|
inventaire: inventaire-production
|
|
|
|
# Bascule le symlink 'instance' vers un autre dépôt d'instance (séparation par
|
|
# instance : prod vs bac à sable). Ex. : make instance-utiliser NOM=OPS-Chezlepro-lab
|
|
instance-utiliser:
|
|
@if [[ -z "$(NOM)" ]]; then printf '%s\n' "Usage: make instance-utiliser NOM=<dossier-frère> (ex. OPS-Chezlepro-lab)"; exit 2; fi
|
|
@if [[ ! -d "../$(NOM)" ]]; then printf '%s\n' "Introuvable: ../$(NOM)"; exit 2; fi
|
|
@if [[ -e instance && ! -L instance ]]; then printf '%s\n' "Refus: 'instance' existe et n'est pas un symlink."; exit 2; fi
|
|
@rm -f instance && ln -s "../$(NOM)" instance
|
|
@printf 'instance -> %s\n' "$$(readlink instance)"
|
|
|
|
instance-courante:
|
|
@printf 'instance -> %s\n' "$$(readlink instance 2>/dev/null || echo '(non monté)')"
|
|
|
|
# Vue d'ensemble : toutes les instances de la fédération, l'active (*), leur index,
|
|
# plage VLAN, statut fédéré/prod ; signale les collisions d'index. Lecture seule.
|
|
instances:
|
|
@python3 scripts/instances.py
|
|
|
|
# (Re)génère le plan de recette (docs/audit/plan-de-recette.md) depuis les exercices
|
|
# du wiki. La preuve P22 vérifie qu'il reste à jour.
|
|
plan-recette:
|
|
@python3 scripts/plan_recette.py
|
|
|
|
# Liste les modèles disponibles (socle + SETOPS_MODELES) pour créer une instance.
|
|
instance-modeles:
|
|
@python3 scripts/instance_creer.py --lister-modeles
|
|
|
|
# Crée un dépôt d'instance frère depuis un modèle. Ne bascule pas le symlink.
|
|
# Ex. : make instance-creer NOM=OPS-ClientX MODELE=socle INDEX=4
|
|
instance-creer:
|
|
@python3 scripts/instance_creer.py --nom "$(NOM)" --modele "$(MODELE)" \
|
|
$(if $(INDEX),--index $(INDEX),)
|
|
|
|
# Crée un MODÈLE (dépôt privé). Deux modes :
|
|
# base : copier un modèle générique -> make model-creer MODE=base BASE=identite NOM=maison-obnl
|
|
# instance : promouvoir une instance -> make model-creer MODE=instance SOURCE=OPS-Chezlepro NOM=cabinet
|
|
model-creer:
|
|
@python3 scripts/model_creer.py --mode "$(MODE)" --nom "$(NOM)" \
|
|
$(if $(BASE),--base $(BASE),) $(if $(SOURCE),--source $(SOURCE),) $(if $(DEST),--dest $(DEST),)
|
|
|
|
config:
|
|
python3 scripts/config_proxmox.py
|
|
|
|
inventaire-ui: _instance-requise
|
|
python3 scripts/inventory_gui.py --inventaire $(FICHIER_INVENTAIRE)
|
|
|
|
hote-ajouter hote-planifier hote-groupes:
|
|
@printf '%s\n' 'Cible depreciee: l inventaire est GENERE depuis le plan, il ne s edite plus a la main.'
|
|
@printf '%s\n' 'Declare ou modifie l hote dans instance/plan/serveurs.yml (ou la vue Serveurs du GUI), puis :'
|
|
@printf '%s\n' ' make instancier-appliquer'
|
|
@printf '%s\n' '(creer-vm lit desormais VMID/IP/VLAN/passerelle directement dans l inventaire genere.)'
|
|
@exit 2
|
|
|
|
hote-afficher: ansible-runtime
|
|
@if [[ -z "$(HOTE)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
|
exit 2; \
|
|
fi
|
|
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) afficher --hote $(HOTE)
|
|
|
|
appliquer: ansible-runtime
|
|
@if [[ -z "$(GROUPE)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec GROUPE=nom_groupe.'; \
|
|
exit 2; \
|
|
fi
|
|
@if [[ ! -f "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" ]]; then \
|
|
printf '%s\n' 'Refus: aucun playbook pour ce groupe: $(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml'; \
|
|
exit 2; \
|
|
fi
|
|
python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-groupe --groupe $(GROUPE)
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$(DOSSIER_PLAYBOOKS_GROUPES)/$(GROUPE).yml" --limit '$(GROUPE):&$(GROUPE_HOTES_ACTIFS)'
|
|
|
|
deployer: _instance-requise
|
|
@set -e; \
|
|
if [[ -z "$(HOTE)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
|
exit 2; \
|
|
fi; \
|
|
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) verifier-actif --hote $(HOTE); \
|
|
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-hote --hote $(HOTE); \
|
|
playbooks="$$(python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) playbooks --hote $(HOTE) --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES))"; \
|
|
if [[ -z "$$playbooks" ]]; then \
|
|
printf '%s\n' 'Refus: aucun playbook applicable pour HOTE=$(HOTE).'; \
|
|
exit 2; \
|
|
fi; \
|
|
vault_chiffre="$$(grep -rlsIF '$$ANSIBLE_VAULT' $(dir $(INVENTAIRE_PRODUCTION))group_vars 2>/dev/null | head -1 || true)"; \
|
|
if [[ -n "$$vault_chiffre" && -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \
|
|
if [[ -t 0 ]]; then \
|
|
read -r -s -p 'Mot de passe du vault Ansible: ' mdp; echo; \
|
|
vf="$$(mktemp)"; printf '%s' "$$mdp" > "$$vf"; chmod 600 "$$vf"; \
|
|
export ANSIBLE_VAULT_PASSWORD_FILE="$$vf"; \
|
|
trap 'rm -f "$$vf"' EXIT; \
|
|
else \
|
|
printf '%s\n' 'Refus: vault chiffre detecte mais aucun mot de passe (entree non interactive). Fournir ANSIBLE_VAULT_PASSWORD_FILE ou le champ vault de la GUI.'; \
|
|
exit 2; \
|
|
fi; \
|
|
fi; \
|
|
$(MAKE) _verifier-acces-hote LIMITE="$(HOTE)"; \
|
|
$(MAKE) _verifier-privileges-hote LIMITE="$(HOTE)"; \
|
|
for playbook in $$playbooks; do \
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$$playbook" --limit "$(HOTE)"; \
|
|
done; \
|
|
$(MAKE) verifier-hote LIMITE="$(HOTE)"
|
|
|
|
.PHONY: site site-verifier deployer-tout
|
|
site: ansible-runtime
|
|
python3 scripts/orchestrer.py ecrire
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) playbooks/site.yml --syntax-check
|
|
|
|
site-verifier:
|
|
python3 scripts/orchestrer.py verifier
|
|
|
|
.PHONY: flux flux-verifier
|
|
flux: ansible-runtime
|
|
python3 scripts/resoudre_flux.py registre
|
|
python3 scripts/resoudre_flux.py nftables
|
|
|
|
.PHONY: devis-reseau
|
|
devis-reseau: ansible-runtime ## Devis switch (VLANs/SVIs/ACLs) du reseau converge, derive des nomenclatures. DIALECTE=cisco|binardat
|
|
python3 scripts/devis_reseau.py $(if $(DIALECTE),--dialecte $(DIALECTE),)
|
|
|
|
.PHONY: underlay
|
|
underlay: ## Underlay (fabric physique cluster-global : mgmt/iSCSI/Ceph) : affiche + valide (P23)
|
|
python3 scripts/underlay.py
|
|
|
|
flux-verifier:
|
|
python3 scripts/resoudre_flux.py verifier
|
|
|
|
.PHONY: valider
|
|
valider: ansible-runtime
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) playbooks/valider.yml
|
|
|
|
.PHONY: wiki-publier
|
|
wiki-publier:
|
|
@set -e; \
|
|
if [[ -z "$(WIKI_REMOTE)" ]]; then \
|
|
printf '%s\n' 'Refus: URL du wiki Forgejo requise.'; \
|
|
printf '%s\n' 'Ex: make wiki-publier WIKI_REMOTE=https://forge.<domaine>/<proprio>/<depot>.wiki.git'; \
|
|
exit 2; \
|
|
fi; \
|
|
src="$(CURDIR)/wiki"; \
|
|
tmp="$$(mktemp -d)"; \
|
|
trap 'rm -rf "$$tmp"' EXIT; \
|
|
printf '%s\n' "Clonage du wiki: $(WIKI_REMOTE)"; \
|
|
if ! git clone --quiet --depth 1 "$(WIKI_REMOTE)" "$$tmp/wiki"; then \
|
|
printf '%s\n' 'Echec du clone (URL ou acces ?). Le wiki doit exister (creer une 1re page dans Forgejo).'; \
|
|
exit 1; \
|
|
fi; \
|
|
find "$$tmp/wiki" -maxdepth 1 -name '*.md' -delete; \
|
|
for f in "$$src"/*.md; do \
|
|
bn="$$(basename "$$f")"; \
|
|
[[ "$$bn" == "README.md" ]] && continue; \
|
|
cp "$$f" "$$tmp/wiki/$$bn"; \
|
|
done; \
|
|
cd "$$tmp/wiki"; \
|
|
if [[ -z "$$(git status --porcelain)" ]]; then \
|
|
printf '%s\n' 'Wiki deja a jour (aucun changement).'; \
|
|
exit 0; \
|
|
fi; \
|
|
git add -A; \
|
|
sha="$$(git -C "$(CURDIR)" rev-parse --short HEAD 2>/dev/null || echo inconnu)"; \
|
|
git commit --quiet -m "Publication du wiki depuis le depot (source: $$sha)"; \
|
|
git push --quiet; \
|
|
printf '%s\n' 'Wiki publie.'
|
|
|
|
deployer-tout: _instance-requise
|
|
@set -e; \
|
|
if [[ "$(CONFIRMER)" != "true" ]]; then \
|
|
printf '%s\n' 'Refus: deploiement ORCHESTRE de TOUTE la flotte (action impactante).'; \
|
|
printf '%s\n' 'Relancer avec CONFIRMER=true. Astuce: tester d abord en idempotent avec MODE_CHECK=1.'; \
|
|
exit 2; \
|
|
fi; \
|
|
python3 scripts/orchestrer.py verifier; \
|
|
python3 scripts/orchestrer.py ecrire; \
|
|
vault_chiffre="$$(grep -rlsIF '$$ANSIBLE_VAULT' $(dir $(INVENTAIRE_PRODUCTION))group_vars 2>/dev/null | head -1 || true)"; \
|
|
if [[ -n "$$vault_chiffre" && -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \
|
|
if [[ -t 0 ]]; then \
|
|
read -r -s -p 'Mot de passe du vault Ansible: ' mdp; echo; \
|
|
vf="$$(mktemp)"; printf '%s' "$$mdp" > "$$vf"; chmod 600 "$$vf"; \
|
|
export ANSIBLE_VAULT_PASSWORD_FILE="$$vf"; \
|
|
trap 'rm -f "$$vf"' EXIT; \
|
|
else \
|
|
printf '%s\n' 'Refus: vault chiffre detecte mais aucun mot de passe (entree non interactive). Fournir ANSIBLE_VAULT_PASSWORD_FILE ou le champ vault de la GUI.'; \
|
|
exit 2; \
|
|
fi; \
|
|
fi; \
|
|
$(MAKE) _verifier-acces-hote LIMITE="$(GROUPE_HOTES_ACTIFS)"; \
|
|
$(MAKE) _verifier-privileges-hote LIMITE="$(GROUPE_HOTES_ACTIFS)"; \
|
|
mode="$$([[ -n "$(MODE_CHECK)" ]] && printf -- '--check --diff' || true)"; \
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) playbooks/site.yml --limit "$(GROUPE_HOTES_ACTIFS)" $$mode
|
|
|
|
# --- Reconstruction from-zero : creer TOUTES les VM (2a) puis deployer (2b) ---
|
|
|
|
.PHONY: flotte-creer
|
|
flotte-creer: _instance-requise
|
|
@set -e; \
|
|
if [[ "$(CONFIRMER)" != "true" ]]; then \
|
|
printf '%s\n' 'Refus: creation de TOUTES les VM actives du plan (clone Proxmox).'; \
|
|
printf '%s\n' 'Relancer avec CONFIRMER=true.'; \
|
|
exit 2; \
|
|
fi; \
|
|
hotes="$$(python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) lister-actifs)"; \
|
|
if [[ -z "$$hotes" ]]; then printf '%s\n' 'Refus: aucun hote actif dans le plan.'; exit 2; fi; \
|
|
for h in $$hotes; do \
|
|
printf '\n=== Creation VM: %s ===\n' "$$h"; \
|
|
$(MAKE) creer-vm HOTE="$$h"; \
|
|
done; \
|
|
printf '\nToutes les VM actives sont creees.\n'
|
|
|
|
.PHONY: _attendre-flotte
|
|
_attendre-flotte: ansible-runtime
|
|
@set -e; \
|
|
max="$${ATTENTE_MAX:-600}"; deadline=$$(( $$(date +%s) + max )); \
|
|
printf 'Attente que la flotte reponde en SSH (max %ss)...\n' "$$max"; \
|
|
until ansible -i $(INVENTAIRE_PRODUCTION) $(GROUPE_HOTES_ACTIFS) -m ping -e ansible_become=false >/dev/null 2>&1; do \
|
|
if (( $$(date +%s) > deadline )); then printf 'Timeout: flotte injoignable apres %ss.\n' "$$max"; exit 1; fi; \
|
|
sleep 10; \
|
|
done; \
|
|
printf 'Flotte joignable.\n'
|
|
|
|
.PHONY: reconstruire
|
|
reconstruire: _instance-requise
|
|
@set -e; \
|
|
if [[ "$(CONFIRMER)" != "true" ]]; then \
|
|
printf '%s\n' 'Refus: RECONSTRUCTION — cree les VM manquantes (2a) PUIS deploie tout (2b).'; \
|
|
printf '%s\n' 'Idempotent : une VM deja presente est sautee (clone par nom), le deploiement converge.'; \
|
|
printf '%s\n' 'Relancer avec CONFIRMER=true.'; \
|
|
exit 2; \
|
|
fi; \
|
|
$(MAKE) flotte-creer CONFIRMER=true; \
|
|
$(MAKE) _attendre-flotte; \
|
|
$(MAKE) deployer-tout CONFIRMER=true
|
|
|
|
# « Go ahead, make my day. » — LE bouton rouge : alias de reconstruire (Clint Eastwood).
|
|
# Cree toutes les VM puis deploie tout, en une commande. Garde CONFIRMER=true.
|
|
.PHONY: myDay
|
|
myDay: reconstruire
|
|
|
|
deployer-groupe:
|
|
@if [[ -z "$(GROUPE)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec GROUPE=nom_groupe.'; \
|
|
exit 2; \
|
|
fi
|
|
$(MAKE) appliquer GROUPE="$(GROUPE)"
|
|
|
|
.PHONY: verifier-deploiement
|
|
verifier-deploiement: ansible-runtime
|
|
@set -e; \
|
|
if [[ -z "$(HOTE)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
|
exit 2; \
|
|
fi; \
|
|
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) verifier-actif --hote $(HOTE); \
|
|
python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) --dependances $(FICHIER_DEPENDANCES) verifier-dependances-hote --hote $(HOTE); \
|
|
playbooks="$$(python3 scripts/inventory_host.py --inventaire $(FICHIER_INVENTAIRE) playbooks --hote $(HOTE) --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES))"; \
|
|
if [[ -z "$$playbooks" ]]; then \
|
|
printf '%s\n' 'Refus: aucun playbook applicable pour HOTE=$(HOTE).'; \
|
|
exit 2; \
|
|
fi; \
|
|
vault_chiffre="$$(grep -rlsIF '$$ANSIBLE_VAULT' $(dir $(INVENTAIRE_PRODUCTION))group_vars 2>/dev/null | head -1 || true)"; \
|
|
if [[ -n "$$vault_chiffre" && -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \
|
|
if [[ -t 0 ]]; then \
|
|
read -r -s -p 'Mot de passe du vault Ansible: ' mdp; echo; \
|
|
vf="$$(mktemp)"; printf '%s' "$$mdp" > "$$vf"; chmod 600 "$$vf"; \
|
|
export ANSIBLE_VAULT_PASSWORD_FILE="$$vf"; \
|
|
trap 'rm -f "$$vf"' EXIT; \
|
|
else \
|
|
printf '%s\n' 'Refus: vault chiffre detecte mais aucun mot de passe (entree non interactive). Fournir ANSIBLE_VAULT_PASSWORD_FILE ou le champ vault de la GUI.'; \
|
|
exit 2; \
|
|
fi; \
|
|
fi; \
|
|
for playbook in $$playbooks; do \
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) "$$playbook" --limit "$(HOTE)" --check --diff; \
|
|
done
|
|
|
|
cloner-vm: ansible-runtime
|
|
@if [[ -z "$(HOTE)" || -z "$(VMID)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec HOTE=nom VMID=id_clone.'; \
|
|
exit 2; \
|
|
fi
|
|
@if [[ -z "$(VLAN)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec VLAN=id_vlan.'; \
|
|
exit 2; \
|
|
fi
|
|
@if ! [[ "$(VLAN)" =~ ^[0-9]+$$ ]] || (( 10#$(VLAN) < 1 || 10#$(VLAN) > 4094 )); then \
|
|
printf '%s\n' 'Refus: VLAN doit etre un nombre entre 1 et 4094.'; \
|
|
exit 2; \
|
|
fi
|
|
@if [[ -n "$(CLE_SSH_PUBLIQUE)" && ! -f "$(CLE_SSH_PUBLIQUE)" ]]; then \
|
|
printf '%s\n' 'Refus: cle publique SSH introuvable: $(CLE_SSH_PUBLIQUE)'; \
|
|
exit 2; \
|
|
fi
|
|
@if [[ "$(DHCP)" != "true" && ( -z "$(ADRESSE_IP)" || -z "$(CIDR)" || -z "$(PASSERELLE)" ) ]]; then \
|
|
printf '%s\n' 'Refus: fournir ADRESSE_IP, CIDR et PASSERELLE, ou utiliser DHCP=true.'; \
|
|
exit 2; \
|
|
fi
|
|
@ipconfig='ip=dhcp'; \
|
|
if [[ "$(DHCP)" != "true" ]]; then \
|
|
ipconfig='ip=$(ADRESSE_IP)/$(CIDR),gw=$(PASSERELLE)'; \
|
|
fi; \
|
|
extra_vars=( \
|
|
-e proxmox_clone_nom="$(HOTE)" \
|
|
-e proxmox_clone_vmid="$(VMID)" \
|
|
-e proxmox_clone_ipconfig0="$$ipconfig" \
|
|
); \
|
|
[[ -n "$(VMID_MODELE)" ]] && extra_vars+=( -e proxmox_clone_vmid_modele="$(VMID_MODELE)" ); \
|
|
[[ -n "$(NOEUD_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_noeud="$(NOEUD_PROXMOX)" ); \
|
|
[[ -n "$(STOCKAGE_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_stockage="$(STOCKAGE_PROXMOX)" ); \
|
|
[[ -n "$(FORMAT_DISQUE)" ]] && extra_vars+=( -e proxmox_clone_format="$(FORMAT_DISQUE)" ); \
|
|
[[ -n "$(CLONE_COMPLET)" ]] && extra_vars+=( -e proxmox_clone_complet="$(CLONE_COMPLET)" ); \
|
|
[[ -n "$(TAILLE_DISQUE)" ]] && extra_vars+=( -e proxmox_clone_taille_disque="$(TAILLE_DISQUE)" ); \
|
|
[[ -n "$(COEURS)" ]] && extra_vars+=( -e proxmox_clone_coeurs="$(COEURS)" ); \
|
|
[[ -n "$(MEMOIRE)" ]] && extra_vars+=( -e proxmox_clone_memoire="$(MEMOIRE)" ); \
|
|
[[ -n "$(DISQUE_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_disque="$(DISQUE_PROXMOX)" ); \
|
|
[[ -n "$(DNS)" ]] && extra_vars+=( -e proxmox_clone_dns="$(DNS)" ); \
|
|
[[ -n "$(CIUSER)" ]] && extra_vars+=( -e proxmox_clone_ciuser="$(CIUSER)" ); \
|
|
[[ -n "$(CLE_SSH_PUBLIQUE)" ]] && extra_vars+=( -e proxmox_clone_cle_publique_fichier="$(CLE_SSH_PUBLIQUE)" ); \
|
|
[[ -n "$(PONT_PROXMOX)" ]] && extra_vars+=( -e proxmox_clone_pont="$(PONT_PROXMOX)" ); \
|
|
extra_vars+=( -e proxmox_clone_vlan="$(VLAN)" ); \
|
|
[[ -n "$(DEMARRER)" ]] && extra_vars+=( -e proxmox_clone_demarrer="$(DEMARRER)" ); \
|
|
vault_args=(); \
|
|
vault_file=""; \
|
|
for d in lab principal production; do \
|
|
for gv in group_vars/all/vault.yml group_vars/proxmox.vault.yml; do \
|
|
f="$(SETOPS_INSTANCE)/inventories/$$d/$$gv"; \
|
|
[[ -f "$$f" ]] && vault_file="$$f" && break 2; \
|
|
done; \
|
|
done; \
|
|
if [[ -n "$$vault_file" && -f "$$vault_file" ]]; then \
|
|
read -r premiere_ligne < "$$vault_file" || true; \
|
|
case "$$premiere_ligne" in \
|
|
'$$ANSIBLE_VAULT'*) \
|
|
if [[ -z "$${ANSIBLE_VAULT_PASSWORD_FILE:-}" ]]; then \
|
|
vault_args+=( --ask-vault-pass ); \
|
|
fi; \
|
|
;; \
|
|
esac; \
|
|
fi; \
|
|
ansible-playbook -i localhost, $(PLAYBOOK_PROXMOX_CLONER_VM) "$${vault_args[@]}" "$${extra_vars[@]}"
|
|
|
|
creer-vm: _instance-requise
|
|
@set -e; \
|
|
if [[ -z "$(HOTE)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote (declare dans le plan).'; \
|
|
exit 2; \
|
|
fi; \
|
|
params="$$(python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) parametres-proxmox --hote $(HOTE))"; \
|
|
eval "$$params"; \
|
|
$(MAKE) cloner-vm \
|
|
HOTE="$(HOTE)" \
|
|
VMID="$$SETOPS_VMID" \
|
|
ADRESSE_IP="$$SETOPS_IP" \
|
|
CIDR="$$SETOPS_CIDR" \
|
|
PASSERELLE="$$SETOPS_PASSERELLE" \
|
|
VLAN="$$SETOPS_VLAN" \
|
|
STOCKAGE_PROXMOX="$${SETOPS_STOCKAGE:-$(STOCKAGE_PROXMOX)}" \
|
|
TAILLE_DISQUE="$${SETOPS_DISQUE:-$(TAILLE_DISQUE)}" \
|
|
COEURS="$${SETOPS_COEURS:-$(COEURS)}" \
|
|
MEMOIRE="$${SETOPS_MEMOIRE:-$(MEMOIRE)}" \
|
|
NOEUD_PROXMOX="$${SETOPS_NOEUD:-$(NOEUD_PROXMOX)}" \
|
|
VMID_MODELE="$(VMID_MODELE)" \
|
|
FORMAT_DISQUE="$(FORMAT_DISQUE)" \
|
|
DISQUE_PROXMOX="$(DISQUE_PROXMOX)" \
|
|
DNS="$(DNS)" \
|
|
DHCP="$(DHCP)" \
|
|
CIUSER="$(CIUSER)" \
|
|
CLE_SSH_PUBLIQUE="$(CLE_SSH_PUBLIQUE)" \
|
|
PONT_PROXMOX="$(PONT_PROXMOX)" \
|
|
DEMARRER="$(DEMARRER)" \
|
|
CLONE_COMPLET="$(CLONE_COMPLET)"
|
|
|
|
inventaire-verifier: ansible-runtime _instance-requise
|
|
ansible-inventory -i $(INVENTAIRE_LAB) --list > /dev/null
|
|
ansible-inventory -i $(INVENTAIRE_PRODUCTION) --list > /dev/null
|
|
python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) verifier-playbooks --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES)
|
|
python3 scripts/inventory_host.py --inventaire $(INVENTAIRE_PRODUCTION) --dependances $(FICHIER_DEPENDANCES) verifier-dependances --dossier-playbooks $(DOSSIER_PLAYBOOKS_GROUPES)
|
|
python3 scripts/verifier_gui.py
|
|
python3 scripts/serveurs.py verifier
|
|
python3 scripts/applications.py verifier
|
|
python3 scripts/bases_donnees.py verifier
|
|
python3 scripts/domaines.py verifier
|
|
|
|
.PHONY: bases bases-verifier domaines domaines-verifier applications applications-verifier applications-bootstrap serveurs serveurs-verifier serveurs-bootstrap
|
|
serveurs:
|
|
python3 scripts/serveurs.py lister
|
|
|
|
serveurs-verifier:
|
|
python3 scripts/serveurs.py verifier
|
|
|
|
serveurs-bootstrap:
|
|
python3 scripts/serveurs.py bootstrap
|
|
|
|
.PHONY: instancier instancier-appliquer
|
|
instancier: _instance-requise
|
|
python3 scripts/instancier.py generer
|
|
python3 scripts/instancier.py comparer
|
|
|
|
instancier-appliquer: _instance-requise
|
|
python3 scripts/instancier.py appliquer $(if $(FORCE),--force)
|
|
|
|
bases:
|
|
python3 scripts/bases_donnees.py lister
|
|
|
|
bases-verifier:
|
|
python3 scripts/bases_donnees.py verifier
|
|
|
|
domaines:
|
|
python3 scripts/domaines.py lister
|
|
|
|
domaines-verifier:
|
|
python3 scripts/domaines.py verifier
|
|
|
|
applications:
|
|
python3 scripts/applications.py lister
|
|
|
|
applications-verifier:
|
|
python3 scripts/applications.py verifier
|
|
|
|
applications-bootstrap:
|
|
python3 scripts/applications.py bootstrap
|
|
|
|
inventaire-lister: ansible-runtime
|
|
ansible-inventory -i $(FICHIER_INVENTAIRE) --list
|
|
|
|
inventaire-graphe: ansible-runtime
|
|
ansible-inventory -i $(FICHIER_INVENTAIRE) --graph
|
|
|
|
inventaire-hote: ansible-runtime
|
|
@if [[ -z "$(HOTE)" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec HOTE=nom_hote.'; \
|
|
exit 2; \
|
|
fi
|
|
ansible-inventory -i $(FICHIER_INVENTAIRE) --host $(HOTE)
|
|
|
|
inventaire-lab:
|
|
$(MAKE) inventaire-graphe FICHIER_INVENTAIRE="$(INVENTAIRE_LAB)"
|
|
|
|
inventaire-production:
|
|
$(MAKE) inventaire-graphe FICHIER_INVENTAIRE="$(INVENTAIRE_PRODUCTION)"
|
|
|
|
.PHONY: _verifier-acces-modele _verifier-privileges-modele preparer-modele verifier-modele nettoyer-modele
|
|
_verifier-acces-modele: ansible-runtime
|
|
ansible -i $(INVENTAIRE_LAB) $(GROUPE_MODELE) -m ping -e ansible_become=false
|
|
|
|
_verifier-privileges-modele: ansible-runtime
|
|
ansible -i $(INVENTAIRE_LAB) $(GROUPE_MODELE) -b -m command -a "whoami"
|
|
|
|
preparer-modele: ansible-runtime _verifier-acces-modele _verifier-privileges-modele
|
|
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_PREPARER_MODELE)
|
|
|
|
verifier-modele: ansible-runtime
|
|
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_VERIFIER_MODELE)
|
|
|
|
nettoyer-modele: ansible-runtime
|
|
@if [[ "$(CONFIRMER)" != "true" ]]; then \
|
|
printf '%s\n' 'Refus: relancer avec CONFIRMER=true pour le nettoyage final du modele.'; \
|
|
exit 2; \
|
|
fi
|
|
ansible-playbook -i $(INVENTAIRE_LAB) $(PLAYBOOK_NETTOYER_MODELE) -e template_cleanup_confirm=true
|
|
|
|
.PHONY: _verifier-acces-hote _verifier-privileges-hote faits verifier-hote
|
|
_verifier-acces-hote: ansible-runtime
|
|
ansible -i $(INVENTAIRE_PRODUCTION) $(LIMITE) -m ping -e ansible_become=false
|
|
|
|
_verifier-privileges-hote: ansible-runtime
|
|
ansible -i $(INVENTAIRE_PRODUCTION) $(LIMITE) -b -m command -a "whoami"
|
|
|
|
faits: ansible-runtime
|
|
ansible -i $(INVENTAIRE_PRODUCTION) $(LIMITE) -m setup -a "filter=ansible_distribution*"
|
|
|
|
verifier-hote: ansible-runtime
|
|
ansible-playbook -i $(INVENTAIRE_PRODUCTION) $(PLAYBOOK_VERIFIER_HOTE) $(OPTIONS_PLAYBOOK)
|