contexte : etape 2b, la face reseau du locataire (les faits)
locataire.face_reseau() publie index, machines, groupes, administration, zones publiques et cle de sauvegarde ; verifier_face la confronte aux consommateurs du site (decouverte, devis Proxmox, frontiere, inventaire du site). P85 : aucun ecart ; huit alterations vues en ecart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8251022148
commit
077c6c91b4
7 changed files with 282 additions and 4 deletions
|
|
@ -188,7 +188,7 @@ Si `ansible-lint` n’est pas disponible, le signaler clairement. Ne pas invente
|
|||
## Écrire, puis relire (D-68)
|
||||
|
||||
`--syntax-check` et `ansible-lint` prouvent que le dépôt est cohérent **avec lui-même**.
|
||||
C'est aussi ce que font les 84 preuves de `make prouver` : elles lisent le dépôt, sans le
|
||||
C'est aussi ce que font les 85 preuves de `make prouver` : elles lisent le dépôt, sans le
|
||||
moindre appel réseau. **Aucune ne demande au système déployé s'il ressemble à ce que le
|
||||
dépôt annonce.**
|
||||
|
||||
|
|
|
|||
43
CHANGELOG.md
43
CHANGELOG.md
|
|
@ -1,5 +1,48 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-10-04 (81) — Étape 2, seconde moitié (les faits) : la face réseau du locataire
|
||||
|
||||
**Le chemin** (`docs/conception-contextes.md` §6), étape 2, sens locataire → site. La face
|
||||
réseau se livre en deux temps vérifiés : d'abord les **faits** que le site lit chez le
|
||||
locataire (ici), ensuite ses **flux résolus**, confrontés aux devis de la frontière et de
|
||||
Proxmox (à suivre).
|
||||
|
||||
**Fait** (`scripts/contexte.py`) :
|
||||
- `locataire.face_reseau()` publie, calculé **chez le locataire** : son index ; ses machines
|
||||
(adresse, groupes, paramètres de matérialisation `proxmox_*`) ; ses groupes ; son
|
||||
administration (l'intrant `nftables_admin_ssh`, son tunnel, ses pairs WireGuard avec leurs
|
||||
clés **publiques**) ; ses zones publiques (zones, signées, adresse et port de son
|
||||
primaire) ; la clé publique de sa sauvegarde. Elle porte l'empreinte de ses six sources.
|
||||
- `verifier_face(site, locataire)` interroge **les consommateurs du site eux-mêmes**, le site
|
||||
monté : la découverte des locataires (`devis_reseau`), le devis du pare-feu Proxmox (la
|
||||
flotte, chaque groupe qu'il utilise, l'administration), la frontière (`admin_de`), et
|
||||
l'inventaire du site (relations du DNS public, comptes de sauvegarde).
|
||||
- `--face <locataire>` l'affiche ; `--verifier-faces` confronte chaque couple.
|
||||
|
||||
**Un faux écart, corrigé avant le commit** : la première comparaison exigeait un ensemble
|
||||
d'adresses par groupe dans le devis Proxmox, et en signalait 19 absents par locataire. Le
|
||||
devis ne garde que les ensembles que ses règles **utilisent** (13 chez chacun) ; la
|
||||
vérification se fait désormais dans ce sens.
|
||||
|
||||
**Deux lectures fragiles du site, que la face réseau fera disparaître à l'étape 3** :
|
||||
`site_inventaire.py` lit la clé de sauvegarde sous `inventories/principal/` écrit en dur, et
|
||||
re-dérive l'adresse du primaire DNS avec la séquence 1 par défaut (juste aujourd'hui, les
|
||||
primaires sont des `-01`). La face réseau prend l'une dans le dossier d'inventaire réel du
|
||||
locataire, l'autre dans son inventaire.
|
||||
|
||||
**Ce que la vérification ne couvre pas encore** : la matérialisation est recopiée de
|
||||
l'inventaire, que le clonage lit par Ansible, sans consommateur Python à confronter ; les pairs
|
||||
WireGuard ne sont vérifiés qu'à travers le tunnel qu'ils ouvrent ; les flux arrivent dans le
|
||||
second temps.
|
||||
|
||||
**Éprouvé** :
|
||||
- **P85**, « La face réseau du locataire dit exactement ce que le site en tire » : 2 faces,
|
||||
aucun écart.
|
||||
- `test_contexte.py`, 60 contrôles : les deux faces réelles concordent, et une face altérée de
|
||||
**huit façons** (index, adresse d'une machine, membres d'un groupe, administration déclarée,
|
||||
tunnel, zones publiques, primaire DNS, clé de sauvegarde) est vue en écart à chaque fois.
|
||||
- `make verifier` conforme, **85/85**. Les trois documents comptent 85 preuves.
|
||||
|
||||
## 2026-10-04 (80) — Étape 2, première moitié : la fiche du site, et la preuve qu'elle dit vrai
|
||||
|
||||
**Le chemin** (`docs/conception-contextes.md` §6), étape 2 : générer les fiches **à côté** de
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ make placement-plan # chaque VM est-elle là où le plan la met
|
|||
|
||||
## Le trou qu'il comble
|
||||
|
||||
`scripts/prouver.py` porte 84 preuves (dont une conditionnelle, sautée sans la clé de la voûte). Elles sont toutes **statiques** : elles lisent le
|
||||
`scripts/prouver.py` porte 85 preuves (dont une conditionnelle, sautée sans la clé de la voûte). Elles sont toutes **statiques** : elles lisent le
|
||||
dépôt. Zéro appel réseau, zéro SSH, zéro `ansible`. Elles établissent que le dépôt est
|
||||
cohérent **avec lui-même** — que les handlers existent, que les intrants ont un
|
||||
propriétaire, que rien n'est codé en dur.
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ Nommer un point ouvert vaut mieux qu'une ligne rassurante sans mécanisme derri
|
|||
Aucune de ces responsabilités n'est laissée à la parole :
|
||||
|
||||
```
|
||||
make prouver le dépôt est-il cohérent avec lui-même (84 preuves, zéro réseau)
|
||||
make prouver le dépôt est-il cohérent avec lui-même (85 preuves, zéro réseau)
|
||||
make remise-verifier le second temps de la remise est-il fait, ou en retard ? (P80)
|
||||
make certificats-plan ce que le disque porte contre ce que la mémoire sert
|
||||
make expositions-plan chaque service publié répond-il, et depuis où
|
||||
|
|
|
|||
|
|
@ -361,6 +361,81 @@ class Locataire(Ecosysteme):
|
|||
return None
|
||||
return Site.charger(nom, self.depot.parent)
|
||||
|
||||
# LE CONTRAT, SENS LOCATAIRE -> SITE (§2.4) ---------------------------------------------
|
||||
def face_reseau(self) -> dict:
|
||||
"""Ce que CE locataire demande a son site, en une fiche — les faits, pas encore les flux.
|
||||
|
||||
Le site lisait jusqu'ici six fichiers internes du locataire (relevé du 2026-10-04) :
|
||||
sa nomenclature, son inventaire genere, ses `group_vars` (`nftables_admin_ssh`,
|
||||
`serveur_backup_pubkey`), son `plan/acces.yml`, son `plan/domaines.yml` et ce qui
|
||||
l'accompagne. La face reseau les publie, calcules ICI, chez le locataire, qui seul sait
|
||||
lire ses fichiers : l'adresse de son primaire DNS vient de son inventaire (le site la
|
||||
re-derivait, sequence 1 par defaut), sa cle de sauvegarde de SON dossier d'inventaire
|
||||
(le site ecrivait `principal` en dur).
|
||||
|
||||
LES FLUX RESOLUS sont la seconde moitie de l'etape 2 ; ils ne sont pas encore ici.
|
||||
"""
|
||||
from inventory_rules import charger_acces, est_groupe_operationnel, tunnel_admin_de
|
||||
from resoudre_flux import _enfants, _hotes_du_groupe, _ip_par_hote
|
||||
data = _yaml(self.inventaire())
|
||||
hv = _hostvars(self.inventaire())
|
||||
ips = _ip_par_hote(data) if data else {}
|
||||
groupes = {g: sorted(h for h in _hotes_du_groupe(data, g) if h in ips)
|
||||
for g in sorted(_enfants(data)) if est_groupe_operationnel(g)} if data else {}
|
||||
machines = {
|
||||
h: {"ip": ip,
|
||||
"groupes": sorted(g for g, membres in groupes.items() if h in membres),
|
||||
"materialisation": {k: v for k, v in sorted((hv.get(h) or {}).items())
|
||||
if k.startswith("proxmox_")}}
|
||||
for h, ip in sorted(ips.items())}
|
||||
# Les reseaux d'administration que le locataire DECLARE (l'intrant), et son tunnel.
|
||||
intrant: list[str] = []
|
||||
gv_all = self.dossier_inventaire() / "group_vars" / "all"
|
||||
for fichier in sorted(gv_all.glob("*.yml")) if gv_all.is_dir() else []:
|
||||
if "vault" in fichier.name:
|
||||
continue
|
||||
d = _yaml(fichier)
|
||||
if isinstance(d, dict) and d.get("nftables_admin_ssh"):
|
||||
src = d["nftables_admin_ssh"]
|
||||
intrant = [str(s) for s in src] if isinstance(src, list) else [str(src)]
|
||||
break
|
||||
try:
|
||||
pairs = charger_acces(self.plan / "acces.yml").get("acces_admin_vpn") or {}
|
||||
except (OSError, ValueError):
|
||||
pairs = {}
|
||||
# Ses zones publiques : celles qu'il fait servir par le site (`primaire-cache`).
|
||||
doms = self.lire_plan("domaines.yml").get("domaines_publics") or {}
|
||||
apps = self.lire_plan("applications.yml").get("applications") or {}
|
||||
zones = sorted(z for z, c in doms.items()
|
||||
if isinstance(c, dict) and str(c.get("autorite")) == "primaire-cache")
|
||||
hote_dns = next((str(a.get("hote")) for a in apps.values()
|
||||
if str(a.get("groupe")) == "serveur_powerdns"), "")
|
||||
colocalise = any(str(a.get("groupe")) == "serveur_resolveur" and str(a.get("hote")) == hote_dns
|
||||
for a in apps.values())
|
||||
dns_public = ({"zones": zones,
|
||||
"signees": sorted(z for z in zones if doms[z].get("dnssec") is True),
|
||||
"primaire": ips.get(hote_dns, ""),
|
||||
"port": 5300 if colocalise else 53} if zones else {})
|
||||
cle_sauvegarde = str(_yaml(self.dossier_inventaire() / "group_vars" / "serveur_backup.yml")
|
||||
.get("serveur_backup_pubkey") or "").strip()
|
||||
sources = {str(Path(*f.relative_to(self.depot).parts)): _empreinte(f) for f in (
|
||||
self.plan / "nomenclature.yml", self.inventaire(), self.plan / "acces.yml",
|
||||
self.plan / "domaines.yml", self.plan / "applications.yml",
|
||||
self.dossier_inventaire() / "group_vars" / "serveur_backup.yml")}
|
||||
return {
|
||||
"locataire": self.nom,
|
||||
"hebergeur": self.nom_hebergeur(),
|
||||
"sources": sources,
|
||||
"index": self.index,
|
||||
"machines": machines,
|
||||
"groupes": groupes,
|
||||
"administration": {"intrant": intrant, "tunnel": tunnel_admin_de(self.depot),
|
||||
"pairs": {n: {k: c.get(k) for k in ("cle_publique", "adresse", "etat")}
|
||||
for n, c in sorted(pairs.items()) if isinstance(c, dict)}},
|
||||
"dns_public": dns_public,
|
||||
"sauvegarde": {"cle_publique": cle_sauvegarde},
|
||||
}
|
||||
|
||||
def decrire(self) -> dict:
|
||||
d = super().decrire()
|
||||
d.update({"inventaire": str(self.inventaire()), "hebergeur": self.nom_hebergeur()})
|
||||
|
|
@ -453,6 +528,81 @@ def verifier_fiche(site: "Site", locataire: "Locataire", fiche: dict | None = No
|
|||
return ecarts
|
||||
|
||||
|
||||
def verifier_face(site: "Site", locataire: "Locataire", face: dict | None = None) -> list[str]:
|
||||
"""Les ecarts entre la face reseau du locataire et ce que les CONSOMMATEURS DU SITE en tirent
|
||||
aujourd'hui, en lisant ses fichiers internes.
|
||||
|
||||
On interroge les consommateurs eux-memes, le site monte : la decouverte des locataires
|
||||
(`devis_reseau`), le devis du pare-feu Proxmox (ses ensembles d'adresses par groupe et
|
||||
d'administration), la frontiere (`admin_de`), et l'inventaire du site (relations du DNS
|
||||
public, comptes de sauvegarde). Vide = chacun lirait la face reseau sans rien changer.
|
||||
"""
|
||||
import devis_proxmox_fw
|
||||
import devis_reseau
|
||||
import site_inventaire
|
||||
f = face if face is not None else locataire.face_reseau()
|
||||
ecarts: list[str] = []
|
||||
with _monter(site):
|
||||
decouverts = {nom: n for nom, _p, n in devis_reseau.decouvrir_du_site()}
|
||||
bloc = next((b for b in devis_proxmox_fw.construire(devis_reseau.decouvrir_du_site())["blocs"]
|
||||
if b.get("tenant") == locataire.nom), None)
|
||||
admin_frontiere = sorted(devis_reseau.admin_de(locataire.nom))
|
||||
inv = site_inventaire.inventaire() or {}
|
||||
hv_site = (inv.get("_meta") or {}).get("hostvars") or {}
|
||||
|
||||
# 1. L'index, tel que le site le decouvre.
|
||||
n = decouverts.get(locataire.nom)
|
||||
if n is None:
|
||||
ecarts.append("le site ne decouvre pas ce locataire")
|
||||
elif n.get("index") != f["index"]:
|
||||
ecarts.append(f"index : le site decouvre {n.get('index')}, la face dit {f['index']}")
|
||||
|
||||
# 2. Les machines et leurs groupes, tels que le pare-feu Proxmox les range.
|
||||
ips = {h: m["ip"] for h, m in f["machines"].items()}
|
||||
if bloc is None:
|
||||
ecarts.append("le devis Proxmox n'a aucun bloc pour ce locataire")
|
||||
else:
|
||||
ens = bloc.get("ipsets") or {}
|
||||
flotte = next((v["membres"] for v in ens.values() if str(v.get("role", "")).startswith("flotte")), [])
|
||||
if sorted(flotte) != sorted(set(ips.values())):
|
||||
ecarts.append(f"flotte : le devis Proxmox range {sorted(flotte)}, la face {sorted(set(ips.values()))}")
|
||||
# Le devis ne garde que les ensembles que ses regles UTILISENT : chaque groupe qu'il range
|
||||
# doit exister dans la face avec les memes adresses ; un groupe inutilise n'est pas un ecart.
|
||||
speciaux = ("flotte", "Internet", "reseaux d'admin")
|
||||
par_groupe = {str(v.get("role")): sorted(v.get("membres") or []) for v in ens.values()
|
||||
if not str(v.get("role", "")).startswith(speciaux)}
|
||||
for g, membres in sorted(par_groupe.items()):
|
||||
if g not in f["groupes"]:
|
||||
ecarts.append(f"groupe {g} : range par le devis Proxmox, absent de la face")
|
||||
elif membres != sorted({ips[h] for h in f["groupes"][g]}):
|
||||
ecarts.append(f"groupe {g} : le devis Proxmox range {membres}, "
|
||||
f"la face {sorted({ips[h] for h in f['groupes'][g]})}")
|
||||
adm = next((v["membres"] for v in ens.values() if str(v.get("role", "")).startswith("reseaux d'admin")), [])
|
||||
attendu_adm = sorted(set(f["administration"]["intrant"]) | set(f["administration"]["tunnel"]))
|
||||
if sorted(adm) != attendu_adm:
|
||||
ecarts.append(f"administration (Proxmox) : le devis admet {sorted(adm)}, la face {attendu_adm}")
|
||||
|
||||
# 3. L'administration, telle que la frontiere la lit.
|
||||
if admin_frontiere != sorted(f["administration"]["intrant"]):
|
||||
ecarts.append(f"administration (frontiere) : le site lit {admin_frontiere}, "
|
||||
f"la face {sorted(f['administration']['intrant'])}")
|
||||
|
||||
# 4. Le DNS public et la sauvegarde, tels que l'inventaire du site les porte.
|
||||
relations = [r for v in hv_site.values() for r in (v.get("serveur_dns_public_relations") or [])
|
||||
if r.get("ecosysteme") == locataire.nom]
|
||||
rel = relations[0] if relations else {}
|
||||
attendu_dns = f["dns_public"]
|
||||
vu_dns = ({k: rel.get(k) for k in ("zones", "signees", "primaire", "port")} if rel else {})
|
||||
if vu_dns != attendu_dns:
|
||||
ecarts.append(f"DNS public : l'inventaire du site porte {vu_dns}, la face {attendu_dns}")
|
||||
comptes = [c for v in hv_site.values() for c in (v.get("serveur_backup_site_locataires") or [])
|
||||
if c.get("nom") == locataire.nom]
|
||||
cle_site = comptes[0].get("pubkey") if comptes else ""
|
||||
if (cle_site or "") != f["sauvegarde"]["cle_publique"]:
|
||||
ecarts.append("sauvegarde : la cle que le site autorise n'est pas celle que le locataire publie")
|
||||
return ecarts
|
||||
|
||||
|
||||
def couples_hebergeur() -> list[tuple["Site", "Locataire"]]:
|
||||
"""Chaque (site, locataire) dont ce site est l'hebergeur ACTIF — les seuls qui ont une fiche
|
||||
a verifier : un site de reprise ne depose rien tant que la bascule n'a pas eu lieu."""
|
||||
|
|
@ -534,7 +684,26 @@ def main(argv: list[str] | None = None) -> int:
|
|||
ap.add_argument("--fiche", metavar="LOCATAIRE", help="la fiche que son hebergeur lui destine")
|
||||
ap.add_argument("--verifier-fiches", action="store_true",
|
||||
help="chaque fiche dit-elle ce que le locataire porte ?")
|
||||
ap.add_argument("--face", metavar="LOCATAIRE", help="la face reseau qu'il publie pour son site")
|
||||
ap.add_argument("--verifier-faces", action="store_true",
|
||||
help="chaque face reseau dit-elle ce que le site en tire ?")
|
||||
args = ap.parse_args(argv)
|
||||
if args.face:
|
||||
print(yaml.safe_dump(Locataire.charger(args.face).face_reseau(), allow_unicode=True,
|
||||
sort_keys=False), end="")
|
||||
return 0
|
||||
if args.verifier_faces:
|
||||
couples = couples_hebergeur()
|
||||
if not couples:
|
||||
print("Aucun site frere : aucune face reseau a verifier.")
|
||||
return 0
|
||||
total = 0
|
||||
for site, loc in couples:
|
||||
e = verifier_face(site, loc)
|
||||
total += len(e)
|
||||
print(f"{'OK ' if not e else 'ECART'} {loc.nom} -> {site.nom}"
|
||||
+ "".join(f"\n - {x}" for x in e))
|
||||
return 1 if total else 0
|
||||
if args.fiche:
|
||||
loc = Locataire.charger(args.fiche)
|
||||
site = loc.site()
|
||||
|
|
|
|||
|
|
@ -4692,6 +4692,29 @@ def preuve_fiche_du_site() -> tuple[bool, str]:
|
|||
f"porte (copies, racine, inventaire genere).")
|
||||
|
||||
|
||||
def preuve_face_reseau() -> tuple[bool, str]:
|
||||
"""La face reseau que chaque locataire publie dit-elle ce que les consommateurs du site en
|
||||
tirent aujourd'hui, en lisant ses fichiers internes ?
|
||||
|
||||
POURQUOI (2026-10-04, `docs/conception-contextes.md` §2.4). Le site lisait six fichiers
|
||||
internes de ses locataires — nomenclature, inventaire, `group_vars`, acces, domaines. La
|
||||
face reseau les publie, calculee chez le locataire. Avant que le site la lise a leur place
|
||||
(etape 3), elle doit dire EXACTEMENT ce que la decouverte, le devis Proxmox, la frontiere
|
||||
et l'inventaire du site en tirent. Les flux resolus suivront ; ils ne sont pas encore la.
|
||||
"""
|
||||
sys.path.insert(0, str(RACINE / "scripts"))
|
||||
import contexte as _ctx
|
||||
couples = _ctx.couples_hebergeur()
|
||||
if not couples:
|
||||
return True, "Aucun site frere : aucune face reseau a confronter."
|
||||
ecarts = [f"{l.nom} -> {s.nom} : {e}" for s, l in couples for e in _ctx.verifier_face(s, l)]
|
||||
if ecarts:
|
||||
return False, (f"{len(ecarts)} ecart(s) entre la face reseau et ce que le site en tire : "
|
||||
+ " | ".join(ecarts[:4]))
|
||||
return True, (f"{len(couples)} face(s) reseau : chacune dit exactement ce que le site en tire "
|
||||
f"(decouverte, devis Proxmox, frontiere, DNS public, sauvegarde).")
|
||||
|
||||
|
||||
PREUVES: list[dict] = [
|
||||
{"id": "P01", "titre": "Lint (ansible-lint)", "refs": ["AFF-006"],
|
||||
"cmds": [["ansible-lint", "-q"]]},
|
||||
|
|
@ -4880,6 +4903,8 @@ PREUVES: list[dict] = [
|
|||
"refs": [], "func": preuve_runbooks_suivent_le_makefile},
|
||||
{"id": "P84", "titre": "La fiche du site dit exactement ce que chaque locataire porte",
|
||||
"refs": [], "func": preuve_fiche_du_site},
|
||||
{"id": "P85", "titre": "La face reseau du locataire dit exactement ce que le site en tire",
|
||||
"refs": [], "func": preuve_face_reseau},
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ Sur une arborescence FABRIQUEE (un site, deux locataires, un depot ambigu), on v
|
|||
- un contexte nomme qui ne designe rien est un REFUS, pas un contexte vide.
|
||||
Puis, si les vrais depots sont la : chaque locataire declare par un site porte l'index que ce
|
||||
site lui attribue, et nomme un hebergeur qui existe ; la fiche de chaque hebergeur dit
|
||||
exactement ce que son locataire porte, et une fiche alteree (sept facons) est vue en ecart.
|
||||
exactement ce que son locataire porte, et une fiche alteree (sept facons) est vue en ecart ; la face
|
||||
reseau de chaque locataire dit ce que les consommateurs du site en tirent, et une face alteree
|
||||
(huit facons) est vue en ecart.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
@ -198,6 +200,44 @@ def fiches() -> None:
|
|||
f"une fiche alteree ({nom}) est vue en ecart")
|
||||
|
||||
|
||||
def faces() -> None:
|
||||
"""La face reseau dit ce que les consommateurs du site en tirent — et chaque ecart se voit."""
|
||||
import copy
|
||||
couples = C.couples_hebergeur()
|
||||
if not couples:
|
||||
print("SAUTE aucun site frere : aucune face reseau a confronter")
|
||||
return
|
||||
for site, loc in couples:
|
||||
e = C.verifier_face(site, loc)
|
||||
verifier(not e, f"face reseau {loc.nom} -> {site.nom} : identique a ce que le site en tire"
|
||||
+ (f" ({e[0]})" if e else ""))
|
||||
site, loc = couples[0]
|
||||
juste = loc.face_reseau()
|
||||
groupe = next(g for g in ("serveur_postfix", "serveur_nginx", "client_backup") if juste["groupes"].get(g))
|
||||
hote = juste["groupes"][groupe][0]
|
||||
|
||||
def deplacer_machine(f):
|
||||
f["machines"][hote]["ip"] = "192.0.2.10"
|
||||
|
||||
def retirer_du_groupe(f):
|
||||
f["groupes"][groupe] = [h for h in f["groupes"][groupe] if h != hote]
|
||||
|
||||
alterations = {
|
||||
"index": lambda f: f.__setitem__("index", (f["index"] or 0) + 1),
|
||||
"adresse d'une machine": deplacer_machine,
|
||||
f"membres du groupe {groupe}": retirer_du_groupe,
|
||||
"administration declaree": lambda f: f["administration"].__setitem__("intrant", ["192.0.2.0/24"]),
|
||||
"tunnel d'administration": lambda f: f["administration"].__setitem__("tunnel", ["192.0.2.128/25"]),
|
||||
"zones publiques": lambda f: f["dns_public"].__setitem__("zones", ["exemple.invalid"]),
|
||||
"primaire DNS": lambda f: f["dns_public"].__setitem__("primaire", "192.0.2.53"),
|
||||
"cle de sauvegarde": lambda f: f["sauvegarde"].__setitem__("cle_publique", "ssh-ed25519 AAAA-fausse"),
|
||||
}
|
||||
for nom, alterer in alterations.items():
|
||||
f = copy.deepcopy(juste)
|
||||
alterer(f)
|
||||
verifier(bool(C.verifier_face(site, loc, f)), f"une face reseau alteree ({nom}) est vue en ecart")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
d = Path(tmp)
|
||||
|
|
@ -207,6 +247,7 @@ def main() -> int:
|
|||
vrais_depots()
|
||||
monter_restaure()
|
||||
fiches()
|
||||
faces()
|
||||
if ECHECS:
|
||||
print(f"\n{len(ECHECS)} echec(s).")
|
||||
return 1
|
||||
|
|
|
|||
Loading…
Reference in a new issue