Blogue ·
Uma palavra de capacidade, um comando antigo
Quando uma ronda acrescenta um campo protobuf, um agente antigo falha alto. Quando só muda o sentido de um sinalizador, responde bem e engana-se.
Por Provibr
O nosso agente corre dentro da rede do próprio cliente e liga para fora, até nós. Atualiza-se sozinho, mas não instantaneamente e nem sempre, por isso em qualquer momento a frota é um leque de versões e a plataforma tem de saber o que cada uma consegue fazer.
Sabe-o porque o agente o diz. Em cada sessão o agente envia uma lista de palavras curtas, uma por capacidade, e a plataforma recusa um comando cuja palavra falte, em vez de o enviar na esperança de que corra bem.
Esta ronda acrescentou a terceira dessas palavras para os contentores do Proxmox, e é a primeira em que a pergunta interessante não era se a devíamos acrescentar mas o que teria acontecido sem ela.
Porque é que as palavras existem sequer
O mecanismo protege contra uma propriedade específica do protobuf: um campo desconhecido dentro de um oneof é descartado.
Quando uma ronda acrescenta um comando novo como um campo novo, um agente anterior a essa ronda analisa a mensagem, não reconhece o número do campo, deita-o fora, e fica com um ProxmoxCommand sem comando nenhum lá dentro. Depois diz exatamente isso. A mensagem é honesta e completamente inútil: o operador vê uma queixa sobre um envelope vazio e a causa está a quatro camadas de distância, numa diferença de versões que ninguém mencionou.
Por isso a plataforma recusa primeiro. Se a palavra falta, o comando nunca parte, e a recusa nomeia a capacidade e a versão do agente. É um desfecho pior do que o comando funcionar e muito melhor do que o comando falhar de uma maneira que leva uma tarde a rastrear.
É uma falha alta de qualquer das formas. Isso, afinal, é o que importa.
A terceira palavra não é um campo novo
A mudança desta ronda foi que um contentor passa a poder mostrar o seu hardware. O comando que faz isso, GetHardware, não é novo. Todos os agentes, desde os primeiros trabalhos sobre o ciclo de vida das máquinas virtuais, conhecem a mensagem e sabem responder-lhe.
O que mudou é um sinalizador ao lado dela que diz a que tipo de recurso se refere o identificador. Um agente anterior a esta ronda recebe esse sinalizador, não o conhece, e deita-o fora, exatamente como o protobuf manda. Depois faz aquilo que sempre fez com um pedido de hardware: pergunta ao Proxmox pela configuração da máquina no caminho QEMU.
Nada fica vazio. Nada se queixa. O agente acredita que lhe foi feita uma pergunta que percebe, e responde.
Há duas maneiras de isso aterrar, e nenhuma delas é alta. Se o Proxmox não tiver nada naquele identificador debaixo do caminho das máquinas virtuais, é dito ao cliente que uma máquina não existe, a respeito de um contentor que está a correr à frente dele. E se vier de facto uma configuração e for entregue ao analisador construído para máquinas virtuais, a resposta não é vazia, é errada.
A resposta errada é específica e parece bem
Os dois formatos de configuração são suficientemente próximos para serem analisados e suficientemente diferentes para importarem. Uma máquina virtual escreve a sua primeira placa de rede como um modelo e um endereço MAC unidos por um sinal de igual. Um contentor escreve primeiro um nome de interface, e depois o MAC num campo com chave própria.
O analisador das máquinas virtuais toma o primeiro par de chave e valor como o modelo e o endereço. Perante a linha de um contentor, comunica portanto uma placa de rede cujo modelo é name e cujo endereço MAC é ETH0.
Isso é uma linha de aspeto plausível numa tabela. Tem um modelo, tem um endereço, é desenhada sem nenhum aviso. É a razão pela qual o caminho dos contentores precisava do seu próprio analisador, e é exatamente a classe de defeito que ninguém comunica, porque não há ali nada para comunicar. Alguém olha para um ecrã, acha a coluna do modelo esquisita, e segue em frente.
Portanto um comando que já existe é um tipo de mudança mais perigoso do que um comando que é novo. O novo falha no envelope, em público. Este falha no sentido, em privado.
Porque não alargámos nada e acrescentámos antes uma linha
A alternativa evidente é alargar a palavra que já existe. Há uma palavra a dizer que o agente percebe de todo o caminho dos contentores, e teria sido um carácter de trabalho fazê-la significar também a coisa mais recente.
Isso recusaria todos os comandos de contentor de todos os agentes que ainda não se atualizaram, incluindo os que hoje funcionam na perfeição. Uma frota que neste momento está a servir contentores ficaria às escuras para uma capacidade que tem genuinamente, porque mudámos por baixo dela o sentido da nossa palavra.
Uma palavra é uma promessa sobre aquilo que foi construído, e a promessa tem de manter o seu sentido enquanto houver alguém a segurá-la. Acrescentar uma terceira palavra custa uma constante de cada lado e recusa exatamente os comandos que precisam de ser recusados, e mais nada. Também põe o raciocínio num sítio onde uma pessoa o vai encontrar, que é ao lado da constante e não numa mensagem de commit.
Os dois lados são duas constantes, uma na fonte Rust e outra no TypeScript partilhado, cada uma a nomear a outra. Esse emparelhamento não é elegante, e todas as tentativas de o tornar elegante acabam com um passo de compilação entre duas linguagens que precisam de ser legíveis de forma independente.
O simulador diz duas das três de propósito
Há um agente simulador que nos deixa conduzir o gateway sem hipervisor, e também ele anuncia as palavras dos contentores.
Anuncia duas delas. Diz que conhece o caminho dos contentores e diz que lê o hardware dos contentores, e deliberadamente não reclama a terceira, porque reinstalar um contentor é uma coisa que não consegue fazer.
Vale a pena dizê-lo porque um simulador que reclama tudo é um simulador que torna intestável todo e qualquer caminho de recusa. E o contrário importa exatamente na mesma medida: sem a palavra do hardware o gateway teria recusado, corretamente, e a verificação teria medido em silêncio uma recusa em vez de uma resposta. Um andaime de testes que mente sobre as suas próprias capacidades produz resultados verdes sobre a coisa errada.
O que registaríamos
- O protobuf descarta campos desconhecidos em silêncio, por isso um comando novo chega a um agente antigo como um envelope vazio.
- Recuse antes de enviar. Uma recusa que nomeia a capacidade e a versão vale mais do que uma queixa vinda de quatro camadas abaixo.
- A mudança sem campo novo é a perigosa. Nada é descartado, portanto nada se queixa.
- O modo de falha que se quer é alto. Uma resposta plausível que está errada nunca lhe será comunicada.
- Dois formatos de configuração que passam ambos na análise são piores do que dois que não passam.
- Nunca alargue uma palavra de capacidade existente. É uma promessa segurada por agentes a que não consegue chegar.
- Uma palavra a mais custa uma constante de cada lado, e recusa apenas o que precisa de ser recusado.
- Ponha o raciocínio ao lado da constante, onde a próxima pessoa vai realmente estar.
- Um simulador tem de declinar o que não consegue fazer, ou todo o caminho de recusa fica intestável.
- Um andaime que reclama a mais produz resultados verdes sobre a coisa errada.
Para que fique claro o que isto é: uma terceira palavra de capacidade para os contentores do Proxmox, acrescentada ao lado de uma mudança que não introduziu nenhum campo novo de protocolo, com o raciocínio registado junto de ambas as constantes e o agente simulador a anunciar duas das três; a ronda levou o módulo de testes dos contentores de trinta e cinco testes para trinta e nove, com a formatação e o alvo de lançamento limpos, e terminou com os pacotes partilhados a 5347 verdes, o gateway a 1467, as ferramentas do simulador a 489 e a bateria de testes da web a 4593, sem falhas, mais cinquenta verificações de navegador verdes em duas línguas. Por provar: nada aqui correu contra um Proxmox a sério, portanto o comportamento de um agente mais antigo perante um identificador de contentor está estabelecido a partir dos dois formatos de configuração e do analisador e não observado, e a cadeia em funcionamento foi exercitada contra o nosso próprio simulador.
Do trabalho de plataforma na Provibr. O que acontece quando duas rondas procuram o mesmo número de campo está em Duas rondas, um número de campo, a ronda que ensinou pela primeira vez o agente a lidar com contentores está em Reinstalar um contentor é uma substituição, e como um agente decide se confia sequer numa compilação nova está em Como uma atualização assinada se recusa.