Airframe

Por que o Airframe

Um catálogo para toda a organização

Quem trabalha aqui, em que equipe está, quais produtos existem e quem é responsável por cada um: o Airframe guarda tudo isso como arquivos num só repositório git, o catálogo. Toda automação que precisa desses dados lê os arquivos, então uma mudança é feita uma vez, revisada uma vez, e todos os leitores a seguem.

Como um repositório descreve a organização

  1. A organização como arquivos

    O catálogo é um repositório git de pequenos arquivos YAML. Jornadas, domínios, contextos e produtos formam a sua hierarquia, cada um um arquivo nomeado pelo seu caminho, como contexts/shop.store.ordering.yaml, e o arquivo de um produto nomeia a equipe responsável por ele. O arquivo de uma equipe nomeia o seu contexto, o seu líder e os seus membros com os seus papéis. O arquivo de uma pessoa tem um nome, um endereço de e-mail, um status (active, pending ou departed), os nomes de usuário da pessoa no GitLab e no Grafana quando ela já tem contas, e um perfil: sobre, especialidades, links e horário. As regras de responsáveis, no mesmo repositório, dizem quem aprova o quê. Em cada merge request, o lint do catálogo verifica cada arquivo contra o seu JSON Schema, e as referências entre arquivos.

  2. Mudado por merge request

    Ninguém muda a organização nas configurações de uma ferramenta: uma mudança é um merge request ao catálogo, e as próprias regras de responsáveis do catálogo decidem quem precisa aprová-la. O arquivo de uma equipe precisa de um dos seus líderes de equipe ou dos líderes do seu contexto; o próprio perfil de uma pessoa, dessa pessoa, que aprova a mudança ou a abre só com commits seus; o resto do arquivo de uma pessoa, de um líder de uma das suas equipes; e a estrutura, das jornadas às próprias regras, de dois membros da equipe da plataforma. O controle de aprovação traduz cada regra em pessoas a partir da branch main protegida do catálogo, nunca da mudança que avalia, e o merge espera a sua aprovação. Assim, cada mudança tem um revisor, um histórico no git e um jeito de desfazê-la: outro merge request.

  3. Uma fonte, muitos leitores

    Hoje estes o leem: o controle de aprovação, para cada aprovação que dá; a raiz de grupos do landing-zone, para um grupo do Google por equipe, pelos líderes de cada nível e pelos usuários de cada produto, o público que o nome de host do produto admite atrás do login único; as raízes do GitLab do control-plane, para as participações em grupos de cada pessoa e a lista de quem pode fazer merge na branch main de cada produto; a raiz do Grafana do operations, para os membros da organização e uma equipe para cada equipe do catálogo, com as suas pastas, o seu ponto de contato e a sua rota de alertas; a raiz de pastas, para uma pasta por jornada, domínio e contexto; e o catálogo de arquitetura, para uma página por equipe e por pessoa, com o sobre, as especialidades e o horário da pessoa. As fábricas de projetos dão ao grupo de uma equipe acesso de leitura aos projetos dos seus produtos e aos seus logs; o resto do que a entrada de um produto deriva é a história de autosserviço por merge request.

  4. Nada para manter sincronizado

    Quando uma pessoa ou uma equipe muda, os leitores acompanham na sua próxima execução, e um merge no catálogo a inicia. O controle de aprovação lê a branch main do catálogo em cada avaliação. O pipeline do catálogo na main dispara a cadeia de reconciliadores: o pipeline do landing-zone, depois o do operations, depois o do control-plane e de novo o do landing-zone, cada um rodando só as raízes que leem o catálogo. O mesmo pipeline publica as páginas do catálogo no catálogo de arquitetura. Para o que os leitores derivam, não há um segundo inventário nem um job de sincronização. Duas coisas ainda ficam fora do catálogo: a política de aprovação de todo o grupo nomeia os seus aprovadores no security-policies, onde só um merge request os muda, e uma verificação depois de cada merge no catálogo avisa quando essa lista e o catálogo diferem, enquanto uma execução diária falha e mantém uma issue aberta até que coincidam; e os grupos da plataforma e de emergência são administrados à mão.

  5. A próxima automação é mais um leitor

    Uma automação que precisa saber quem é responsável por um produto, quem lidera um domínio ou quem está numa equipe lê os mesmos arquivos na branch main do catálogo, e herda o que eles já trazem: cada dado foi aprovado pelos seus responsáveis, tem um histórico e pode ser desfeito. Ela não precisa de lista, formulário nem job de sincronização próprios. Uma nova raiz do Terraform no landing-zone, no operations ou no control-plane que lê o catálogo declara isso no seu pipeline, com a entrada reads_catalog do componente tf-apply, e a cadeia a roda depois de cada merge no catálogo.

O que o torna verdade

Cada arquivo do catálogo é verificado antes do merge.
O componente validate do control-plane roda o lint do catálogo em cada merge request e na main: cada arquivo contra o seu JSON Schema, o pai de cada nível presente, cada líder e cada membro de equipe uma pessoa que não saiu, e o líder de cada equipe um dos seus membros com o papel de líder de equipe. Cada achado nomeia o seu arquivo.
Só os responsáveis atuais podem aprovar uma mudança no catálogo.
O controle de aprovação lê as regras de responsáveis, as equipes e as pessoas da branch main protegida do catálogo, nunca da mudança que avalia, e conta só pessoas ativas com uma conta no GitLab, nunca o autor nem os autores dos seus commits. Uma política de aprovação no security-policies torna a aprovação do controle uma condição para o merge no catálogo, como em todos os outros repositórios que o controle protege.
Um merge no catálogo chega aos leitores sem que ninguém rode um comando.
O pipeline do catálogo na sua branch main protegida dispara, um após o outro, os pipelines do landing-zone, do operations e do control-plane, e depois de novo o do landing-zone, cada um esperando o anterior. Neles, o componente tf-apply roda só as raízes que declaram reads_catalog, contra a branch main do catálogo, cada uma com a sua própria identidade de pipeline.
Cada leitor deriva as participações e as aprovações só de pessoas ativas.
A raiz de grupos sincroniza participações só para pessoas ativas; as raízes do GitLab dão participações e direitos de merge só a pessoas ativas com um nome de usuário no GitLab, e lhes dão acesso aos repositórios da plataforma e ao security-policies por um só grupo, projectairframe/contributors, então uma saída tira a pessoa de todos eles na próxima execução da cadeia; a raiz do Grafana adiciona só pessoas ativas com um nome de usuário no Grafana; o controle de aprovação conta só pessoas ativas. O lint recusa uma pessoa que saiu em qualquer equipe ou lista de líderes, então o merge request que marca alguém como departed também o tira de cada equipe e de cada lista de líderes.
A lista de pessoas da política de aprovação não pode se afastar do catálogo sem que se perceba.
A política de aprovação de todo o grupo nomeia os seus aprovadores um a um. A sua verificação, policy:approvers, compara essa lista com as pessoas ativas do catálogo com uma conta no GitLab e nomeia cada pessoa a adicionar ou remover. No security-policies ela roda em cada merge request e na main, e falha diante de qualquer diferença. No control-plane ela roda na passagem que a cadeia do catálogo dispara depois de cada merge, onde uma pessoa a adicionar ou remover só gera um aviso, então a cadeia continua, e num agendamento diário, onde falha e policy:approvers:report mantém uma issue aberta com a mudança exata a fazer até que as listas coincidam. Um papel, um grupo ou um id entre os aprovadores, ou qualquer aprovador que não seja a conta do controle na regra do próprio controle, faz falhar todas as execuções. Enquanto a lista não acompanha, uma pessoa que ainda não está nela não pode aprovar, e uma pessoa que saiu e continua nela não alcança nenhum repositório da plataforma. Uma verificação que falha não muda nada sozinha: a lista muda por um merge request no security-policies.