diff --git a/cmd/lab/main_test.go b/cmd/lab/main_test.go index fe17d78..733fd3c 100644 --- a/cmd/lab/main_test.go +++ b/cmd/lab/main_test.go @@ -27,7 +27,7 @@ func TestRun_UsageOnMissingArguments(t *testing.T) { } func TestRun_PlanOfTheShippedExampleTopology(t *testing.T) { - code, stdout, stderr := runLab("plan", filepath.Join("..", "..", "conf", "lab", "evpn-2hv.yml")) + code, stdout, stderr := runLab("plan", filepath.Join("..", "..", "test", "e2e", "topologies", "evpn-2hv.yml")) if code != 0 { t.Fatalf("code %d, stderr %s", code, stderr) } @@ -82,7 +82,7 @@ func TestRun_RenderWritesEveryNodeFiles(t *testing.T) { t.Fatal(err) } out := filepath.Join(dir, "run") - code, stdout, stderr := runLab("render", "-key", key, filepath.Join("..", "..", "conf", "lab", "evpn-2hv.yml"), out) + code, stdout, stderr := runLab("render", "-key", key, filepath.Join("..", "..", "test", "e2e", "topologies", "evpn-2hv.yml"), out) if code != 0 { t.Fatalf("code %d, stderr %s", code, stderr) } @@ -118,7 +118,7 @@ func TestRun_RenderWritesEveryNodeFiles(t *testing.T) { } func TestRun_RenderRefusesMissingKeyFile(t *testing.T) { - code, _, stderr := runLab("render", "-key", filepath.Join(t.TempDir(), "absent.pub"), filepath.Join("..", "..", "conf", "lab", "evpn-2hv.yml"), t.TempDir()) + code, _, stderr := runLab("render", "-key", filepath.Join(t.TempDir(), "absent.pub"), filepath.Join("..", "..", "test", "e2e", "topologies", "evpn-2hv.yml"), t.TempDir()) if code != 1 || !strings.Contains(stderr, "absent.pub") { t.Errorf("code %d, stderr %q", code, stderr) } @@ -130,7 +130,7 @@ func savedLab(t *testing.T) string { if err := os.MkdirAll(run, 0o700); err != nil { t.Fatal(err) } - example, err := os.ReadFile(filepath.Join("..", "..", "conf", "lab", "evpn-2hv.yml")) + example, err := os.ReadFile(filepath.Join("..", "..", "test", "e2e", "topologies", "evpn-2hv.yml")) if err != nil { t.Fatal(err) } @@ -308,7 +308,7 @@ func TestRun_RenderShipsTheExampleFRRConfigs(t *testing.T) { t.Fatal(err) } out := filepath.Join(dir, "run") - code, _, stderr := runLab("render", "-key", key, filepath.Join("..", "..", "conf", "lab", "evpn-2hv.yml"), out) + code, _, stderr := runLab("render", "-key", key, filepath.Join("..", "..", "test", "e2e", "topologies", "evpn-2hv.yml"), out) if code != 0 { t.Fatalf("code %d, stderr %s", code, stderr) } diff --git a/docs/deploiement/route-reflector.rst b/docs/deploiement/route-reflector.rst index d8977ce..a9bcb08 100644 --- a/docs/deploiement/route-reflector.rst +++ b/docs/deploiement/route-reflector.rst @@ -57,10 +57,10 @@ Configuration de FRR -------------------- ``bgpd`` et ``bfdd`` activés dans ``/etc/frr/daemons``. La configuration ci-dessous est **celle du -lab** (``conf/lab/frr/rr1.conf``) : ASN, loopback et plages sont ceux de la production, seul le nom +lab** (``test/e2e/topologies/frr/rr1.conf``) : ASN, loopback et plages sont ceux de la production, seul le nom d'hôte diffère. Le lab qualifie donc exactement ce fichier. -.. literalinclude:: ../../conf/lab/frr/rr1.conf +.. literalinclude:: ../../test/e2e/topologies/frr/rr1.conf :language: text Ce qu'elle établit : diff --git a/docs/developpement/lab.rst b/docs/developpement/lab.rst index 95a18a2..6e01936 100644 --- a/docs/developpement/lab.rst +++ b/docs/developpement/lab.rst @@ -17,7 +17,7 @@ comment s'en servir. topologie déclarative et plan déterministe (``lab plan``), VM rendues et lancées sur le serveur (``lab render``, ``lab up`` / ``status`` / ``down`` / ``ssh``), rôles installés au démarrage (FRR sur le switch et le route reflector, two par ``deploy.sh`` sur les - hyperviseurs) et scénarios versionnés (``scripts/lab/scenario.sh``). La redondance du plan de + hyperviseurs) et scénarios versionnés (``test/e2e/run.sh``). La redondance du plan de contrôle — deux route reflectors, deux switchs — est l'objet de `#54 `_. @@ -179,7 +179,7 @@ Une campagne sur le lab enchaîne ces commandes depuis le Mac ; ``lab`` s'exécu .. code-block:: text scripts/lab-host.sh up - scripts/lab-host.sh push conf/lab/evpn-2hv.yml + scripts/lab-host.sh push test/e2e/topologies/evpn-2hv.yml scripts/lab-host.sh ssh './lab up topology/evpn-2hv.yml' scripts/lab-host.sh ssh './lab ssh hv1' # shell interactif sur hv1 scripts/lab-host.sh ssh './lab ssh hv1 ip -br a' # commande, code de retour propagé @@ -194,9 +194,9 @@ Topologie --------- Un lab est décrit par un fichier YAML : des **nœuds** (les VM) et des **segments** (des réseaux L2 -portés par un switch). Exemple livré, ``conf/lab/evpn-2hv.yml`` : +portés par un switch). Exemple livré, ``test/e2e/topologies/evpn-2hv.yml`` : -.. literalinclude:: ../../conf/lab/evpn-2hv.yml +.. literalinclude:: ../../test/e2e/topologies/evpn-2hv.yml :language: yaml Chaque nœud non-switch est relié au switch de chacun de ses segments par un câble virtuel QEMU ; @@ -236,7 +236,7 @@ Ce que le fichier déclare : * ``agent`` — pour un hyperviseur seulement : le chemin d'un ``agent.yml``, relatif au fichier de topologie, déposé dans ``/etc/two/agent.yml`` avant ``deploy.sh``. Sans lui, l'agent tourne avec sa configuration par défaut. L'exemple met hv1 sur le serveur DHCP intégré - (``conf/lab/agent/two.yml`` : ``dhcp.backend: two``) et laisse hv2 sur dnsmasq. + (``test/e2e/topologies/agent/two.yml`` : ``dhcp.backend: two``) et laisse hv2 sur dnsmasq. ``mgmt0`` et ``lo1`` sont réservés : aucun segment ne peut porter ces noms. @@ -272,7 +272,7 @@ Limites : 1000 nœuds, 256 segments, et autant de câbles que la plage UDP le pe .. code-block:: text - $ go run ./cmd/lab plan conf/lab/evpn-2hv.yml + $ go run ./cmd/lab plan test/e2e/topologies/evpn-2hv.yml lab evpn-2hv: nodes 4, segments 1, cables 3 nodes @@ -308,7 +308,7 @@ champs inconnus et les clés en double sont refusés aussi : Les ASN, la loopback du route reflector, le lien ``169.254.0.0/28`` et le subnet des hyperviseurs de l'exemple sont **ceux de la production** (décision du 2026-10-04, #50) : les fichiers de -``conf/lab/`` restent ainsi au plus près de ce qui tourne réellement. Toutes les adresses y sont +``test/e2e/topologies/`` restent ainsi au plus près de ce qui tourne réellement. Toutes les adresses y sont **fixées** par ``addresses`` — le route reflector en ``.2``, les hyperviseurs à partir de ``.11`` — pour que le modèle se lise sans le plan et ne dépende pas de l'ordre de déclaration : le ``frr.conf`` d'un hyperviseur, écrit à la main, porte son adresse en ``router-id``. Seul le switch @@ -317,11 +317,11 @@ n'en déclare pas : il porte toujours la passerelle, la première adresse du seg Rôles ~~~~~ -Les configurations FRR du lab vivent dans ``conf/lab/frr/``, une par nœud, **écrites à la main** : +Les configurations FRR du lab vivent dans ``test/e2e/topologies/frr/``, une par nœud, **écrites à la main** : ce sont les mêmes fichiers que la documentation de déploiement inclut, pour que le lab qualifie exactement ce qu'elle prescrit. Celle du route reflector : -.. literalinclude:: ../../conf/lab/frr/rr1.conf +.. literalinclude:: ../../test/e2e/topologies/frr/rr1.conf :language: text Au premier démarrage, cloud-init installe FRR (``frr-stable`` de ``deb.frrouting.org``, sans les @@ -421,7 +421,7 @@ Vérifié le 2026-10-04 sur le serveur de lab, topologie ``evpn-2hv``, release ` **Le switch du lab est un routeur Linux avec FRR, par choix.** Il joue le rôle générique de routeur de cluster : passerelle des hyperviseurs, session eBGP avec BFD vers le route reflector, - dont il n'accepte que la loopback (``conf/lab/frr/sw1.conf``). L'équipement réel dépend de qui + dont il n'accepte que la loopback (``test/e2e/topologies/frr/sw1.conf``). L'équipement réel dépend de qui déploie l'infrastructure (MikroTik aujourd'hui ; Cisco, Juniper, Arista… demain) : il n'a besoin que de BGP et d'EVPN, et sa configuration propre au constructeur n'a pas sa place dans le lab. @@ -432,7 +432,7 @@ Rendu des VM .. code-block:: text - $ go run ./cmd/lab render -key ~/.config/two-lab/ssh/lab_ed25519.pub conf/lab/evpn-2hv.yml + $ go run ./cmd/lab render -key ~/.config/two-lab/ssh/lab_ed25519.pub test/e2e/topologies/evpn-2hv.yml ``//`` reçoit : @@ -611,7 +611,7 @@ Une campagne réelle, de la création du serveur à la première commande sur un … qemu QEMU emulator version 7.2.22 (Debian 1:7.2+dfsg-7+deb12u18+b3), nested=Y == prêt : root@ - $ scripts/lab-host.sh push conf/lab/evpn-2hv.yml + $ scripts/lab-host.sh push test/e2e/topologies/evpn-2hv.yml == compilation de lab (linux/amd64) == déposés sur le serveur : ~/lab, ~/evpn-2hv.yml — ensuite : lab-host.sh ssh './lab up evpn-2hv.yml' $ scripts/lab-host.sh ssh './lab up evpn-2hv.yml' @@ -674,9 +674,9 @@ Les scénarios se lancent **depuis le Mac**, sur un lab démarré (``up``, ``pus .. code-block:: text - scripts/lab/scenario.sh s1 # un scénario - scripts/lab/scenario.sh s1 s3 # plusieurs - scripts/lab/scenario.sh all # tous, dans l'ordre + test/e2e/run.sh s1 # un scénario + test/e2e/run.sh s1 s3 # plusieurs + test/e2e/run.sh all # tous, dans l'ordre Chacun affiche une ligne ``RÉUSSI`` ou ``ÉCHOUÉ`` par vérification — un échec porte la dernière ligne de la commande en cause —, des lignes ``INFO`` pour les mesures, puis son bilan. Le code de @@ -720,9 +720,9 @@ sortie vaut 1 si une vérification échoue **ou si aucune n'a été faite**. ``s6`` réutilise les VM de ``s4`` : le lancer après. -**Comment c'est fait.** ``scripts/lab/scenario.sh`` exécute chaque scénario sur le Mac ; un +**Comment c'est fait.** ``test/e2e/run.sh`` exécute chaque scénario sur le Mac ; un scénario envoie des blocs de shell aux nœuds par ``on [VAR=valeur…] <<'NODE'``, précédés de -``scripts/lab/node.sh`` — appels à l'API de l'agent, attente des états, image Debian compatible two +``test/e2e/lib/node.sh`` — appels à l'API de l'agent, attente des états, image Debian compatible two (préparée une fois par hyperviseur, ``seedfrom`` avec barre oblique finale), clé SSH des VM, ``check`` et ``vm_fails``. Une vérification négative (« ne joint pas ») passe par ``vm_fails`` : elle n'est réussie que si le SSH vers la VM a fonctionné **et** que la commande y a échoué — un @@ -733,7 +733,7 @@ hv2 sur dnsmasq — toute la série en 8 minutes : .. code-block:: text - $ scripts/lab/scenario.sh all | grep -E '^(=== s[0-9].* : |INFO)' + $ test/e2e/run.sh all | grep -E '^(=== s[0-9].* : |INFO)' INFO: MAC de sn-s1a : 00:22:33:00:00:0a 00:22:33:00:00:0b ; de sn-s1b : 00:22:33:00:00:0a 00:22:33:00:00:0b === s1-dhcp-two : 37 réussi(s), 0 échoué(s) === s2-gateway : 22 réussi(s), 0 échoué(s) @@ -763,7 +763,7 @@ Les VM sont accessibles depuis le netns de leur VPC, sur l'hyperviseur, avec l'u Le lab sert à qualifier des comportements qui ne se voient qu'à plusieurs hyperviseurs — la campagne L3VNI de `#41 `_ en est le prochain exemple. Un -scénario est un fichier ``scripts/lab/scenarios/-.sh``, exécuté par ``scenario.sh`` sur le +scénario est un fichier ``test/e2e/scenarios/-.sh``, exécuté par ``scenario.sh`` sur le Mac ; il envoie des blocs aux nœuds : .. code-block:: bash @@ -796,7 +796,7 @@ Les règles qui ont fait leurs preuves en E5 : (``check "prérequis : …"``) ; * variables vers un nœud : ``on hv1 NOM=valeur <<'NODE'`` (valeurs échappées par ``scenario.sh``) ; -* ``bash scripts/lab/scenario_test.sh`` vérifie la syntaxe de chaque bloc réellement envoyé — à +* ``bash test/e2e/run_test.sh`` vérifie la syntaxe de chaque bloc réellement envoyé — à lancer avant toute session. Facturation @@ -890,7 +890,7 @@ Tests .. code-block:: bash bash scripts/lab-host_test.sh - bash scripts/lab/scenario_test.sh + bash test/e2e/run_test.sh go test ./internal/lab/... ./cmd/lab/ Environ une minute et demie, sans réseau : la suite remplace ``curl`` par une fausse API Scaleway diff --git a/scripts/lab/node.sh b/test/e2e/lib/node.sh similarity index 100% rename from scripts/lab/node.sh rename to test/e2e/lib/node.sh diff --git a/scripts/lab/scenario.sh b/test/e2e/run.sh similarity index 94% rename from scripts/lab/scenario.sh rename to test/e2e/run.sh index 58a6d24..4b9e84d 100755 --- a/scripts/lab/scenario.sh +++ b/test/e2e/run.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash LAB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -LAB_HOST="${LAB_HOST:-${LAB_DIR}/../lab-host.sh}" +LAB_HOST="${LAB_HOST:-${LAB_DIR}/../../scripts/lab-host.sh}" SCENARIO_DIR="${SCENARIO_DIR:-${LAB_DIR}/scenarios}" SCENARIO_LOG="" @@ -25,7 +25,7 @@ on () { for assignment in "$@"; do printf 'export %q=%q\n' "${assignment%%=*}" "${assignment#*=}" done - cat "${LAB_DIR}/node.sh" + cat "${LAB_DIR}/lib/node.sh" cat } | "${LAB_HOST}" ssh "./lab ssh ${node} 'sudo bash -s'" 2>&1 | tee -a "${SCENARIO_LOG}" } diff --git a/scripts/lab/scenario_test.sh b/test/e2e/run_test.sh similarity index 98% rename from scripts/lab/scenario_test.sh rename to test/e2e/run_test.sh index 0ca394c..dd8022f 100755 --- a/scripts/lab/scenario_test.sh +++ b/test/e2e/run_test.sh @@ -29,7 +29,7 @@ FAKE run () { env LAB_HOST="${WORK}/lab-host" FAKE_DIR="${WORK}" SCENARIO_DIR="${SCENARIO_DIR:-${WORK}/scenarios}" \ - FAKE_OUT="${FAKE_OUT:-}" bash "${DIR}/scenario.sh" "$@" > "${WORK}/out.log" 2>&1 + FAKE_OUT="${FAKE_OUT:-}" bash "${DIR}/run.sh" "$@" > "${WORK}/out.log" 2>&1 } teardown () { @@ -39,7 +39,7 @@ teardown () { } node () { - bash -c ". '${DIR}/node.sh'; ${1}" 2>&1 + bash -c ". '${DIR}/lib/node.sh'; ${1}" 2>&1 } test_on_sends_assignments_library_and_block_to_the_node () { diff --git a/scripts/lab/scenarios/s1-dhcp-two.sh b/test/e2e/scenarios/s1-dhcp-two.sh similarity index 100% rename from scripts/lab/scenarios/s1-dhcp-two.sh rename to test/e2e/scenarios/s1-dhcp-two.sh diff --git a/scripts/lab/scenarios/s2-gateway.sh b/test/e2e/scenarios/s2-gateway.sh similarity index 100% rename from scripts/lab/scenarios/s2-gateway.sh rename to test/e2e/scenarios/s2-gateway.sh diff --git a/scripts/lab/scenarios/s3-isolation-local.sh b/test/e2e/scenarios/s3-isolation-local.sh similarity index 100% rename from scripts/lab/scenarios/s3-isolation-local.sh rename to test/e2e/scenarios/s3-isolation-local.sh diff --git a/scripts/lab/scenarios/s4-evpn.sh b/test/e2e/scenarios/s4-evpn.sh similarity index 100% rename from scripts/lab/scenarios/s4-evpn.sh rename to test/e2e/scenarios/s4-evpn.sh diff --git a/scripts/lab/scenarios/s5-isolation-evpn.sh b/test/e2e/scenarios/s5-isolation-evpn.sh similarity index 100% rename from scripts/lab/scenarios/s5-isolation-evpn.sh rename to test/e2e/scenarios/s5-isolation-evpn.sh diff --git a/scripts/lab/scenarios/s6-rr-loss.sh b/test/e2e/scenarios/s6-rr-loss.sh similarity index 100% rename from scripts/lab/scenarios/s6-rr-loss.sh rename to test/e2e/scenarios/s6-rr-loss.sh diff --git a/conf/lab/agent/two.yml b/test/e2e/topologies/agent/two.yml similarity index 100% rename from conf/lab/agent/two.yml rename to test/e2e/topologies/agent/two.yml diff --git a/conf/lab/evpn-2hv.yml b/test/e2e/topologies/evpn-2hv.yml similarity index 100% rename from conf/lab/evpn-2hv.yml rename to test/e2e/topologies/evpn-2hv.yml diff --git a/conf/lab/frr/hv1.conf b/test/e2e/topologies/frr/hv1.conf similarity index 100% rename from conf/lab/frr/hv1.conf rename to test/e2e/topologies/frr/hv1.conf diff --git a/conf/lab/frr/hv2.conf b/test/e2e/topologies/frr/hv2.conf similarity index 100% rename from conf/lab/frr/hv2.conf rename to test/e2e/topologies/frr/hv2.conf diff --git a/conf/lab/frr/rr1.conf b/test/e2e/topologies/frr/rr1.conf similarity index 100% rename from conf/lab/frr/rr1.conf rename to test/e2e/topologies/frr/rr1.conf diff --git a/conf/lab/frr/sw1.conf b/test/e2e/topologies/frr/sw1.conf similarity index 100% rename from conf/lab/frr/sw1.conf rename to test/e2e/topologies/frr/sw1.conf