TFImport: Uma ferramenta para importar infraestrutura de forma fácil!
Gosto muito do OpenTofu/Terraform, mas quem já lidou com IaC sabe que uma grande parte do trabalho passa por importar infraestrutura que foi previamente criada na interface (“clickopsed”) ou por outras vias. Quem já o fez, sabe também que cada recurso é importado de uma forma diferente, com recurso a IDs diferentes, e que se trata de um processo lento e doloroso que se agrava à medida que se gerem mais recursos.
Para acelerar um pouco as coisas, normalmente recorro a pequenos scripts de bash ou one-liners, mas não deixa de ser um processo muito aborrecido e propenso a erros. Claro, as versões mais recentes têm agora os blocos import {} e suportam for_each, mas isso ainda não resolve o problema central de cada recurso ter uma maneira diferente de ser importado. Continuamos a ter de consultar a documentação e procurar o ID de importação correto para cada pequena coisa. Ao longo dos anos, desejei que houvesse uma forma mais fácil de o fazer, mas nunca encontrei uma forma de resolver o problema e, muito menos, como calcular os IDs necessários para importar cada recurso. Pelo menos, não até agora!
A Dor de Cabeça do Import
Recentemente encontrava-me a meio da refatoração de um grande projeto, onde tive de importar uma enorme quantidade de recursos através de diferentes unidades do terragrunt em contas e ambientes distintos. O script em bash para ajudar na tarefa tornava-se cada vez mais complexo quando me apercebi de que a maior parte da informação necessária para calcular os IDs de importação é muitas vezes possível de inferir de forma direta a partir do próprio plano. A informação em falta pode, muitas vezes, ser calculada através de outros dados no plano ou com uma espécie de pesquisa (lookup)! A minha cabeça começou a trabalhar a mil à hora, era aquela comichão que não quer desaparecer… pausei imediatamente o meu trabalho e comecei a esboçar uma solução.
Certo… Então consigo obter dados do plano, mas como faço o parse disso? O Terraform tem um pacote tfjson que contém toda a estrutura para conseguir analisar o plano, espetacular! Mas existe ainda outro problema. Como sei que informação preciso para construir os IDs de importação? Não consegui encontrar maneira de tirar partido do código dos providers para obter tal informação, teria de descobrir uma forma de analisar a documentação dos providers… bolas, é exatamente por isto que nunca tentei fazer nada em relação a isto inicialmente.
E se houvesse uma espécie de máquina devoradora de markdown que conseguisse processar todos aqueles dados da documentação dos providers e extrair a informação essencial à construção dos IDs de importação? E se… oooh, espera… Não chamam a isso Inteligência Artificial hoje em dia? Basta-me colocar um agente de IA a debruçar-se sobre o problema e ele vai dar-me tudo o que preciso. Só tenho de garantir que o código é suficientemente desacoplado e extensível para que os agentes de IA possam trabalhar de forma segura e adicionar diferentes providers sem terem de tocar no resto do código. Fixe, tenho um plano!
Os “Clankers”
Após umas horas a colocar as mãos na massa, consegui deixar a estrutura base da ferramenta CLI montada e operacional. Era hora de meter os clankers a fazer a sua parte! Expliquei ao agente o propósito da ferramenta que estava a construir e a forma como planeava a sua arquitetura. Antes sequer de o deixar arrancar a sério, pedi-lhe para gerar um ficheiro AGENTS.md. Concluído esse passo, pedi-lhe para processar a documentação do Provider da AWS, encontrar forma de extrair a informação necessária para a construção dos IDs de importação, e transformá-la em código!
Fiz um script fantástico! mas, apaguei!
Deixei o agente livre ao seu trabalho. Olhei por acidente para o seu raciocínio lógico e o maldito clanker andava a desenvolver internamente um script para processar e analisar os ficheiros markdown e extrair a informação. Quando terminou, disse-me todo satisfeito: “Ei, criei um script processador de documentos para fazer isto, adicionei o provedor da AWS com toda a lógica necessária e apaguei todo o código temporário incluindo o script de processamento”.
Espera, fizeste o quê? Nem pensar!!! Traz lá essa coisa de volta! E já agora, constrói a lógica de forma a que seja reutilizável para facilitar não só o processo de adicionar novos providers, mas também a atualização de providers já existentes quando saírem novas versões com novos recursos adicionados ou removidos! A máquina concordou de imediato, trouxe o script de volta e atualizou o AGENTS.md com a informação e o padrão focado na adição de novos providers.
A recompensa foi imediata! Com o processador de documentação e com cada provedor de cloud isolado com a sua própria lógica, a expansão da ferramenta tornou-se trivial. Literalmente encarreguei de novo o agente desta tarefa e disse: “Ora então, adiciona o Google Cloud! Agora Azure, e agora Scaleway.” Em poucos minutos, o agente clonou as respetivas documentações e gerou o código para os milhares de mapas de IDs dos respetivos recursos.
Polir a Experiência
Foquei-me de seguida na experiência de utilizador da ferramenta, enquanto eu próprio testava o tfimport no mundo real e… Porra! A importação de recursos para o tfstate agora é tão fácil! Os IDs de importação são todos extraídos a partir do plano ou podem ser calculados através de informação existente no mesmo. Contudo, certos recursos necessitam de IDs opacos (como um ID de VPC na AWS vpc-xxxxxx ou um ID de instância EC2) que pura e simplesmente não existem no plano antes de o recurso ser importado. Para esses casos, o tfimport recorre de forma elegante ao SDK do provedor cloud em segundo plano (lazy loading), pesquisa a infraestrutura com a ajuda das tags ou dos nomes fornecidos na composição, apanha o ID correspondente e retorna o valor de volta à lógica de importação.
E foi então que me deparei com uns problemas estranhos de rede. Descobri mais tarde o verdadeiro motivo por trás disto tudo, mas, uma vez que o tfimport estava a executar terragrunt import diretamente, a minha mente assumiu de imediato que talvez estivesse a bater nos rate limits da API da AWS. Isso levou-me à ideia de que talvez fosse melhor gerar um ficheiro .tf com blocos import {}. A experiência tornou-se, de facto, muito melhor, tanto que passou a ser o comportamento por defeito da aplicação.
E sabem qual é a melhor parte de desenvolvermos as ferramentas que efetivamente utilizamos? Um pouco mais tarde, apercebi-me de que precisava de uma forma de ignorar certos recursos e decidi adicionar uma nova flag, --ignore. Tudo isto porque, muitas das vezes, estamos a importar alguns recursos e a criar outros novos e não queremos que o tfimport tente importar recursos que, de facto, não existem!
Experimente o tfimport
Se importar recursos preexistentes na cloud é uma tarefa que executam com frequência, da próxima vez, experimentem o tfimport!
Podem encontrar o código-fonte e as instruções de instalação no repositório oficial no GitHub.