Introdução ao Cloud Foundation Toolkit

1. Introdução ao CFT 101

ea557448aaa1fffc.png

Última atualização:03/03/2020

O que é o Cloud Foundation Toolkit?

Em essência, o CFT fornece modelos de práticas recomendadas para começar a usar o Google Cloud Platform rapidamente. Neste tutorial, você vai aprender a contribuir com o Cloud Foundation Toolkit.

O que é necessário

  • Uma conta do GitHub.
  • Docker instalado na sua máquina ( Mac install, Windows install)
  • Editor de código para edição de código (exemplo: Visual Studio Code)
  • Ter noções básicas sobre o Git e o GitHub.
  • Alguma experiência com Terraform e infraestrutura como código
  • Permissão para conceder o papel de criador do projeto a uma conta de serviço

O que você vai criar

Neste codelab, você vai aprender a contribuir com o Cloud Foundation Toolkit (CFT).

Você vai:

  • Configure um ambiente de desenvolvimento para contribuir com o CFT
  • Adicionar um atributo a um módulo do CFT
  • Adicionar testes para o recurso adicionado
  • Executar testes de integração no CFT
  • Executar testes de lint
  • Confirme o código para o GitHub e envie uma solicitação de envio (PR)

Para executar todas as etapas acima, adicione um novo recurso ao módulo CFT do Google Cloud Storage. Você vai adicionar um rótulo chamado "silly_label", que será adicionado automaticamente a todos os buckets criados no módulo do GCS CFT. Você também vai poder criar testes para validar seu recurso e garantir uma integração completa.

2. Configurar o ambiente de desenvolvimento

Se quiser, use o Cloud Shell para fins de desenvolvimento. Se você não quiser usar o Cloud Shell para contribuir com o CFT, configure o ambiente de desenvolvimento na sua máquina.

Configurar o Git

O GitHub é baseado em um sistema de controle de versões (VCS) de código aberto chamado Git. O Git é responsável por tudo que está relacionado ao GitHub acontece localmente na sua máquina ou no Cloud Shell.

  1. Ao usar o Cloud Shell, você não precisa instalar o git, porque ele vem pré-instalado.
$ git --version
# This will display the git version on the Cloud Shell.

Se você estiver configurando o ambiente de desenvolvimento na sua máquina, será necessário instalar o Git.

Como definir seu nome de usuário e e-mail no Git

O Git usa um nome de usuário para associar commits a uma identidade. O nome de usuário do Git não é igual ao do GitHub.

Você pode alterar o nome associado aos commits do Git usando o comando "git config". A alteração do nome associado às confirmações do Git usando o git config só afetará as confirmações futuras e não o nome usado para as confirmações anteriores.

Você configurou o Git e poderá bifurcar, criar e clonar ramificações. Usaremos bastante o Git neste codelab.

3. Fork CFT do repositório do GCS

Bifurcar um repositório do CFT

Você configurou o Git na máquina local ou no Cloud Shell na etapa anterior. Agora você precisa bifurcar o repositório CFT do Google Cloud Storage para começar a contribuir.

Uma bifurcação é uma cópia de um repositório. A bifurcação de um repositório permite testar as alterações livremente sem afetar o projeto original.

Geralmente, as bifurcações são usadas para propor mudanças no projeto de outra pessoa ou usar o projeto dela como ponto de partida para a própria ideia.

Por exemplo, você pode usar bifurcações para propor mudanças relacionadas à correção de um bug. Para corrigir um bug, você pode fazer o seguinte:

  • Bifurcar o repositório.
  • Corrija.
  • Enviar uma solicitação de envio ao proprietário do projeto.

Etapas para bifurcar um repositório do CFT:

  1. Abra o navegador da Web e navegue até o repositório terraform-google-modules/terraform-google-cloud-storage. Vamos usar esse repositório durante todo o codelab.
  2. No canto superior direito da página, clique em Bifurcar.

e3894c6de6a732b4.png

  1. Será exibida a opção onde você quer ter a bifurcação, escolher seu perfil, e o repositório será bifurcado.

Clonar sua bifurcação localmente

A bifurcação que você criou é uma cópia do repositório do módulo do GCS. Agora você clonará esse repositório no ambiente local para adicionar o novo atributo.

Etapas para clonar a bifurcação:

  1. Abra o navegador da Web e navegue até a bifurcação em terraform-google-modules/terraform-google-cloud-storage.
  2. No canto superior direito, você vai encontrar a opção "Clone or download" (Clonar ou fazer o download). clique nele.

3bfa87b9f7f01f61.png

  1. Após clicar no botão "Clone or download" clique no "Bloco de Notas" para copiar o URL da bifurcação. Você vai usar esse URL para clonar a bifurcação no ambiente local.

dbf3682d004e0ee0.png

  1. Acesse um terminal no VSCode ou na sua máquina e clone a bifurcação.
$ git clone <url>
# This command will clone your fork locally.
# Paste the copied URL from the previous step.
  1. Agora que você clonou sua bifurcação localmente, acesse seu repositório, crie uma nova ramificação e faça alterações de código nela.

Por convenção, é possível nomear a ramificação da seguinte forma:

  • Para solicitações de recursos: feature/feature-name
  • Para atualizações internas, internal/change-name
  • Para correções de bugs: bugfix/issue-name

Como você está adicionando um novo recurso, você pode chamar sua ramificação temporária de feature/silly_label

$ cd terraform-google-cloud-storage
# This command takes you into the cloned directory on your local machine.

$ git branch
# This command tells your current branch
# When you run this for the first time after you have cloned, your 
# output should say "master", that is your fork.

$ git checkout -b feature/silly_label
# This command creates a new branch on your fork and switches your 
# branch to the newly created branch.

$ git branch
# This command will confirm your current branch to be "feature/silly_label"

Você já pode começar a trabalhar no Cloud Foundation Toolkit.

4. Criar um ambiente de teste

O processo padrão de desenvolvimento do CFT usa um projeto de teste isolado para testes. Nesta etapa, vamos ajudar você a criar o projeto de teste (com base em uma configuração padrão) usando uma conta de serviço.

0. Instalar o Docker Engine

Se você estiver usando sua máquina para fins de desenvolvimento, instale o Docker Engine.

1. Instalar o SDK Google Cloud

Não será necessário instalar o SDK do Google Cloud se você estiver usando o Cloud Shell do GCP.

Acesse o SDK do Google Cloud e faça o download do instalador interativo para sua plataforma.

2. Definir a configuração

Para criar um ambiente de teste, você vai precisar de uma organização do Google Cloud, uma pasta de teste e uma conta de faturamento. Esses valores precisam ser definidos por meio de variáveis de ambiente:

export TF_VAR_org_id="your_org_id"
export TF_VAR_folder_id="your_folder_id"
export TF_VAR_billing_account="your_billing_account_id"

3 Configurar a conta de serviço

Antes de criar um ambiente de teste, faça o download de uma chave da conta de serviço para esse ambiente. Essa conta de serviço precisará dos papéis de Criador de projetos, Usuário da conta de faturamento e Leitor da organização. Essas etapas ajudarão você a criar uma nova conta de serviço, mas também é possível reutilizar uma conta existente.

3.1 Criar ou selecionar um projeto de origem do GCP

Antes de criar sua conta de serviço, você precisa selecionar um projeto para hospedá-la. Também é possível criar um novo projeto.

gcloud config set core/project YOUR_PROJECT_ID

3.2 Ativar as APIs do Google Cloud

Ative as seguintes APIs do Google Cloud no projeto de origem:

gcloud services enable cloudresourcemanager.googleapis.com
gcloud services enable iam.googleapis.com
gcloud services enable cloudbilling.googleapis.com

3.3 Criar uma conta de serviço

Crie uma nova conta de serviço para gerenciar o ambiente de teste:

# Creating a service account for CFT.
gcloud iam service-accounts create cft-onboarding \
  --description="CFT Onboarding Terraform Service Account" \
  --display-name="CFT Onboarding"

# Assign SERVICE_ACCOUNT environment variable for later steps
export SERVICE_ACCOUNT=cft-onboarding@$(gcloud config get-value core/project).iam.gserviceaccount.com

Verifique se a conta de serviço foi criada:

gcloud iam service-accounts list --filter="EMAIL=${SERVICE_ACCOUNT}"

3.4 Conceda à conta de serviço os papéis de Criador de projetos, Usuário da conta de faturamento e Leitor da organização:

gcloud resource-manager folders add-iam-policy-binding ${TF_VAR_folder_id} \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/resourcemanager.projectCreator"
gcloud organizations add-iam-policy-binding ${TF_VAR_org_id} \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/billing.user"
gcloud organizations add-iam-policy-binding ${TF_VAR_org_id} \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/resourcemanager.organizationViewer"

Agora você tem uma conta de serviço para gerenciar o ambiente de teste.

4. Atribuir o papel de usuário da conta de faturamento no recurso da conta de faturamento

4.1 Buscar a política do IAM da conta de faturamento

Faça o download das vinculações de política do IAM atuais na conta de faturamento.

gcloud beta billing accounts get-iam-policy ${TF_VAR_billing_account} | tee policy.yml

4.2 Atualizar a política para incluir a conta de serviço

Atualize o arquivo policy.yml para adicionar uma nova vinculação à conta de serviço com o papel roles/billing.user

bindings:
- members:
  - serviceAccount:cft-onboarding@<YOUR_PROJECT_ID>.iam.gserviceaccount.com
  role: roles/billing.user

4.3 Atualizar a política da conta de faturamento

Aplicar as alterações na conta de faturamento

gcloud beta billing accounts set-iam-policy ${TF_VAR_billing_account} policy.yml

5. Prepare a credencial do Terraform

Para criar o ambiente de teste, faça o download da chave da conta de serviço no shell.

5.1 Chave da conta de serviço

Criar e fazer o download de uma chave de conta de serviço para o Terraform

gcloud iam service-accounts keys create cft.json --iam-account=${SERVICE_ACCOUNT}

5.2 Configurar a credencial do Terraform

Forneça a chave ao Terraform usando a variável de ambiente SERVICE_ACCOUNT_JSON e defina o valor como o conteúdo da chave da sua conta de serviço.

export SERVICE_ACCOUNT_JSON=$(< cft.json)

6. criar um projeto de teste para implantações do Terraform

Agora que está tudo pronto, você pode criar o projeto de teste com um único comando. Execute este comando a partir da raiz do diretório terraform-google-cloud-storage:

make docker_test_prepare

A saída abaixo vai aparecer ao executar make docker_test_prepare. No final, você vai receber o projeto de teste que foi criado. Nele, você vai implantar e testar o módulo do Cloud Storage com o novo recurso.

macbookpro3:terraform-google-cloud-storage user$ make docker_test_prepare
docker run --rm -it \
                -e SERVICE_ACCOUNT_JSON \
                -e TF_VAR_org_id \
                -e TF_VAR_folder_id \
                -e TF_VAR_billing_account \
                -v /Users/cft/terraform-google-cloud-storage:/workspace \
                gcr.io/cloud-foundation-cicd/cft/developer-tools:0.8.0 \
                /usr/local/bin/execute_with_credentials.sh prepare_environment
Activated service account credentials for: [cft-onboarding@<project_id>.iam.gserviceaccount.com]
Activated service account credentials for: [cft-onboarding@<project_id>.iam.gserviceaccount.com]
Initializing modules...

Initializing the backend...

Initializing provider plugins...

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.

* provider.google-beta: version = "~> 3.9"
* provider.null: version = "~> 2.1"
* provider.random: version = "~> 2.2"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
module.project.module.project-factory.null_resource.preconditions: Refreshing state... [id=8723188031607443970]
module.project.module.project-factory.null_resource.shared_vpc_subnet_invalid_name[0]: Refreshing state... [id=5109975723938185892]
module.project.module.gsuite_group.data.google_organization.org[0]: Refreshing state...
module.project.module.project-factory.random_id.random_project_id_suffix: Refreshing state... [id=rnk]
module.project.module.project-factory.google_project.main: Refreshing state... [id=<project-id>]
module.project.module.project-factory.google_project_service.project_services[0]: Refreshing state... [id=<project-id>/storage-api.googleapis.com]
module.project.module.project-factory.google_project_service.project_services[1]: Refreshing state... [id=<project-id>/cloudresourcemanager.googleapis.com]
module.project.module.project-factory.google_project_service.project_services[2]: Refreshing state... [id=<project-id>/compute.googleapis.com]
module.project.module.project-factory.data.null_data_source.default_service_account: Refreshing state...
module.project.module.project-factory.google_service_account.default_service_account: Refreshing state... [id=projects/ci-cloud-storage-ae79/serviceAccounts/project-service-account@<project-id>.iam.gserv
iceaccount.com]
module.project.module.project-factory.google_project_service.project_services[3]: Refreshing state... [id=<project-id>/serviceusage.googleapis.com]
module.project.module.project-factory.null_resource.delete_default_compute_service_account[0]: Refreshing state... [id=3576396874950891283]
google_service_account.int_test: Refreshing state... [id=projects/<project-id>/serviceAccounts/cft-onboarding@<project-id>.iam.gserviceaccount.com]
google_service_account_key.int_test: Refreshing state... [id=projects/<project-id>/serviceAccounts/cft-onboarding@<project-id>.iam.gserviceaccount.com/keys/351009a1e011e88049ab2097994d1c627a61
6961]
google_project_iam_member.int_test[1]: Refreshing state... [id=<project-id>/roles/iam.serviceAccountUser/serviceaccount:cft-onboarding@<project-id>.iam.gserviceaccount.com]
google_project_iam_member.int_test[0]: Refreshing state... [id=<project-id>/roles/storage.admin/serviceaccount:cft-onboarding@<project-id>.iam.gserviceaccount.com]

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

project_id = <test-project-id>
sa_key = <sensitive>
Found test/setup/make_source.sh. Using it for additional explicit environment configuration.

Você criou um projeto de teste referenciado por project_id, como mostra a saída do console. Seu ambiente de desenvolvimento e teste está configurado.

5. Adicionar um novo atributo ao módulo do CFT

Agora que o ambiente de desenvolvimento e teste foi configurado, vamos começar a adicionar o "silly_label" no módulo do CFT google-cloud-storage.

Você precisa estar no terraform-google-cloud-storage e abrir o arquivo main.tf como mostrado abaixo na estrutura de pastas.

17f2d3b9893be853.png

Desde "silly_label" for um rótulo, você adicionará o recurso na linha 27 na variável "labels" em main.tf, como você pode ver abaixo:

terraform-google-cloud-storage/main.tf

resource "google_storage_bucket" "buckets" {
 <...>
 storage_class = var.storage_class
 // CODELAB:Add silly label in labels variable
 labels        = merge(var.labels, { name = replace("${local.prefix}${lower(element(var.names, count.index))}", ".", "-") }, { "silly" = var.silly_label })
 force_destroy = lookup(
 <...>
}

Agora você vai adicionar a variável silly_label ao arquivo variables.tf que aparece na estrutura de pastas acima.

Copie e cole o código abaixo na linha 29 do arquivo variables.tf. Além disso, confira se há um caractere de nova linha acima e abaixo do bloco de variáveis adicionado.

terraform-google-cloud-storage/variables.tf

variable "names" {
 description = "Bucket name suffixes."
 type        = list(string)
}

// CODELAB: Add "silly_label" variable to variables.tf between "names" and "location"
variable "silly_label" {
 description = "Sample label for bucket."
 type        = string
}

variable "location" {
 description = "Bucket location."
 default     = "EU"
}

6. Adicionar um novo atributo ao exemplo de bucket de armazenamento

Você adicionou o atributo ao main.tf do módulo e agora vai testar o recurso adicionado com um exemplo.

"silly_label" precisam ser adicionados ao arquivo example/multiple-buckets/main.tf

Esse exemplo será usado por um recurso na próxima etapa para realizar testes de integração.

Copie e cole a variável silly_label line abaixo na linha 27 em main.tf em terraform-google-cloud-storage/examples/multiple-buckets/ como mostrado na estrutura de pastas:

408cb1365b2a0793.png

terraform-google-cloud-storage/examples/multiple-buckets/main.tf

module "cloud_storage" {
 <...>
 // CODELAB: Add "silly_label" as an example to main.tf.
 silly_label        = "awesome"

 <..>
}

7. Criar um teste de especificação para verificar o recurso

Você adicionou o recurso ao main.tf do módulo e, em seguida, ao exemplo "multiple_buckets" para ser testado com o recurso. Você precisa testar seu recurso com um teste de integração InSpec escrito em Ruby.

Você adicionará seus novos testes no arquivo gsutil.rb encontrado na estrutura de pastas abaixo:

b2bfeb203477e0c8.png

Você adicionou "silly_label" em todos os buckets criados com o módulo multiple_buckets e agora você precisa criar testes para conhecer o novo recurso.

No código abaixo, você está recebendo o rótulo de cada bloco por meio do comando gsutil e, em seguida, verifica a saída retornada do comando.

terraform-google-cloud-storage/test/integration/multiple-buckets/controls/gsutil.rb

control "gsutil" do
 <..>

# CODELAB: Copy paste the below test in gsutil.rb to test silly_label feature.

# command to get the labels for bucket_1
describe command("gsutil label get gs://#{attribute("names_list")[0]}") do
   //check if the command gave a valid response
   its(:exit_status) { should eq 0 }
   its(:stderr) { should eq "" }

   //parse the command's output into JSON
   let!(:data) do
     if subject.exit_status == 0
         JSON.parse(subject.stdout)
     else
         {}
     end
   end

   # check if bucket_1 has the new "silly" label with the value "awesome"
   describe "bucket_1" do
   it "has label" do
       data.each do |bucket|
           expect(data["silly"]).to include("awesome")
       end
     end
   end
 end

8. Executar testes de integração no CFT

Teste de integração

Os testes de integração são usados para verificar o comportamento do módulo raiz, dos submódulos e dos módulos de exemplo. Adições, mudanças e correções precisam ser acompanhadas com testes.

Os testes de integração são executados usando Kitchen, Kitchen-Terraform e InSpec. Por conveniência, essas ferramentas são empacotadas em uma imagem do Docker.

A estratégia geral para esses testes é verificar o comportamento dos módulos de exemplo, garantindo assim que o módulo raiz, os submódulos e os módulos de exemplo estejam funcionalmente corretos.

Na execução interativa, cada etapa é executada por meio de vários comandos.

  1. Execute make docker_run para iniciar o contêiner de teste do Docker no modo interativo.

O Make é uma ferramenta de automação de builds que cria automaticamente programas e bibliotecas executáveis com base no código-fonte lendo arquivos chamados Makefiles que especificam como derivar o programa de destino. Quando você faz alterações em um arquivo, o contêiner do Docker precisa ser atualizado automaticamente.

Ao executar make docker_run, você cria um espaço de trabalho no contêiner do Docker e ativa as credenciais da sua conta de serviço. O espaço de trabalho será usado nas próximas etapas para executar testes.

A saída abaixo vai aparecer no seu terminal:

Activated service account credentials for: [cft@<PROJECT_ID>.iam.gserviceaccount.com]
  1. Execute kitchen_do list para listar todas as instâncias no seu espaço de trabalho que contêm testes de integração.
     You will see the below output in your terminal.
    
[root@<CONTAINER_ID> workspace]# kitchen_do list
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [cft@<PROJECT_ID>.iam.gserviceaccount.com]
Instance                  Driver     Provisioner  Verifier   Transport  Last Action  Last Error
multiple-buckets-default  Terraform  Terraform    Terraform  Ssh        Verified     <None>
  1. Execute kitchen_do create <EXAMPLE_NAME> para inicializar o diretório de trabalho para um módulo de exemplo.

Esta etapa inicializa a cozinha e o Terraform no espaço de trabalho.

A resposta abaixo vai aparecer no seu terminal.

[root@<CONTAINER_ID> workspace]# kitchen_do create multiple-buckets-default
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [cft@<PROJECT_ID>.iam.gserviceaccount.com]
-----> Starting Kitchen (v1.24.0)
-----> Creating <multiple-buckets-default>...
       Terraform v0.12.12
       + provider.google v3.10.0
       
       Your version of Terraform is out of date! The latest version
       is 0.12.21. You can update by downloading from www.terraform.io/downloads.html
$$$$$$ Running command `terraform init -input=false -lock=true -lock-timeout=0s  -upgrade -force-copy -backend=true  -get=true -get-plugins=true -verify-plugins=true` in directory /workspace/test/fi
xtures/multiple_buckets
       Upgrading modules...
       - example in ../../../examples/multiple_buckets
       - example.cloud_storage in ../../..
       
       Initializing the backend...
       
       Initializing provider plugins...
       - Checking for available provider plugins...
       - Downloading plugin for provider "google" (hashicorp/google) 2.18.1...
       - Downloading plugin for provider "random" (hashicorp/random) 2.2.1...
       
       Terraform has been successfully initialized!
$$$$$$ Running command `terraform workspace select kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
       Finished creating <multiple-buckets-default> (0m11.01s).
-----> Kitchen is finished. (0m12.62s)
  1. Execute kitchen_do converge <EXAMPLE_NAME> para aplicar o módulo de exemplo.

Esta etapa aplica o espaço de trabalho do Terraform criado na etapa anterior ao projeto do GCP criado anteriormente no codelab.

A resposta abaixo vai aparecer no seu terminal.

[root@<CONTAINER_ID> workspace]# kitchen_do converge multiple-buckets-default
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [cft@<YOUR_PROJECT_ID>.iam.gserviceaccount.com]
-----> Starting Kitchen (v1.24.0)
-----> Converging <multiple-buckets-default>...
       Terraform v0.12.20
       + provider.google v3.9.0
       
       Your version of Terraform is out of date! The latest version
       is 0.12.21. You can update by downloading from https://www.terraform.io/downloads.html
$$$$$$ Running command `terraform workspace select kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
$$$$$$ Running command `terraform get -update` in directory /workspace/test/fixtures/multiple_buckets
       - example in ../../../examples/multiple_buckets
       - example.cloud_storage in ../../..
$$$$$$ Running command `terraform validate   ` in directory /workspace/test/fixtures/multiple_buckets
       Success! The configuration is valid.
       
$$$$$$ Running command `terraform apply -lock=true -lock-timeout=0s -input=false -auto-approve=true  -parallelism=10 -refresh=true  ` in directory /workspace/test/fixtures/multiple_buckets
       random_pet.main: Creating...
       random_pet.main: Creation complete after 0s [id=<BUCKET-ID>]
       module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Creating...
       module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Creating...
       module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Creation complete after 3s [id=<BUCKET-ID-01>]
       module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Creation complete after 3s [id=<BUCKET-ID-02>]
       
       Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
       
       Outputs:
       
       names = {
         "one" = "<BUCKET-ID-01>"
         "two" = "<BUCKET-ID-02>"
       }
       names_list = [
         "<BUCKET-NAME-01>",
         "<BUCKET-NAME-02>",
       ]
       project_id = ci-cloud-storage-ae79
       Finished converging <multiple-buckets-default> (0m7.17s).
-----> Kitchen is finished. (0m8.77s)
  1. Execute kitchen_do verify <EXAMPLE_NAME> para testar o módulo de exemplo.

Esta etapa executará o arquivo gsutils.rb, que contém testes para o módulo multiple_buckets. Cada teste tem um comando gsutil que será executado no projeto de teste que você criou anteriormente usando a configuração de credenciais da conta de serviço.

Se ocorrer algum erro, você verá o que era esperado e o que foi recebido pelo comando para o teste.

A resposta abaixo vai aparecer no seu terminal.

multiple_buckets local: Verifying

Profile: multiple_buckets
Version: (not specified)
Target:  local://

  ✔  gsutil: gsutil
     ✔  Command: `gsutil ls -p <PROJECT_ID>` exit_status should eq 0
     ✔  Command: `gsutil ls -p <PROJECT_ID>` stderr should eq ""
     ✔  Command: `gsutil ls -p <PROJECT_ID>` stdout should include "multiple-buckets-mzgy-eu-one"
     ✔  Command: `gsutil ls -p <PROJECT_ID>` stdout should include "<BUCKET-ID-01>"
     ✔  Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-01>` exit_status should eq 0
     ✔  Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-01>` stderr should eq ""
     ✔  Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-01>` stdout should include "Enabled: True"
     ✔  Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-02>` exit_status should eq 0
     ✔  Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-02>` stderr should eq ""
     ✔  Command: `gsutil bucketpolicyonly get gs://<BUCKET-ID-02>` stdout should include "Enabled: False"
     ✔  Command: `gsutil label get gs://<BUCKET-ID-01>` exit_status should eq 0
     ✔  Command: `gsutil label get gs://<BUCKET-ID-01>` stderr should eq ""
     ✔  Command: `gsutil label get gs://<BUCKET-ID-01>` bucket_1 has label
     ✔  Command: `gsutil label get gs://<BUCKET-ID-02>` exit_status should eq 0
     ✔  Command: `gsutil label get gs://<BUCKET-ID-02>` stderr should eq ""
     ✔  Command: `gsutil label get gs://<BUCKET-ID-02>` bucket_2 has label
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq "NEARLINE"
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq "SetStorageClass"
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq 10
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq false
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` should eq ["MULTI_REGIONAL", "STANDARD", "DURABLE_REDUCED_AVAILABILITY"]
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` exit_status should eq 0
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-01>` stderr should eq ""
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq "NEARLINE"
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq "SetStorageClass"
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq 10
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq false
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` should eq ["MULTI_REGIONAL", "STANDARD", "DURABLE_REDUCED_AVAILABILITY"]
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` exit_status should eq 0
     ✔  Command: `gsutil lifecycle get gs://<BUCKET-ID-02>` stderr should eq ""


Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
Test Summary: 30 successful, 0 failures, 0 skipped
       Finished verifying <multiple-buckets-default> (0m8.83s).
-----> Kitchen is finished. (0m16.61s)
  1. Execute kitchen_do destroy <EXAMPLE_NAME> para destruir o estado do módulo de exemplo.

Nesta etapa, o espaço de trabalho que você criou nas etapas acima vai ser destruído. Esta etapa também vai destruir os buckets do GCS criados no projeto com o rótulo que você adicionou ao módulo do GCS.

Você pode conferir a saída abaixo no seu terminal.

[root@<CONTAINER_ID> workspace]# kitchen_do destroy multiple-buckets-default
Automatically setting inputs from outputs of test/setup
Found test/source.sh. Using it for additional explicit environment configuration.
Activated service account credentials for: [ci-cloud-storage@ci-cloud-storage-54ab.iam.gserviceaccount.com]
-----> Starting Kitchen (v1.24.0)
-----> Destroying <multiple-buckets-default>...
       Terraform v0.12.12
       + provider.google v3.10.0
       
       Your version of Terraform is out of date! The latest version
       is 0.12.21. You can update by downloading from www.terraform.io/downloads.html
$$$$$$ Running command `terraform init -input=false -lock=true -lock-timeout=0s  -force-copy -backend=true  -get=true -get-plugins=true -verify-plugins=true` in directory /workspace/test/fixtures/mu
ltiple_buckets
       Initializing modules...
       
       Initializing the backend...
       
       Initializing provider plugins...
       
       Terraform has been successfully initialized!
$$$$$$ Running command `terraform workspace select kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
$$$$$$ Running command `terraform destroy -auto-approve -lock=true -lock-timeout=0s -input=false  -parallelism=10 -refresh=true  ` in directory /workspace/test/fixtures/multiple_buckets
       random_string.prefix: Refreshing state... [id=mzgy]
       module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Refreshing state... [id=<BUCKET-ID-01>]
       module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Refreshing state... [id=<BUCKET-ID-02>]
       module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Destroying... [id=<BUCKET-ID-01>]
       module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Destroying... [id=<BUCKET-ID-02>]
       module.example.module.cloud_storage.google_storage_bucket.buckets[0]: Destruction complete after 1s
       module.example.module.cloud_storage.google_storage_bucket.buckets[1]: Destruction complete after 2s
       random_string.prefix: Destroying... [id=mzgy]
       random_string.prefix: Destruction complete after 0s
       
       Destroy complete! Resources: 3 destroyed.
$$$$$$ Running command `terraform workspace select default` in directory /workspace/test/fixtures/multiple_buckets
       Switched to workspace "default".
$$$$$$ Running command `terraform workspace delete kitchen-terraform-multiple-buckets-default` in directory /workspace/test/fixtures/multiple_buckets
       Deleted workspace "kitchen-terraform-multiple-buckets-default"!
       Finished destroying <multiple-buckets-default> (0m6.49s).
-----> Kitchen is finished. (0m8.10s)

9. Como gerar documentação para entradas e saídas

As tabelas de entradas e saídas nos README do módulo raiz, dos submódulos e dos módulos de exemplo são geradas automaticamente com base no variables e outputs dos respectivos módulos. Essas tabelas precisarão ser atualizadas se as interfaces do módulo forem alteradas.

Execute:

make generate_docs
# This will generate new Inputs and Outputs tables

10. Executar testes de lint no CFT

O linter é uma ferramenta que analisa o código-fonte para sinalizar erros de programação, bugs, erros de estilo e construções suspeitas.

Muitos dos arquivos no repositório podem ser examinados ou formatados para manter um padrão de qualidade. Para garantir a qualidade no CFT, você vai usar um teste de lint.

Execute:

make docker_test_lint
# This will run all lint tests on your repo

11. Como enviar um PR no GitHub

Agora que você alterou seu código localmente e o testou com os testes de integração, é hora de publicar esse código no repositório mestre.

Para disponibilizar o código no repositório mestre, você precisará confirmar as alterações no código na ramificação e enviá-las por push para o repositório mestre. Para que seu código seja adicionado ao repositório principal que você bifurcou no início do codelab, gere uma solicitação de envio (PR, na sigla em inglês) no repositório mestre depois de confirmar o código no seu repositório.

Quando você enviar um PR, o administrador do repositório vai ser notificado para analisar as mudanças propostas no código. Além disso, também é possível adicionar outros usuários como revisores para receber feedback sobre as alterações no código. O PR acionará um Cloud Build que executará testes no repositório.

Com base nas alterações feitas no código, os revisores fornecerão comentários e pedem modificações caso algo precise ser alterado de acordo com as práticas recomendadas e a documentação. O administrador analisará as alterações no código, verificará se ele está em conformidade com o repositório e pode solicitar novamente que você faça algumas alterações antes de mesclar seu código no repositório mestre.

Execute as etapas a seguir para confirmar o código na ramificação bifurcada e enviá-lo por push:

  1. A primeira etapa é adicionar os arquivos alterados ao repositório local.
$ git add main.tf
$ git add README.md
$ git add variables.tf
$ git add examples/multiple-buckets/main.tf
$ git add test/integration/multiple-buckets/controls/gsutil.rb
# The ‘git add' command adds the file in the local repository and 
# stages the file for commit. To unstage a file, use git reset HEAD YOUR-FILE
  1. Seus arquivos estão preparados. Em seguida, confirme as alterações.
$ git commit -m "First CFT commit"
# This will commit the staged changes and prepares them to be pushed 
# to a remote repository. To remove this commit and modify the file, 
# use 'git reset --soft HEAD~1' and commit and add the file again.
  1. Envie as alterações confirmadas no repositório local para o GitHub para criar uma solicitação de envio (PR, na sigla em inglês).
$ git push -u origin master
# Pushes the changes in your local repository up to the remote
# repository you specified as the origin

Suas alterações de código agora estão prontas para uma solicitação de envio.

Execute as etapas a seguir para enviar uma PR ao repositório terraform-google-modules/terraform-google-cloud-storage :

  1. No navegador da Web, acesse a página principal do repositório.
  2. No menu Ramificação, escolha a bifurcação que contém suas confirmações.
  3. À direita de "Ramificação", clique em "Nova solicitação de envio".

40087ce52ee5ed35.png

  1. Usar a "base" básica menu suspenso para selecionar a ramificação em que você quer mesclar as alterações. Geralmente, esse é o "mestre" já que você confirmou as alterações de código feitas na bifurcação.
  2. Insira um título e uma descrição para a solicitação de envio para descrever as mudanças de código. Seja o mais específico possível e conciso.
  3. Para criar uma solicitação de envio pronta para análise, clique em "Criar solicitação de envio".

a9e70a2ec9653cd7.png

  1. Você verá gatilhos do Cloud Build em execução que são acionados devido ao PR.

Você enviou a primeira alteração de código para a ramificação bifurcada e criou o primeiro CFT PR na ramificação mestre.

12. Parabéns

Parabéns! Você adicionou um recurso a um módulo do CFT e enviou um PR para análise.

Você adicionou um recurso a um módulo do CFT, o testou localmente com um exemplo e realizou testes antes de confirmar seu código no GitHub. Por fim, você enviou um PR para revisão e mesclagem final no CFT.

Agora você sabe as etapas importantes para começar a usar o Cloud Foundation Toolkit.