Como a AWS Cloud Control API e o novo Terraform provider impactam sua vida?

Marcelo Andrade - Jun 6 - - Dev Community

Recentemente, a Hashicorp anunciou que o provider AWS Cloud Control agora é considerável pronto para uso em produção (também conhecido como "Generally Available", ou GA):

Hashicorp Headline: Terraform AWS Cloud Control API provider now generally available

A notícia é bem explicativa, mas percebi bastante confusão dentre meus conhecidos a respeito sobre o assunto, então vamos falar sobre! O que é AWS Cloud Control, como funciona, o que faz este novo provider e qual o impacto na sua vida!

Terraform Provider AWS

Se você usa Terraform (ou OpenTofu) e AWS, então provavelmente você usa o Terraform Provider AWS para provisionar sua infraestrutura.

Screenshot of the Terraform Provider AWS page, current version 5.52.0

Disponível desde o Terraform 0.1 (2014!), este possivelmente é o provider mais antigo da solução e de longe o mais conhecido e usado.

O que a notícia compartilhada tem a ver com este provider?

Nada!

Este provider usa a mesma API que a AWS SDK e o AWS CLI, por exemplo.

Por falar em AWS CLI...

AWS API e suas inconsistências

Se você já usou a AWS CLI, provavelmente já percebeu algumas "particularidades".

As APIs da AWS foram construídas ao longo de quase 20 anos; serviços de épocas diferentes certamente foram desenvolvidos por equipes diferentes a partir de modelos e ideias diferentes. Além disso, serviços antigos são extendidos possivelmente por outras equipes que implementam recursos do seu jeito.

Combinado ao tamanho e variedade de ofertas, essa característica torna torna a API extremamente inconsistente em seu comportamento. Vamos a um exemplo bem simplório mas que ilustra adequadamente o que queremos dizer.

Para listar as máquinas virtuais de uma determinada região, você executa:

$ aws ec2 describe-instances
Enter fullscreen mode Exit fullscreen mode

Para listar seus bancos gerenciados do serviço RDS:

$ aws rds describe-db-instances
Enter fullscreen mode Exit fullscreen mode

Por outro lado, se você quiser os buckets S3 de uma conta, você usa o seguinte comando:

aws s3 ls 
Enter fullscreen mode Exit fullscreen mode

Para listar todas as Kinesis streams:

$ aws kinesis list-streams
Enter fullscreen mode Exit fullscreen mode

O subcomando s3 da AWS CLI é tão esquisito que a AWS optou por implementar uma nova API para trabalhar com s3 e não quebrar a retrocompatibilidade - o subcomando s3api. Este subcomando usa a versão mais "moderna", parecida com o Kinesis, que usa list como verbo em vez de describe:

$ aws s3api list-buckets
Enter fullscreen mode Exit fullscreen mode

Se você achou bobagem essas divergências, saiba que isso tem seu custo, em especial se você vai além das operações triviais. Como essas particularidades não são da linha de comando e sim da API, elas se apresentam também na AWS SDK, e isso pode ser um problema, em especial para quem desenvolve soluções third-party que integram com serviços AWS. Observe o post abaixo:

Screenshot com uma notícia sobre a inconsistência da API

Então eu não sou o primeiro a apontar que isso incomoda!

AWS Cloud Control

Curiosamente, no mesmo ano da notícia anterior, a AWS anunciou a API Cloud Control, cujo propósito é resolver justamente esse problema de consistência:

Anúncio da AWS sobre Cloud Control API

A própria AWS admite os problemas:

As applications and infrastructures become increasingly sophisticated and you work across more AWS services, it becomes increasingly difficult to learn and manage distinct APIs. This challenge is exacerbated when you also use third-party services in your infrastructure, since you have to build and maintain custom code to manage both the AWS and third-party services together.

Qual era a ideia então? Oferecer uma "interface padrão" para as operações em todos os serviços da AWS. No caso, implementar as operações de um CRUDL (o mesmo que um CRUD, mas com um List junto!):

  • CreateResource;
  • GetResource;
  • UpdateResource;
  • DeleteResource;
  • ListResource.

Como funciona na prática? Vamos criar um bucket S3:

$ aws cloudcontrol create-resource \
      --type-name AWS::S3::Bucket \
      --desired-state '{
        "BucketName": devsres-cloudcontrol-lab
        }'
{
    "ProgressEvent": {
        "TypeName": "AWS::S3::Bucket",
        "Identifier": "devsres-cloudcontrol-lab",
        "RequestToken": "6b47f322-d9af-4d08-8faa-6d530f33bcff",
        "Operation": "CREATE",
        "OperationStatus": "IN_PROGRESS",
        "EventTime": "2024-06-05T22:16:06.220000-03:00"
    }
}
Enter fullscreen mode Exit fullscreen mode

Criando uma stream Kinesis:

$ aws cloudcontrol create-resource \
    --type-name AWS::Kinesis::Stream \
    --desired-state '{
      "Name": "ResourceExample",
      "RetentionPeriodHours":168, 
      "ShardCount\":3
      }'

Enter fullscreen mode Exit fullscreen mode

Quer criar um CloudWatch LogGroup?

$ aws cloudcontrol create-resource \
 --type-name AWS::Logs::LogGroup   \
 --desired-state '{
   "LogGroupName": "DevSREsCloudControlLG",
   "RetentionInDays":30
   }'
{
    "ProgressEvent": {
        "TypeName": "AWS::Logs::LogGroup",
        "Identifier": "DevSREsCloudControlLG",
        "RequestToken": "7fe86619-dda1-4698-beb0-7bcf29c22868",
        "Operation": "CREATE",
        "OperationStatus": "IN_PROGRESS",
        "EventTime": "2024-06-04T00:56:17.364000-03:00"
    }
}
Enter fullscreen mode Exit fullscreen mode

Para listar os buckets existentes:

$ aws cloudcontrol list-resources --type-name AWS::S3::Bucket
{
    "ResourceDescriptions": [
        {
            "Identifier": "devsres-cloudcontrol-lab",
            "Properties": "{\"BucketName\":\"devsres-cloudcontrol-lab\"}"
        },
        {
            "Identifier": "outro-bucket-criado-de-outro-jeito",
            "Properties": "{\"BucketName\":\"outro-bucket-criado-de-outro-jeito\"}"
        },
        {
            "Identifier": "terceiro-bucket-criado-de-outro-jeito",
            "Properties": "{\"BucketName\":\"terceiro-bucket-criado-de-outro-jeito\"}"
        }
    ],
    "TypeName": "AWS::S3::Bucket"
}
Enter fullscreen mode Exit fullscreen mode

Quer listar os CloudWatch LogGroups?

$ aws cloudcontrol list-resources --type-name AWS::Logs::LogGroup
{
    "ResourceDescriptions": [
        {
            "Identifier": "DevSREsCloudControlLG",
            "Properties": "{\"RetentionInDays\":30,\"LogGroupClass\":\"STANDARD\",\"LogGroupName\":\"DevSREsCloudControlLG\",\"Arn\":\"arn:aws:logs:us-west-2:211125357951:log-group:DevSREsCloudControlLG:*\"}"
        },
        {
            "Identifier": "OutroLogGroup",
            "Properties": "{\"RetentionInDays\":30,\"LogGroupClass\":\"STANDARD\",\"LogGroupName\":\"OutroLogGroup\",\"Arn\":\"arn:aws:logs:us-west-2:211125357951:log-group:OutroLogGroup:*\"}"
        },
        {
            "Identifier": "TerceiroLogGroup",
            "Properties": "{\"RetentionInDays\":30,\"LogGroupClass\":\"STANDARD\",\"LogGroupName\":\"TerceiroLogGroup\",\"Arn\":\"arn:aws:logs:us-west-2:211125357951:log-group:TerceiroLogGroup:*\"}"
        }
    ],
    "TypeName": "AWS::Logs::LogGroup"
}
Enter fullscreen mode Exit fullscreen mode

Não sei se você prestou atenção, mas a solicitação de criação não é concluída de maneira síncrona:

$ aws cloudcontrol create-resource \
      --type-name AWS::S3::Bucket       \
      --desired-state '{
        "BucketName": "ele-nao-espera-concluir"
      }'
{
    "ProgressEvent": {
        "TypeName": "AWS::S3::Bucket",
        "Identifier": "ele-nao-espera-concluir",
        "RequestToken": "e871792e-1467-45cb-bd0d-9ac8041825e2",
        "Operation": "CREATE",
        "OperationStatus": "IN_PROGRESS",
        "EventTime": "2024-06-05T23:52:02.801000-03:00"
    }
}
Enter fullscreen mode Exit fullscreen mode

O OperationStatus IN_PROGRESS indica que a solicitação está sendo processada. Para acompanhar o status, usa-se outro comando passando o RequestToken:

$ aws cloudcontrol get-resource-request-status \
      --request-token e871792e-1467-45cb-bd0d-9ac8041825e2
{
    "ProgressEvent": {
        "TypeName": "AWS::S3::Bucket",
        "Identifier": "ele-nao-espera-concluir",
        "RequestToken": "e871792e-1467-45cb-bd0d-9ac8041825e2",
        "Operation": "CREATE",
        "OperationStatus": "SUCCESS",
        "EventTime": "2024-06-05T23:52:25.022000-03:00"
    }
}
Enter fullscreen mode Exit fullscreen mode

A solicitação foi atendida com sucesso.

E se tentarmos criar o mesmo bucket novamente?

$ aws cloudcontrol create-resource \
      --type-name AWS::S3::Bucket       \
      --desired-state '{
        "BucketName": "ele-nao-espera-concluir"
      }'
{
    "ProgressEvent": {
        "TypeName": "AWS::S3::Bucket",
        "Identifier": "ele-nao-espera-concluir",
        "RequestToken": "c965b56a-7a25-4b70-b084-6e733db0c6c3",
        "Operation": "CREATE",
        "OperationStatus": "IN_PROGRESS",
        "EventTime": "2024-06-05T23:57:55.038000-03:00"
    }
}

$ aws cloudcontrol get-resource-request-status \
      --request-token c965b56a-7a25-4b70-b084-6e733db0c6c3
{
    "ProgressEvent": {
        "TypeName": "AWS::S3::Bucket",
        "Identifier": "ele-nao-espera-concluir",
        "RequestToken": "c965b56a-7a25-4b70-b084-6e733db0c6c3",
        "Operation": "CREATE",
        "OperationStatus": "FAILED",
        "EventTime": "2024-06-05T23:57:55.311000-03:00",
        "StatusMessage": "ele-nao-espera-concluir already exists (Service: S3, Status Code: 0, Request ID: null)",
        "ErrorCode": "AlreadyExists"
    }
}
Enter fullscreen mode Exit fullscreen mode

Como era esperado, o retorno da requisição é uma falha, e StatusMEssage te explica o porquê.

Genial! Quando migramos?

Parece legal, certo? E realmente é.

Mas você precisa se perguntar da relevância dessa mudança na sua vida e no seu código.

Faz sentido você migrar todas as suas stacks de código Terraform para usar o novo provider?

A resposta, provavelmente, é não - o ganho é mínimo para a infraestrutura pré-existente, em especial se levado em consideração a massiva quantidade de trabalho que essa migração demandaria.

Faz sentido você passar a escrever todos os códigos Terraform daqui pra frente usando única e exclusivamente a API Cloud Control com seu novo provider?

Aqui temos algo passível de discussão. Mas, na minha opinião, não vejo como imperativa a troca. O provider acabou de ser lançado como GA; a maturidade do software e a base de usuários que o adotou nem se comparam com o provider original.

A própria API Cloud Control não tem tanta popularidade assim - em uma rápida pesquisa que fiz no meu perfil, quase ninguém havia sequer ouvido falar a respeito. Uma base menor de usuários no mínimo aumenta a possibilidade de incorrer em maior quantidades de bugs e comportamentos inesperados - tanto do provider quanto da própria API Cloud Control.

Esse fato, por si só, não deveria desencorajar a adoção de um software, mas sabemos que nem todos estão prontos para se tornarem Early Adopters.

Para quem é o Cloud Control então?

A AWS responde sua pergunta no seu anúncio de 2021: pessoas que construam soluções que operam usando serviços da AWS (especialmente se usarem muitos serviços!). Trouxe o excerto em inglês original para cá:

Builders - The first community is builders using AWS Services APIs to manage their infrastructure or their customer’s infrastructure. The ones requiring usage of low-level AWS Services APIs rather than higher level tools. For example, I know companies that manages AWS infrastructures on behalf of their clients. Many developed solutions to list and describe all resources deployed in their client’s AWS Accounts, for management and billing purposes. Often, they built specific tools to address their requirements, but find it hard to keep up with new AWS Services and features. Cloud Control API simplifies this type of tools by offering a consistent, resource-centric approach. It makes easier to keep up with new AWS Services and features.

APN Partners - The second community that benefits from Cloud Control API is APN Partners, such as HashiCorp (maker of Terraform) and Pulumi, and other APN Partners offering solutions that relies on AWS Services APIs. When AWS releases a new service or feature, our partner’s engineering teams need to learn, integrate, and test a new set of AWS Service APIs to expose it in their offerings. This is a time consuming process and often leads to a lag between the AWS release and the availability of the service or feature in their solution. With the new Cloud Control API, partners are now able to build a unique REST API code base, using unified API verbs, common input parameters, and common error types. They just have to merge the standardized pre-defined uniform resource model to interact with new AWS Services exposed as REST resources.

Se você não lê em inglês (melhore isso já!), vamos usar um exemplo.

A AWS anunciou, no fim de abril, um novo serviço (nº 356?) de "render farms" gerenciado com o pouco sugestivo¹ nome Deadline Cloud. Suponha que você trabalhe em uma empresa que faz trailers de filmes e tem interesse em usar este serviço; você não pode usar o terraform provider aws simplesmente porque ele ainda não é suportado:

No matching records for Deadline on AWS Terraform Providers

Isso quer dizer que você não pode usar sua infra-estrutura de IaC com Terraform para usar este serviço, certo?

Ou pode?

18 matching results for Deadline on AWS Cloud Control Terraform Provider

Como a própria Hashicorp conta em seu comunicado do post original:

Initially launched in 2021 as a tech preview, the Terraform AWS Cloud Control provider is automatically generated based on the Cloud Control API published by AWS, which means the latest features and services on AWS can be supported right away. The AWSCC provider gives developers access with several new AWS services such as: AWS Billing Conductor, AWS Chatbot, Amazon Personalize, Amazon Q Business, and more.

Em uma tradução livre, o provider Cloud Control para Terraform é gerado automaticamente usando como base a API disponibilizada pela AWS. Teoricamente isso quer dizer que qualquer funcionalidade disponibilizada pela AWS estará disponível quase que imediatamente.

Mas há detalhes adicionais! A lista de serviços acima do excerto em inglês lista os serviços Amazon Q Business (lançado em maio de 2024), AWS Billing Conductor (lançado em 2022), AWS Chatbot (lançado em 2020!) e Amazon Personalize, que foi lançado há quase 5 anos atrás!

Isso dá uma ideia que não é só uma questão de "usar os serviços lançados ontem", mas também usar serviços mais obscuros e menos usados, cuja baixa popularidade faz com que a implementação no provider principal não atinja massa crítica o suficiente para se justificar o tempo gasto (como o Amazon Personalize), oferecendo uma alternativa às pessoas que não conseguiam usar o mesmo padrão e convenções de IaC para 100% de sua infraestrutura na AWS.

Conclusão

Para a Hashicorp e Pulumi, naturalmente seria muito melhor se todos abandonassem seus providers oiginais e migrassem para os novos baseados em Cloud Control.

Mas esse desejo provavelmente não significa que irão descontinuar os providers originais e só oferecer manutenção nos novos - eles certamente não são loucos o suficiente para fazê-lo (ou são?).

Se sua empresa está interessada em usar os serviços mais novos (em especial o festival de ofertas sobre generative AI), serviços mais obscuros (como o Amazon Personalize) ou simplesmente tem o perfil "early adopter", em que os funcionários contam com espaço para depurar e contribuir com projetos, lembre-se: a API Cloud Control existe, e agora temos inclusive um Terraform Provider considerado pronto para uso em produção.

Aproveitem!


¹ O nome do serviço não é tão pouco sugestivo assim; na verdade não é sugestivo para você! Em 2017, a AWS comprou uma empresa chamada Thinkbox Software, que construía, entre outras coisas, soluções para gerenciamento e pós processamento de renderizações. A mais popular das ferramentas se chama Deadline; logo, AWS Deadline Cloud é o deploy automatizado deste software na nuvem.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .