Salta al contenuto

Blog ·

Una parola di capacità per un vecchio comando

Aggiungere un campo protobuf fa fallire un agente vecchio ad alta voce. Cambiare il senso di un contrassegno lo fa rispondere in modo plausibile, e sbagliato.

Di Provibr

Il nostro agente gira dentro la rete del cliente e compone verso di noi, dall’interno. Si aggiorna da solo, ma non all’istante e non sempre, quindi in un dato momento la flotta è un ventaglio di versioni e la piattaforma deve sapere che cosa sa fare ciascuna.

Lo sa perché è l’agente a dirglielo. A ogni sessione l’agente manda un elenco di parole brevi, una per capacità, e la piattaforma rifiuta un comando la cui parola manca invece di mandarlo e sperare.

Questa tornata ha aggiunto la terza parola di questo tipo per i container Proxmox, ed è la prima in cui la domanda interessante non era se aggiungerla ma che cosa sarebbe successo senza.

Perché quelle parole esistono

Il meccanismo protegge da una proprietà precisa di protobuf: un campo sconosciuto dentro un oneof viene scartato.

Quando una tornata aggiunge un nuovo comando come nuovo campo, un agente precedente a quella tornata analizza il messaggio, non riconosce il numero di campo, lo butta via e si ritrova in mano un ProxmoxCommand senza nessun comando dentro. E dice esattamente questo. Il messaggio è onesto e del tutto inutile: l’operatore vede una lamentela su una busta vuota e la causa sta quattro livelli più in là, in una discordanza di versioni che nessuno ha nominato.

Quindi la piattaforma rifiuta prima. Se la parola manca, il comando non parte mai, e il rifiuto nomina la capacità e la versione dell’agente. È un esito peggiore del comando che funziona e molto migliore del comando che fallisce in un modo che richiede un pomeriggio per essere rintracciato.

In entrambi i casi è un fallimento rumoroso. E si scopre che questo conta.

La terza parola non è un campo nuovo

Il cambiamento di questa tornata è che un container può ora mostrare il proprio hardware. Il comando che lo fa, GetHardware, non è nuovo. Ogni agente, risalendo fino ai primi lavori sul ciclo di vita delle macchine virtuali, conosce il messaggio e sa come rispondere.

Quello che è cambiato è un contrassegno accanto che dice a quale genere di risorsa si riferisce l’identificatore. Un agente precedente a questa tornata riceve quel contrassegno, non lo conosce e lo butta via, esattamente come protobuf prescrive. Poi fa quello che ha sempre fatto con una richiesta di hardware: chiede a Proxmox la configurazione della macchina sul percorso QEMU.

Niente è vuoto. Niente si lamenta. L’agente crede che gli sia stata posta una domanda che capisce, e risponde.

Ci sono due modi in cui la cosa atterra, e nessuno dei due è rumoroso. Se Proxmox non ha niente a quell’identificatore sotto il percorso delle macchine virtuali, al cliente viene detto che una macchina non esiste, a proposito di un container che gli sta girando davanti. E se una configurazione torna davvero e viene consegnata all’analizzatore costruito per le macchine virtuali, la risposta non è vuota, è sbagliata.

La risposta sbagliata è precisa e sembra a posto

I due formati di configurazione sono abbastanza vicini da essere analizzati e abbastanza diversi da contare. Una macchina virtuale scrive la sua prima scheda di rete come un modello e un indirizzo MAC uniti da un segno di uguale. Un container scrive prima il nome di un’interfaccia, poi il MAC in un campo a chiave separato.

L’analizzatore per le macchine virtuali prende la prima coppia di chiave e valore come il modello e l’indirizzo. Data la riga di un container, riferisce quindi una scheda di rete il cui modello è name e il cui indirizzo MAC è ETH0.

È una riga dall’aspetto plausibile in una tabella. Ha un modello, ha un indirizzo, viene disegnata senza nessun avviso. È la ragione per cui il percorso dei container aveva bisogno di un analizzatore proprio, ed è esattamente la classe di difetto che nessuno segnala, perché non c’è niente da segnalare. Qualcuno guarda uno schermo, pensa che la colonna del modello sia strana, e tira dritto.

Quindi un comando che esiste già è un genere di cambiamento più pericoloso di un comando nuovo. Quello nuovo fallisce alla busta, in pubblico. Questo fallisce al significato, in privato.

Perché non allargare niente e aggiungere invece una riga

L’alternativa ovvia è allargare la parola che esiste già. C’è una parola che dice che l’agente capisce il percorso dei container, e sarebbe bastato un carattere di lavoro per farle significare anche la cosa più recente.

Così però verrebbe rifiutato ogni comando sui container da parte di ogni agente che non si è ancora aggiornato, compresi quelli che oggi funzionano perfettamente. Una flotta che in questo momento serve container si spegnerebbe per una capacità che possiede davvero, perché abbiamo cambiato il senso della nostra parola sotto i suoi piedi.

Una parola è una promessa su quello che è stato costruito, e la promessa deve mantenere il proprio senso finché qualcuno la tiene ancora in mano. Aggiungere una terza parola costa una costante per lato e rifiuta esattamente i comandi che vanno rifiutati, e nient’altro. Mette anche il ragionamento in un posto dove una persona lo troverà, cioè accanto alla costante e non in un messaggio di commit.

I due lati sono due costanti, una nel sorgente Rust e una nel TypeScript condiviso, ciascuna delle quali nomina l’altra. Quell’accoppiamento non è elegante, e ogni tentativo di renderlo elegante finisce con un passo di compilazione fra due linguaggi che devono restare leggibili in modo indipendente.

Lo stub ne dichiara due su tre di proposito

C’è un agente stub che ci permette di guidare il gateway senza un hypervisor, e annuncia anche le parole dei container.

Ne annuncia due. Dice di conoscere il percorso dei container e dice di leggere l’hardware dei container, e di proposito non rivendica la terza, perché reinstallare un container è una cosa che non sa fare.

Vale la pena dirlo, perché uno stub che rivendica tutto è uno stub che rende non verificabile ogni cammino di rifiuto. E l’opposto conta altrettanto: senza la parola dell’hardware il gateway avrebbe rifiutato, correttamente, e il controllo avrebbe misurato in silenzio un rifiuto invece di una risposta. Un banco di prova che mente sulle proprie capacità produce risultati verdi sulla cosa sbagliata.

Che cosa annoteremmo

  1. Protobuf butta via i campi sconosciuti in silenzio, quindi un comando nuovo arriva a un agente vecchio come una busta vuota.
  2. Rifiuti prima di mandare. Un rifiuto che nomina la capacità e la versione vale più di una lamentela che arriva da quattro livelli più sotto.
  3. Il cambiamento senza campi nuovi è quello pericoloso. Non viene buttato via niente, quindi niente si lamenta.
  4. Il modo di fallire che si desidera è quello rumoroso. Una risposta plausibile e sbagliata non Le verrà mai segnalata.
  5. Due formati di configurazione che si analizzano entrambi sono peggio di due che non lo fanno.
  6. Non allarghi mai una parola di capacità esistente. È una promessa in mano ad agenti che non può raggiungere.
  7. Una parola in più costa una costante per lato, e rifiuta soltanto quello che va rifiutato.
  8. Metta il ragionamento accanto alla costante, dove la prossima persona si troverà davvero.
  9. Uno stub deve rinunciare a ciò che non sa fare, altrimenti ogni cammino di rifiuto diventa non verificabile.
  10. Un banco di prova che rivendica troppo produce risultati verdi sulla cosa sbagliata.

Per chiarezza su che cosa sia: una terza parola di capacità per i container Proxmox, aggiunta insieme a un cambiamento che non ha introdotto nessun campo nuovo di protocollo, con il ragionamento registrato accanto a entrambe le costanti e l’agente stub che annuncia due parole su tre; la tornata ha portato il modulo di prova dei container da trentacinque test a trentanove, formattazione e bersaglio di rilascio puliti, e si è chiusa con i pacchetti condivisi a 5347 verdi, il gateway a 1467, gli strumenti di stub a 489 e la suite web a 4593, senza fallimenti, più cinquanta controlli nel browser verdi in due lingue. Non dimostrato: qui niente è stato eseguito contro un Proxmox reale, quindi il comportamento di un agente più vecchio su un identificatore di container è accertato dai due formati di configurazione e dall’analizzatore invece che osservato, e la catena in funzione è stata messa alla prova contro il nostro stub.

Dal lavoro di piattaforma su Provibr. Che cosa succede quando due tornate puntano allo stesso numero di campo si trova in due tornate, un solo numero di campo, la tornata che per prima ha insegnato i container all’agente si trova in reinstallare un container è una sostituzione, e come un agente decide se fidarsi di una nuova build si trova in come un aggiornamento firmato si rifiuta.

Inizi con un host e un agente

Crei un account, installi l’agente con un solo comando e colleghi il suo primo host Proxmox. Il periodo di prova dura 14 giorni e non chiede alcun dato di pagamento.