Blog ·
Een capability-woord voor een oud commando
Voegt een ronde een protobuf-veld toe, dan faalt een oude agent luidruchtig. Verandert ze wat een vlag betekent, dan antwoordt hij aannemelijk en fout.
Door Provibr
Onze agent draait binnen het netwerk van de klant en belt naar buiten naar ons. Hij werkt zichzelf bij, maar niet meteen en niet altijd, dus op elk willekeurig moment is de vloot een spreiding van versies en moet het platform weten wat elke versie kan.
Het weet dat omdat de agent het zegt. Bij elke sessie stuurt de agent een lijst korte woorden, één per capability, en het platform weigert een commando waarvan het woord ontbreekt in plaats van het te sturen en te hopen.
Deze ronde voegde het derde van die woorden voor Proxmox-containers toe, en het is de eerste keer dat de interessante vraag niet was of het toegevoegd moest worden maar wat er zonder gebeurd zou zijn.
Waarom die woorden er überhaupt zijn
Het mechanisme beschermt tegen een specifieke eigenschap van protobuf: een onbekend veld in een oneof wordt weggegooid.
Voegt een ronde een nieuw commando toe als een nieuw veld, dan parseert een agent van vóór die ronde het bericht, herkent het veldnummer niet, gooit het weg, en houdt een ProxmoxCommand over zonder commando erin. Vervolgens zegt hij precies dat. Die melding is eerlijk en volstrekt nutteloos: de beheerder ziet een klacht over een lege envelop en de oorzaak ligt vier lagen verderop, in een versieverschil dat niemand genoemd heeft.
Dus weigert het platform eerst. Ontbreekt het woord, dan vertrekt het commando nooit, en de weigering noemt de capability en de versie van de agent. Dat is een slechtere uitkomst dan een commando dat werkt en een veel betere dan een commando dat faalt op een manier waar je een middag aan kwijt bent.
Het is hoe dan ook een luidruchtige mislukking. Dat blijkt uit te maken.
Het derde woord is geen nieuw veld
De wijziging van deze ronde was dat een container nu zijn hardware kan tonen. Het commando dat dat doet, GetHardware, is niet nieuw. Elke agent tot terug aan het vroege werk aan de levenscyclus van virtuele machines kent dat bericht en weet het te beantwoorden.
Wat veranderde is een vlag ernaast die zegt op welke soort resource de identificatie slaat. Een agent van vóór deze ronde ontvangt die vlag, kent hem niet, en gooit hem weg, precies zoals protobuf voorschrijft. Daarna doet hij wat hij altijd met een hardwareverzoek gedaan heeft: hij vraagt Proxmox om de configuratie van de machine op het QEMU-pad.
Niets is leeg. Niets klaagt. De agent gelooft dat hem een vraag gesteld is die hij begrijpt, en hij antwoordt.
Dat landt op twee manieren, en geen van beide is luidruchtig. Heeft Proxmox niets op die identificatie onder het pad van virtuele machines, dan krijgt de klant te horen dat een machine niet bestaat, over een container die voor zijn neus draait. En komt er wél een configuratie terug die aan de parser voor virtuele machines gegeven wordt, dan is het antwoord niet leeg maar fout.
Het foute antwoord is specifiek en het ziet er prima uit
De twee configuratieformaten liggen dicht genoeg bij elkaar om te parseren en verschillen genoeg om ertoe te doen. Een virtuele machine schrijft zijn eerste netwerkkaart als een model en een MAC-adres, verbonden door een isgelijkteken. Een container schrijft eerst een interfacenaam, en daarna het MAC-adres in een apart veld met een eigen sleutel.
De parser voor virtuele machines neemt het eerste sleutel-waardepaar als het model en het adres. Op de regel van een container meldt hij daarom een netwerkkaart waarvan het model name is en het MAC-adres ETH0.
Dat is een aannemelijk ogende rij in een tabel. Hij heeft een model, hij heeft een adres, hij wordt zonder waarschuwing weergegeven. Het is de reden dat het containerpad zijn eigen parser nodig had, en het is precies de soort defecten die niemand meldt, omdat er niets in zit om te melden. Iemand kijkt naar een scherm, vindt de modelkolom raar, en gaat verder.
Een commando dat al bestaat is dus een gevaarlijker soort wijziging dan een commando dat nieuw is. Het nieuwe faalt bij de envelop, in het openbaar. Dit faalt bij de betekenis, in stilte.
Waarom niets verruimen en er één regel bij zetten
Het voor de hand liggende alternatief is het woord verruimen dat er al is. Er is een woord dat zegt dat de agent het containerpad überhaupt begrijpt, en het had één teken werk gekost om het ook het nieuwere te laten betekenen.
Dat zou elk containercommando weigeren van elke agent die nog niet bijgewerkt is, inclusief de agents die vandaag perfect werken. Een vloot die op dit moment containers bedient zou donker gaan voor een capability die hij werkelijk heeft, omdat wij onder hem vandaan veranderd hadden wat ons woord betekende.
Een woord is een belofte over wat er gebouwd is, en die belofte moet zijn betekenis houden zolang iemand hem nog vasthoudt. Een derde woord toevoegen kost één constante aan elke kant en weigert precies de commando's die geweigerd moeten worden, en verder niets. Het zet de redenering bovendien op een plek waar iemand hem vindt, namelijk naast de constante en niet in een commitboodschap.
De twee kanten zijn twee constanten, één in de Rust-bron en één in het gedeelde TypeScript, die elkaar allebei noemen. Dat paar is niet elegant, en elke poging om het elegant te maken eindigt met een buildstap tussen twee talen die onafhankelijk van elkaar leesbaar moeten zijn.
De stub zegt er bewust twee van de drie
Er is een stub-agent waarmee we de gateway kunnen aansturen zonder hypervisor, en die kondigt de containerwoorden ook aan.
Hij kondigt er twee aan. Hij zegt dat hij het containerpad kent en hij zegt dat hij containerhardware leest, en hij claimt bewust het derde niet, want een container opnieuw installeren is iets wat hij niet kan.
Dat is het vermelden waard, want een stub die alles claimt is een stub die elk weigeringspad ontoetsbaar maakt. En het omgekeerde doet er net zoveel toe: zonder het hardwarewoord had de gateway terecht geweigerd, en had de controle stilletjes een weigering gemeten in plaats van een antwoord. Een testharnas dat over zijn eigen capaciteiten liegt levert groene uitslagen op over het verkeerde ding.
Wat we zouden opschrijven
- Protobuf gooit onbekende velden stilletjes weg, dus een nieuw commando bereikt een oude agent als een lege envelop.
- Weiger voordat je verstuurt. Een weigering die de capability en de versie noemt verslaat een klacht van vier lagen verderop.
- Een wijziging zonder nieuw veld is de gevaarlijke. Er wordt niets weggegooid, dus klaagt er niets.
- De faalvorm die je wilt is luidruchtig. Een aannemelijk antwoord dat fout is wordt nooit bij je gemeld.
- Twee configuratieformaten die allebei parseren zijn erger dan twee die dat niet doen.
- Verruim nooit een bestaand capability-woord. Het is een belofte die wordt vastgehouden door agents die je niet kunt bereiken.
- Eén extra woord kost één constante aan elke kant, en weigert alleen wat geweigerd moet worden.
- Zet de redenering naast de constante, waar de volgende persoon werkelijk zal staan.
- Een stub moet weigeren wat hij niet kan, anders wordt elk weigeringspad ontoetsbaar.
- Een harnas dat te veel claimt levert groene uitslagen op over het verkeerde ding.
Voor de duidelijkheid over wat dit is: een derde capability-woord voor Proxmox-containers, toegevoegd naast een wijziging die geen enkel nieuw protocolveld introduceerde, met de redenering vastgelegd bij beide constanten en de stub-agent die er twee van de drie aankondigt; de ronde bracht de containertestmodule van vijfendertig tests naar negenendertig, met formattering en het releasedoel schoon, en eindigde met de gedeelde pakketten op 5347 groen, de gateway op 1467, de stubtools op 489 en de websuite op 4593, zonder falende tests, plus vijftig browsercontroles groen in twee talen. Onbewezen: niets hiervan draaide tegen een echte Proxmox, dus het gedrag van een oudere agent op een containeridentificatie is vastgesteld uit de twee configuratieformaten en de parser en niet waargenomen, en de keten in bedrijf is tegen onze eigen stub geoefend.
Uit het platformwerk aan Provibr. Wat er gebeurt als twee rondes naar hetzelfde veldnummer grijpen staat in twee rondes, één veldnummer, de ronde die de agent als eerste over containers leerde staat in een container opnieuw installeren is vervangen, en hoe een agent überhaupt beslist of hij een nieuwe build vertrouwt staat in hoe een getekende agent-update zichzelf weigert.