gestion multi subnet #33
Labels
No labels
bug fix
feature implementation
new feature
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
syonad/two#33
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
il faut implementer une gestion multi subnet dans les vms, l'api la gere deja il faut le faire coter dispatcher et gestion qemu
Constat
L'information est perdue dès le handler.
internal/api/agent/vms.goparcourtreq.Interfacesuniquement pour trouver celle marquéeprimary, puis ne transmet queprimary.Subnetetprimary.IP. Les autres interfaces sont jetées en silence, sans erreur ni log : une VM demandée avec trois interfaces en obtient une, et l'appelant reçoit 202.Tout le reste de la chaîne est singulier :
StartVMCommand{Subnet, IP}, les clésvm/<name>/{subnet,ip,tap_id},vmData, un seulnetns.Callpour le tap et la redirection metadata,-netdev tap,id=net0avecaddr=0x03en dur côté QEMU, etvmFromDBqui reconstruit un tableau d'une seule entrée toujours marquéeprimary.Contrainte posée : multi-interfaces dans un même VPC uniquement. Donc un seul netns, ce qui simplifie
StartVMet rend le serveur de métadonnées joignable depuis toutes les interfaces de la VM.Le point dur : une seule route par défaut
Une route par défaut est aujourd'hui toujours annoncée par chaque subnet. Une VM multi-NIC en recevrait autant que d'interfaces. Il faut donc que la route par défaut devienne une propriété du couple VM × interface, pas du subnet.
Faits mesurés sur lab3 — dnsmasq 2.90
Testés en netns isolés, pas supposés.
0.0.0.0/0fait disparaître la route/32vers169.254.169.254. Tout override doit donc réémettre la route metadata, sous peine de casser le provisionnement cloud-init.dhcp-hostsdir/dhcp-optsdirsont lus à chaud, sans signal ni redémarrage (read /path/to/filedans le log). En revanche un fichier supprimé n'est pas pris en compte avant SIGHUP ou redémarrage.dhcp-hostbloque celle duhostsdirpour la même adresse :duplicate dhcp-host IP address … at line 1 of hosts.d/vm1, le tag n'est jamais posé, et la VM reçoit la mauvaise route sans qu'aucune erreur ne remonte — dnsmasq démarre normalement. La pré-génération des entrées du range doit donc disparaître.dhcp-macdans le.conffonctionne aussi, mais le.confn'est pas rechargé à chaud : il faudrait redémarrer dnsmasq à chaque création de VM. Écarté.Schéma KV
Même motif que
disk/<dev>(#32) etmetadata/<document>(#34) :L'index n'est pas décoratif : il détermine le slot PCI (
0x03 + i, dans la plage0x03–0x1dréservée au multi-NIC par #36), donc le nom de l'interface dans le guest. Le nommage reste stable si une interface est retirée.Étapes
1 — dnsmasq passe aux répertoires. Le
.confgardedhcp-range, le DNS, la route/32metadata non taggée, et pointe vershostsdir/optsdir. Suppression de la pré-génération du range : la table IP→MAC reste en base soussubnet/<name>/dhcp/<ip>, oùGetMACForIPva la chercher ; seules les entrées réellement utilisées descendent dans dnsmasq. Vérification : une VM mono-NIC se comporte exactement comme avant.2 — Schéma KV et migration. Migration idempotente au démarrage : toute VM ayant
/subnetsans/nic/devientnic/0avecprimary=true, anciennes clés supprimées. Livrée dans le même changement que les lecteurs — la leçon de l'enum d'états (#37) : une étape intermédiaire qui lit le nouveau schéma sans la migration rendrait toutes les VM existantes illisibles.3 — Dispatcher et API.
StartVMCommand.NICs []VMNIC, refus si zéro ou plusieurs primaires, écriture des clés.vmFromDBreconstruit toutes les interfaces au lieu d'en fabriquer une.api/agent.yaml.4 —
StartVM/StopVM. Boucle sur les interfaces : un tap par NIC, une redirection DNAT par IP, les fichiers dnsmasq par interface.StopVMsymétrique, et à la suppression retrait des fichiers puisRestart+Statussur l'unit dnsmasq — un retrait n'est pas relu à chaud (fait 3).5 — QEMU. Un
-netdev/-devicepar interface,id=net<i>,addr=0x03+i. Garde-fou au-delà de 27 interfaces, sur le modèle du garde-fouvdXde #36.6 — Watchdog.
checkVMTapne vérifie qu'un tap ; il doit tous les vérifier.7 — lab3. VM mono-NIC en non-régression, VM bi-NIC, et surtout
ip routedans le guest : une seule route par défaut, celle de l'interface primaire, et la route metadata présente sur toutes.Métadonnées
metadata_portreste au niveau de la VM. Le serveur écoute sur l'interface_ipdu subnet primaire, et la redirection DNAT est installée pour chacune des IP de la VM vers cette même adresse. Tout étant dans le même VPC, donc le même netns, elle est joignable depuis n'importe quelle interface — les métadonnées fonctionnent quelle que soit la route empruntée, sans tag.Correction du découpage
Le découpage en sept étapes que j'ai décrit plus haut n'est pas déployable tel quel : deux étapes laissent le dépôt incohérent entre elles. C'est la leçon de #37 — chaque étape doit laisser le dépôt fonctionnel — que je n'avais pas appliquée à mon propre plan.
Étape 1 annonçait la suppression de la pré-génération avec pour vérification « une VM mono-NIC se comporte comme avant ». Impossible : avec
dhcp-range=…,staticil n'y a pas de pool dynamique, donc sans réservation par VM aucune VM n'obtient d'adresse. L'écriture du fichier de réservation a donc été intégrée à l'étape 1.Étapes 2 et 3 séparaient le schéma KV et ses lecteurs (2) de l'écrivain, le dispatcher (3). Entre les deux,
loadVMliraitnic/<i>pendant quePrepareécrirait encorevm/<name>/subnet: toute VM créée dans cet intervalle serait illisible. Les deux sont fusionnées.Découpage effectif
dhcp-hostsdir/dhcp-optsdir, fin de la pré-génération, un fichier de réservation par VM (sans tag)vm/<name>/nic/<i>/…, migration, dispatcher,loadVM,vmFromDB, API-netdev/-devicepar interface, slot PCI0x03 + iL'étape 2 change le schéma sans changer le comportement : une collection à un seul élément. C'est ce qui la rend vérifiable — une VM existante continue de tourner, une VM créée après est identique à ce qu'elle était.
Étape 1 — livrée
Le
.confd'un subnet passe de 517 à 7 lignes. Les options restent non taggées à ce stade.La table IP→MAC conserve ses 512 entrées, mais uniquement en base sous
subnet/<name>/dhcp/<ip>, oùGetMACForIPva la chercher. Seules les réservations utilisées descendent dans dnsmasq.StartVMécrithosts.d/<vm>;StopVMretire le fichier puis redémarre dnsmasq et vérifie son statut — un ajout est relu à chaud, un retrait ne l'est pas.pkg/systemda gagnéRestart.DeleteSubnetsupprime les deux répertoires.WriteReservationséchoue si la liste est vide ou si une MAC ou une IP manque : écrire un fichier vide donnerait une VM sans adresse, sans aucun signal.TestGenerateConfig_NoPreGeneratedHostsverrouille la décision, avec sa raison en commentaire.Validé sur lab3
Mono-interface — non-régression
Table de routage du guest identique à avant, une seule interface, métadonnées joignables. Surtout :
opts.d/vide. Une VM mono-interface ne génère aucun fichier d'options, son comportement est rigoureusement inchangé — c'est le résultat qui concerne toutes les VM existantes.Deux interfaces
C'est l'objet du ticket. Deux interfaces, deux adresses, une seule route par défaut, celle de la primaire.
Fichiers générés — le subnet de la primaire ne reçoit aucune option, celui de la seconde reçoit l'override :
Les slots PCI sont confirmés par les noms d'interfaces :
ens3etens4dérivent des slots0x03et0x04, dérivés eux-mêmes de l'index. C'est ce qui garantit un nommage stable dans le guest (cf. #36).Refus et suppression
Zéro comme deux interfaces primaires sont refusées en 400,
exactly one interface must be primary. À la suppression, la VM disparaît des deuxhosts.det ses deux taps sont retirés du netns.Une prévision que je corrige
J'avais annoncé que le choix entre les deux routes vers le CIDR du VPC et vers le serveur de métadonnées serait non déterministe. C'est faux : le client DHCP attribue une métrique par interface, dans l'ordre. La primaire étant en index 0 porte la métrique la plus basse et gagne systématiquement.
Nuance sans conséquence fonctionnelle : si la primaire n'était pas l'index 0, les routes metadata et VPC passeraient par l'autre interface. La route par défaut resterait correcte, et les métadonnées fonctionneraient quand même — la redirection DNAT est posée pour chaque IP de la VM, et les deux passerelles sont dans le même VPC.
Non vérifié
systemctl is-activesur les deux dnsmasq après suppression. LeDELETEn'a pas remonté d'erreur, donc le redémarrage a eu lieu, mais le contrôle explicite n'a pas été fait.Livré
dhcp-hostsdir/dhcp-optsdir, fin de la pré-génération, un fichier de réservation par VM. Le.confd'un subnet passe de 517 à 7 lignes ; la table IP→MAC reste en base pourGetMACForIP.vm/<name>/nic/<i>/…, migration idempotente au démarrage, dispatcher,loadVM,vmFromDB, watchdog.loadVMet l'API refusent désormais autre chose qu'exactement une interface primaire.-netdev/-devicepar interface avec le slot PCI dérivé de l'index. Garde-fou au-delà de 27 interfaces, la capacité de la carte PCI.Prérequis de déploiement : le format du
.confayant changé, les subnets existants doivent être recréés. Un agent à jour n'écrit plus dans l'ancien format.Corrections apportées au découpage en cours de route, faute d'étapes déployables isolément, dans le commentaire précédent.