<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Igor Souza</title>
    <description>The latest articles on DEV Community by Igor Souza (@igordcsouzaaa).</description>
    <link>https://dev.to/igordcsouzaaa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F143215%2Fe67b22e4-37dd-4288-859c-d92e84b4193b.jpg</url>
      <title>DEV Community: Igor Souza</title>
      <link>https://dev.to/igordcsouzaaa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/igordcsouzaaa"/>
    <language>en</language>
    <item>
      <title>Terraform APPLY + DESTROY</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Sun, 21 Mar 2021 12:53:19 +0000</pubDate>
      <link>https://dev.to/igordcsouzaaa/terraform-apply-destroy-1oe9</link>
      <guid>https://dev.to/igordcsouzaaa/terraform-apply-destroy-1oe9</guid>
      <description>&lt;h1&gt;
  
  
  Curso Completo Gratis!
&lt;/h1&gt;

&lt;p&gt;Esse post faz parte de um curso completo sobre Terraform, caso voce queira saber mais sobre terraform da um pulo no meu &lt;a href="https://igordcsouza.com"&gt;blog&lt;/a&gt; ou no meu &lt;a href="https://www.youtube.com/channel/UC3yoPZJdjwOjrHWy_iEP08A"&gt;youtube&lt;/a&gt; para ter acesso ao curso completo 100% gratuito.&lt;/p&gt;

&lt;h1&gt;
  
  
  Mas se quiser contribuir:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.udemy.com/course/terraform-na-pratica/?referralCode=6DAB87D1325C238B4745"&gt;Aqui no Udemy&lt;/a&gt; tem o mesmo curso que esta disponivel 100% gratuito no youtube pra quem quiser e puder contribuir financeiramete :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform Apply
&lt;/h2&gt;

&lt;p&gt;Vamos utilizar o comando &lt;code&gt;terraform apply&lt;/code&gt; para tentarmos criar nosso droplet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.web will be created
  + resource "digitalocean_droplet" "web" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + id                   = (known after apply)
      + image                = "ubuntu-20-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "web-1"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "nyc2"
      + resize_disk          = true
      + size                 = "s-1vcpu-1gb"
      + status               = (known after apply)
      + urn                  = (known after apply)
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você prestar atenção, vai perceber que a saída até aqui é bem similar a que tivemos no &lt;code&gt;plan&lt;/code&gt;, isso acontece por que o &lt;code&gt;apply&lt;/code&gt; antes de realmente aplicar as alterações ele executa um plan para que você possa se certificar de que realmente quer fazer isso.&lt;/p&gt;

&lt;p&gt;Se você quiser burlar esse plan e simplesmente aceitar o que vai ser criado, basta executar &lt;code&gt;terraform apply -auto-approve&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform apply -auto-approve
digitalocean_droplet.web: Creating...

Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Achou que eu ia te livrar de todos os erros? Achou errado!&lt;/p&gt;

&lt;p&gt;Bom, &lt;code&gt;401 Unable to authenticate you&lt;/code&gt; significa que não foi possível se autenticar com a api da Digital Ocean. Se voltarmos lá na página sobre o provider vamos conseguir entender melhor como corrigir o erro.&lt;/p&gt;

&lt;p&gt;De toda forma, a primeira coisa que precisamos fazer é criar um token no painel da Digital Ocean. Acesse o painel de controle da sua conta e procure por API, no momento que escrevo é o último item da coluna esquerda. Clique em &lt;code&gt;generate new token&lt;/code&gt; de um nome para o seu token e copie o token que vai aparecer para você. Algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; b783123asd294f002c5ea9af1231298327903284kmmsadoiu48d02707a2018588d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora vamos seguir o jeito mais simples e completamente&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;variable "do_token" {
  default = "b783123asd294f002c5ea9af1231298327903284kmmsadoiu48d02707a2018588d"
}

provider "digitalocean" {
  token = var.do_token
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O nome &lt;code&gt;do_token&lt;/code&gt; poderia ser qualquer coisa, esse é o campo onde você nomeia sua variável e o parametro &lt;code&gt;default&lt;/code&gt; e onde você cadastra um valor padrão pra ela. Sem esse parâmetro, toda vez que você rodar o &lt;code&gt;plan&lt;/code&gt; ou o &lt;code&gt;apply&lt;/code&gt; ele vai te perguntar o valor da variável. Se isso é o que você quer, basta remover a linha com o parâmetro default.&lt;/p&gt;

&lt;p&gt;Vamos executar novamente nosso apply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform apply -auto-approve
digitalocean_droplet.web: Creating...

Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mesmo com o token cadastrado, a gente continua recebendo o mesmo erro. Isso acontece por que apesar de termos criado uma variável, não contamos para o provider que ele deve utilizar essa variável. Vamos fazer isso agora.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; provider "digitalocean" {
  token = var.do_token
}

variable "do_token" {
  default = "b783726c929c48febf8555eee856f84f002c5ea9af7d49648d02707a2018588d"
}

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-20-04-x64"
  name   = "web-1"
  region = "nyc2"
  size   = "s-1vcpu-1gb"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora o provider &lt;code&gt;digitalocean&lt;/code&gt; sabe que ele deve procurar por uma variável chamada &lt;code&gt;do_token&lt;/code&gt; e utilizar no parâmetro &lt;code&gt;token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vamos tentar mais uma vez criar nossa máquina.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform apply -auto-approve
digitalocean_droplet.web: Creating...

Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 422 nyc2 is unavailable.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Opa, agora aconteceu uma das maiores felicidades de quem escreve código. Mudou o erro! O que é bom pois antes estavamos recebendo uma mensagem de que não conseguíamos nos conectar e agora a mensagem foi &lt;code&gt;422 nyc2 nao esta disponivel&lt;/code&gt;. Acontece que apesar da documentação do provider dar o exemplo com a região &lt;code&gt;nyc2&lt;/code&gt;, essa região não está disponível a algum tempo já. Eu não sei exatamente se eles nunca se preocuparam em corrigir isso ou se o objetivo é fazer a gente aprender a debugar o problema. Enfim, a solução é só alterar a região para qualquer outra que exista, vamos mudar pra &lt;code&gt;ams3&lt;/code&gt; que e a região de Amsterdam pra ficar mais pertinho de mim, mas você pode usar outra qualquer como &lt;code&gt;nyc3&lt;/code&gt; por exemplo.&lt;/p&gt;

&lt;p&gt;Mais uma tentativa:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform apply -auto-approve

digitalocean_droplet.web: Creating...
digitalocean_droplet.web: Still creating... [10s elapsed]
digitalocean_droplet.web: Still creating... [20s elapsed]
digitalocean_droplet.web: Still creating... [30s elapsed]
digitalocean_droplet.web: Creation complete after 33s [id=232247846]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Muito bom, mas agora vem a questão! Como a gente pode ter alguns dados desse droplet que acabamos de criar? Por exemplo, se eu quiser saber o IP desse droplet, como a gente faz?&lt;/p&gt;

&lt;p&gt;Pra isso vamos utilizar os &lt;code&gt;outputs&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform Output
&lt;/h2&gt;

&lt;p&gt;Toda documentação de um resource é dividido em pelo menos tres níveis. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exemplo de Uso&lt;/li&gt;
&lt;li&gt;Referência de Argumento (ou parâmetro)&lt;/li&gt;
&lt;li&gt;Referência de Atributos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Todos os itens que tivermos dentro do nível de referência de atributo podem ser utilizados seja para passar para um outro resource ou para ser utilizado como output do nosso código. Antes de começarmos a misturar atributos de um recurso com argumento de outro, vamos usar os atributos na sua forma mais simples, como um output.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;output&lt;/code&gt; em si é uma feature que permite voce apresentar o valor de alguma coisa do seu código na tela. Mais pra frente vamos ver uma outra utilidade do &lt;code&gt;output&lt;/code&gt; que é retornar os valores de um módulo. Mas fica tranquilo que isso é mais pra frente.&lt;/p&gt;

&lt;p&gt;Por hora vamos adicionar o seguinte num arquivo chamado &lt;code&gt;output.tf&lt;/code&gt;, que esteja na mesma pasta que nosso &lt;code&gt;main.tf&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output "droplet_ip" {
  value = "hashicourse"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos executar novamente o comando &lt;code&gt;apply&lt;/code&gt; e vamos ver que agora temos mais um retorno no nosso código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform apply -auto-approve
digitalocean_droplet.web: Refreshing state... [id=232247846]

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

Outputs:

droplet_ip = "hashicourse"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nada foi criado ou alterado, como esperado, mas vemos um &lt;code&gt;Outputs:&lt;/code&gt; na resposta e o valor que a gente cadastrou pro ip do nosso droplet. Agora manter esse valor hardcoded não vai nos ajudar muito. Vamos então utilizar um atributo do nosso droplet pra isso. &lt;/p&gt;

&lt;p&gt;Primeiro, deixa eu te mostrar o código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; resource "digitalocean_droplet" "web" {
  image  = "ubuntu-20-04-x64"
  name   = "web-1"
  region = "ams3"
  size   = "s-1vcpu-1gb"
}

output "droplet_ip" {
  value = digitalocean_droplet.web.ipv4_address
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;.A forma de chegarmos nesse atributo é bem simples.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[A] Primeiro você precisa pegar o nome do recurso, que é aquele primeiro ali "digitalocean_droplet" que nada mais é como uma forma de dizer para o provedor qual o recurso você tá querendo criar. &lt;/li&gt;
&lt;li&gt;[B] Segundo pega o nome que você deu para aquele recurso, no nosso caso "web". É muito comum precisarmos utilizar mais de uma vez um recurso no nosso código e essa é uma das formas de nomear aquele recurso. Vale lembrar que esse nome é único, ok?&lt;/li&gt;
&lt;li&gt;[C] Por último precisamos ir lá na documentação e ver qual dos atributos disponíveis nos fornece o que precisamos. É raro que você precise de algo que não está ali disponível, mas raro não é impossível.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por fim basta montar sempre no formato A.B.C :) &lt;/p&gt;

&lt;p&gt;Se você rodar o seu código agora deve ter um retorno como o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform apply -auto-approve
digitalocean_droplet.web: Refreshing state... [id=232247846]

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

Outputs:

droplet_ip = "104.248.203.68"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Muito provavelmente seu numero de ip é diferente do meu, mas se por algum milagre você pegou o mesmo, bate um print e me manda :)&lt;/p&gt;

&lt;p&gt;Uma última dica no que se refere a outputs é que você não precisa utilizar apenas o apply para ter acesso a todos os outputs do seu código. Considerando que você já tenha executado o apply pelo menos uma vez, você pode utilizar o &lt;code&gt;terraform output&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform output
droplet_ip = "104.248.203.68"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Terraform Destroy
&lt;/h2&gt;

&lt;p&gt;Agora que já criamos um droplet, você talvez esteja se perguntando "Beleza, agora como eu desligo esse droplet pra não gastar meu bônus?", bom pra isso tem um comando com nome bem sugestivo &lt;code&gt;destroy&lt;/code&gt;.&lt;br&gt;
O &lt;code&gt;terraform destroy&lt;/code&gt; é o oposto do &lt;code&gt;apply&lt;/code&gt;. Uma das coisas que ambos tem em comum é o plan antes de executar. A gente não falou antes, mas existe um parâmetro no &lt;code&gt;plan&lt;/code&gt; chamado de &lt;code&gt;-destroy&lt;/code&gt;. E esse é o parâmetro que o terraform usa quando a gente executa o &lt;code&gt;terraform destroy&lt;/code&gt;, a saída deve ser parecida com a seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform destroy

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # digitalocean_droplet.web will be destroyed
  - resource "digitalocean_droplet" "web" {
      - backups              = false -&amp;gt; null
      - created_at           = "2021-02-17T19:34:37Z" -&amp;gt; null
      - disk                 = 25 -&amp;gt; null
      - id                   = "232254786" -&amp;gt; null
      - image                = "ubuntu-20-04-x64" -&amp;gt; null
      - ipv4_address         = "104.248.197.79" -&amp;gt; null
      - ipv4_address_private = "10.110.0.2" -&amp;gt; null
      - ipv6                 = false -&amp;gt; null
      - locked               = false -&amp;gt; null
      - memory               = 1024 -&amp;gt; null
      - monitoring           = false -&amp;gt; null
      - name                 = "web-1" -&amp;gt; null
      - price_hourly         = 0.00744 -&amp;gt; null
      - price_monthly        = 5 -&amp;gt; null
      - private_networking   = true -&amp;gt; null
      - region               = "ams3" -&amp;gt; null
      - resize_disk          = true -&amp;gt; null
      - size                 = "s-1vcpu-1gb" -&amp;gt; null
      - status               = "active" -&amp;gt; null
      - urn                  = "do:droplet:232254786" -&amp;gt; null
      - vcpus                = 1 -&amp;gt; null
      - volume_ids           = [] -&amp;gt; null
      - vpc_uuid             = "b83009d3-8cb0-4545-8123-6f2238e40284" -&amp;gt; null
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Changes to Outputs:
  - droplet_ip = "104.248.197.79" -&amp;gt; null

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que vemos aqui é que vamos destruir todos os nossos recursos, que no caso é apenas um droplet. Você pode digitar &lt;code&gt;yes&lt;/code&gt; no comando acima ou utilizar o &lt;code&gt;-auto-approve&lt;/code&gt; junto com o destroy para destruir todos os recursos sem nem olhar pro &lt;code&gt;plan -destroy&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform destroy -auto-approve
digitalocean_droplet.web: Destroying... [id=232247846]
digitalocean_droplet.web: Still destroying... [id=232247846, 10s elapsed]
digitalocean_droplet.web: Still destroying... [id=232247846, 20s elapsed]
digitalocean_droplet.web: Destruction complete after 22s

Destroy complete! Resources: 1 destroyed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beleza, agora você pode descansar em paz que seu bônus/dinheiro não está sendo mais consumido. Lembre-se sempre de destruir os recursos da sua conta pra garantir que não tenha surpresa no fim do mês. Importante também é criar um alerta lá na digitalocean, eu recomendo criar um valor de 5$ que é o custo de um droplet, se passar disso provavelmente algo está errado. &lt;/p&gt;

&lt;h2&gt;
  
  
  Arquivo de Variaveis
&lt;/h2&gt;

&lt;p&gt;Uma coisa comum de se ver são códigos que utilizam uma variável da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; variable "do_token" {
  description = "Uma descricao bacana!"
  type        = string
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ou seja, nao possuem um valor padrão para a variável, acontece que dependendo da quantidade de variáveis que existem nesse formato, pode ser bem chato de ficar colocando uma a uma. &lt;/p&gt;

&lt;p&gt;Uma solução, bem gambiarra, que eu já fiz muito é colocar um valor &lt;code&gt;default&lt;/code&gt; para cada uma dessas variáveis e garantir que não iria adicionar as alterações desse arquivo no repositório git. O que normalmente acabava acontecendo depois de um tempo. Acontece que o &lt;code&gt;terraform&lt;/code&gt; te dá a possibilidade de usar um arquivo só para adicionar esse valores. Basta criarmos um arquivo &lt;code&gt;qualquer_coisa.tfvars&lt;/code&gt;. Normalmente as pessoas utilizam &lt;code&gt;terraform.tfvars&lt;/code&gt; ou então &lt;code&gt;nome_do_ambiente.tfvars&lt;/code&gt;. Vamos criar o nosso como &lt;code&gt;terraform.tfvars&lt;/code&gt; mesmo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; do_token = "b783123asd294f002c5ea9af1231298327903284kmmsadoiu48d02707a2018588d"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse é o formato do arquivo de variáveis, caso exista um valor padrão e você queira sobrescrever ele, pode colocar o novo valor nesse arquivo e vai funcionar também. Agora precisamos dizer para o &lt;code&gt;terraform&lt;/code&gt; que ele deve buscar os valores das variáveis primeiro nesse arquivo, para isso vamos executar o &lt;code&gt;apply&lt;/code&gt; novamente passando o &lt;code&gt;-var-file&lt;/code&gt; como parâmetro. Esse &lt;code&gt;-varfile&lt;/code&gt; vale para o &lt;code&gt;plan&lt;/code&gt; e o &lt;code&gt;destroy&lt;/code&gt; também.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform apply -var-file terraform.tfvars

An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:
  # digitalocean_droplet.web will be created
  + resource "digitalocean_droplet" "web" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + id                   = (known after apply)
      + image                = "ubuntu-20-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "web-1"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "ams3"
      + resize_disk          = true
      + size                 = "s-1vcpu-1gb"
      + status               = (known after apply)
      + urn                  = (known after apply)
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }
Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + droplet_ip = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

digitalocean_droplet.web: Creating...
digitalocean_droplet.web: Still creating... [10s elapsed]
digitalocean_droplet.web: Still creating... [20s elapsed]
digitalocean_droplet.web: Still creating... [30s elapsed]
digitalocean_droplet.web: Creation complete after 34s [id=232397944]

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

Outputs:

droplet_ip = "206.189.0.61"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>terraform</category>
      <category>hashicorp</category>
      <category>curso</category>
    </item>
    <item>
      <title>Terraform INIT + PLAN</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Sun, 21 Mar 2021 12:51:32 +0000</pubDate>
      <link>https://dev.to/igordcsouzaaa/terraform-init-plan-4k50</link>
      <guid>https://dev.to/igordcsouzaaa/terraform-init-plan-4k50</guid>
      <description>&lt;h1&gt;
  
  
  Curso Completo Gratis!
&lt;/h1&gt;

&lt;p&gt;Esse post faz parte de um curso completo sobre Terraform, caso voce queira saber mais sobre terraform da um pulo no meu &lt;a href="https://igordcsouza.com"&gt;blog&lt;/a&gt; ou no meu &lt;a href="https://www.youtube.com/channel/UC3yoPZJdjwOjrHWy_iEP08A"&gt;youtube&lt;/a&gt; para ter acesso ao curso completo 100% gratuito.&lt;/p&gt;

&lt;h1&gt;
  
  
  Mas se quiser contribuir:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.udemy.com/course/terraform-na-pratica/?referralCode=6DAB87D1325C238B4745"&gt;Aqui no Udemy&lt;/a&gt; tem o mesmo curso que esta disponivel 100% gratuito no youtube pra quem quiser e puder contribuir financeiramete :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform Init
&lt;/h2&gt;

&lt;p&gt;Agora que já temos uma noção de como a estrutura de pasta e arquivos funcionam, vamos conhecer os principais comandos do Terraform. O primeiro comando dos nossos 4 principais é o terraform init.&lt;/p&gt;

&lt;p&gt;Para entender na prática o que ele faz vamos criar um arquivo chamado &lt;code&gt;main.tf&lt;/code&gt; e adicionar o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider "digitalocean" {}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos falar mais pra frente sobre providers, mas o que você precisa saber nesse momento é que cada provider é como se fosse um dicionário. No nosso caso, estamos baixando um dicionário para ensinar o nosso código a se comunicar com a API do Digital Ocean.&lt;/p&gt;

&lt;p&gt;Para manter um tamanho decente, nosso binário não vem com todos os providers por padrão. Então precisamos baixar o nosso plugin antes de executar qualquer outro comando.&lt;/p&gt;

&lt;p&gt;Para isso que temos o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse comando analisa todo nosso código terraform e encontra todos os &lt;code&gt;dicionários&lt;/code&gt; declarados e faz download do provider para que possamos utilizar os seus recursos.&lt;/p&gt;

&lt;p&gt;Um problema diferença na versão atual, é que agora precisamos especificar exatamente qual o provedor estamos utilizando.&lt;/p&gt;

&lt;p&gt;Abra o terminal e na mesma pasta que criamos o arquivo main.tf execute o comando e verá uma saída parecida com a seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of hashicorp/digitalocean...

Error: Failed to query available provider packages

Could not retrieve the list of available versions for provider
hashicorp/digitalocean: provider registry registry.terraform.io does not have
a provider named registry.terraform.io/hashicorp/digitalocean

If you have just upgraded directly from Terraform v0.12 to Terraform v0.14
then please upgrade to Terraform v0.13 first and follow the upgrade guide for
that release, which might help you address this problem.

Did you intend to use digitalocean/digitalocean? If so, you must specify that
source address in each module which requires that provider. To see which
modules are currently depending on hashicorp/digitalocean, run the following
command:
    terraform providers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para resolver isso vamos criar um arquivo chamado de &lt;code&gt;versions.tf&lt;/code&gt; e vamos adicionar o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; terraform {
    required_version = "&amp;gt;= 0.14, &amp;lt; 0.15"
    required_providers {
        digitalocean = {
            source  = "digitalocean/digitalocean"
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nesse caso estamos deixando explícito para o terraform que quando utilizarmos o provider &lt;code&gt;digitalocean&lt;/code&gt; ele deve olhar o provider que se encontra no registry utilizando o path &lt;code&gt;digitalocean/digitalocean&lt;/code&gt;. Eu não vou colocar uma versão específica do provider pois quero usar sempre a última disponível, mas é uma boa prática especificar uma versão principalmente se você estiver fazendo uso do código em produção. &lt;/p&gt;

&lt;p&gt;Vamos aproveitar pra cadastrar uma versão mínima e máxima do terraform, a princípio as próximas versões não devem ter muitas break changes, mas quando lançarem a 0.15.x eu atualizo esse material!&lt;/p&gt;

&lt;p&gt;Vamos rodar novamente o &lt;code&gt;terraform init&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform init

Initializing the backend...

Initializing provider plugins...
- Finding latest version of digitalocean/digitalocean...
- Installing digitalocean/digitalocean v2.5.1...
- Installed digitalocean/digitalocean v2.5.1 (signed by a HashiCorp partner, key ID F82037E524B9C0E8)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

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.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos ver que a versão do provider baixada foi a “2.5.1” e agora podemos seguir para conhecer os próximos comandos pois nosso código está pronto para ser “compreendido” pelo terraform.&lt;/p&gt;

&lt;p&gt;Um ponto importante aqui e o arquivo &lt;code&gt;.terraform.lock.hcl&lt;/code&gt;, ele se parece com isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.

provider "registry.terraform.io/digitalocean/digitalocean" {
  version = "2.5.1"
  hashes = [
    "h1:k9itTwJzUpMBTYsXYPoEW/fyoDOcteQc4+OMRmFErbc=",
    "zh:057b8fa0f95213e7d856208d456175335fb673cfef14abf41193f0a2d76e1210",
    "zh:0daee13dd46de95ce2550459942c1433290798bfb5faac12781f81799dd6b05c",
    "zh:13778c00db5c43b2ed5781e2de32d73f34b391c865a52ad3380714bf86251785",
    "zh:2b2bbb1b057c8bf15804a9fd47c30f30b39bcd7ed478bfcad11e221c654f5d02",
    "zh:43284d2b1a356f541723a46219812590d24742558ef4111eda545212fd60f011",
    "zh:6a6e13b55f9aa889e3162d75cb3e585116e8a0d12084629af38f68cdac6aa777",
    "zh:6fa3dbbad99a075768e9449fc6082769da1b76ae31a8e296ae50899835e859a1",
    "zh:79336598d190f511cf3d3323b49081474669d0daa9c1c0d3b21475110ad97bd9",
    "zh:84c4c8d29820229bd94f7d3c5310f1f7208b97e7d4efca2c8e24ae0c0e032267",
    "zh:86926853140d9072986d2cb8ff4693784abd5f5d241b8cec402dfad77d8060ed",
    "zh:95a896f51656b51519b10edf38f11eb766de60297b8551dc0d14a4041dd16d6f",
    "zh:d163da24466cd60eed4749fef56c6593cc6e33be2e210e1b57edfd1c968aa742",
    "zh:e830649afac9e505603002f8a76b2441a0a41c96c6516609e2c07ce0c45f9dc3",
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse arquivo é mantido pelo próprio comando &lt;code&gt;init&lt;/code&gt; e deve ser adicionado ao seu repositório. Isso ajuda a manter a versão da mesma forma que você faria setando uma versão direto no arquivo &lt;code&gt;versions.tf&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Caso você queira atualizar a versão de um provider onde existe esse arquivo, basta executar o comando &lt;code&gt;terraform init -upgrade=true&lt;/code&gt;, ele vai baixar a última versão disponível do provider sempre respeitando qualquer restrição que você tenha adicionado. Caso você tenha mantido como o meu, vai sempre ter a versão mais nova e consequentemente mais instável.&lt;/p&gt;

&lt;h2&gt;
  
  
  Terraform plan
&lt;/h2&gt;

&lt;p&gt;Agora que já rodamos o init e fizemos download da biblioteca da DigitalOcean, vamos fazer uso dos recursos disponíveis para entender melhor como o comando plan funciona. A primeira coisa que iremos fazer é abrir a documentação do terraform na parte que se refere a biblioteca da DigitalOcean (&lt;a href="https://www.terraform.io/docs/providers/do/index.html"&gt;https://www.terraform.io/docs/providers/do/index.html&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Se você prestar atenção vai ver que existem basicamente 3 itens no menu lateral:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;DigitalOcean Provider: Aqui você encontra uma explicação de como configurar corretamente o provider no seu código. Ele explica coisas como quais variáveis ele busca por padrão no seu ambiente e quais parâmetros são aceitos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Data Sources: Não é incomum precisar de algum recurso que foi criado em outro código terraform ou mesmo de forma manual, e são nesses momentos que o Data Source pode nos ajudar. Com ele podemos pegar alguns valores de recursos já criados para utilizar no nosso código. Vamos entender mais pra frente com detalhes. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resources: Todos os itens dentro desse menu se referem a como criar e gerenciar recursos diretamente pelo terraform. Ou seja, se queremos criar um droplet e aqui dentro que vamos buscar.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nesse momento já configuramos o nosso provider, então vamos criar um droplet usando o recurso para isso. Uma dica: apesar da navegação na documentação ser bem simples as vezes é mais rápido buscar no google por “terraform + versão + recurso”. No nosso caso seria: “terraform 0.14 droplet”.&lt;/p&gt;

&lt;p&gt;Agora que já encontramos a página vamos copiar exatamente o exemplo disponível na página e colar logo abaixo do nosso provider la no arquivo &lt;code&gt;main.tf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "digitalocean_droplet" "web" {
  image  = "ubuntu-20-04-x64"
  name   = "web-1"
  region = "nyc2"
  size   = "s-1vcpu-1gb"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Salve o arquivo e volte para o terminal, nele vamos executar o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform plan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A saída desse comando deve ser algo mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform plan

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.web will be created
  + resource "digitalocean_droplet" "web" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + id                   = (known after apply)
      + image                = "ubuntu-20-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "web-1"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "nyc2"
      + resize_disk          = true
      + size                 = "s-1vcpu-1gb"
      + status               = (known after apply)
      + urn                  = (known after apply)
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;terraform plan&lt;/code&gt; nunca vai alterar o seu arquivo de estado esteja ele local ou remoto. Mas o que é arquivo de estado? Temos um capítulo inteiro para falar sobre isso, mas por hora entenda que o arquivo de estado é o local onde o terraform armazena toda informação sobre sua infraestrutura. Quando a gente pede pra ele planejar a execução ele usa esse arquivo de estado apenas para comparar o que deveria ser criado com o que ja foi criado. Mas e se eu perder o arquivo? Como eu faço pra usar esse arquivo em time? Calma pequeno gafanhoto, vamos falar sobre isso mais pra frente!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  # digitalocean_droplet.web will be created
  + resource "digitalocean_droplet" "web" {
      + backups              = false
      + created_at           = (known after apply)
      + disk                 = (known after apply)
      + id                   = (known after apply)
      + image                = "ubuntu-20-04-x64"
      + ipv4_address         = (known after apply)
      + ipv4_address_private = (known after apply)
      + ipv6                 = false
      + ipv6_address         = (known after apply)
      + locked               = (known after apply)
      + memory               = (known after apply)
      + monitoring           = false
      + name                 = "web-1"
      + price_hourly         = (known after apply)
      + price_monthly        = (known after apply)
      + private_networking   = (known after apply)
      + region               = "nyc2"
      + resize_disk          = true
      + size                 = "s-1vcpu-1gb"
      + status               = (known after apply)
      + urn                  = (known after apply)
      + vcpus                = (known after apply)
      + volume_ids           = (known after apply)
      + vpc_uuid             = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui conseguimos ver exatamente tudo que o terraform irá criar para nós com um símbolo de + do lado. Alguns valores do droplet foram pré fixados, como por exemplo a região (region) que já mostra o valor de nyc2, alguns outros valores apenas serão recebidos após a criação do droplet, como é o caso do preço por hora (price_hourly).&lt;/p&gt;

&lt;p&gt;Existem duas variações importantes no &lt;code&gt;plan&lt;/code&gt; que precisamos entender: &lt;br&gt;
a primeira é o que o terraform chama de update in-place , que basicamente é atualizar um valor de um parâmetro sem afetar o recurso a nível de precisarmos recriar o mesmo. Esse tipo de variação é apresentada da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # digitalocean_droplet.web will be updated in-place
  ~ resource "digitalocean_droplet" "web" {
        backups            = false
        created_at         = "2020-04-10T13:38:03Z"
        disk               = 25
        id                 = "188070139"
        image              = "ubuntu-18-04-x64"
        ipv4_address       = "167.172.25.191"
        ipv6               = false
        locked             = false
        memory             = 1024
        monitoring         = false
      ~ name               = "web-1" -&amp;gt; "web-2"
        price_hourly       = 0.00744
        price_monthly      = 5
        private_networking = false
        region             = "nyc3"
        resize_disk        = true
        size               = "s-1vcpu-1gb"
        status             = "active"
        tags               = []
        urn                = "do:droplet:188070139"
        vcpus              = 1
        volume_ids         = []
    }

Plan: 0 to add, 1 to change, 0 to destroy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enquanto alguns parâmetros podem ser atualizados, alguns precisam que os recursos sejam recriados para que a alteração tenha efeito. No nosso caso poderíamos testar isso modificando a região do nosso droplet.&lt;br&gt;
A saída seria mais ou menos assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # digitalocean_droplet.web must be replaced
-/+ resource "digitalocean_droplet" "web" {
        backups              = false
      ~ created_at           = "2020-04-10T13:38:03Z" -&amp;gt; (known after apply)
      ~ disk                 = 25 -&amp;gt; (known after apply)
      ~ id                   = "188070139" -&amp;gt; (known after apply)
        image                = "ubuntu-18-04-x64"
      ~ ipv4_address         = "167.172.25.191" -&amp;gt; (known after apply)
      + ipv4_address_private = (known after apply)
        ipv6                 = false
      + ipv6_address         = (known after apply)
      + ipv6_address_private = (known after apply)
      ~ locked               = false -&amp;gt; (known after apply)
      ~ memory               = 1024 -&amp;gt; (known after apply)
        monitoring           = false
        name                 = "web-1"
      ~ price_hourly         = 0.00744 -&amp;gt; (known after apply)
      ~ price_monthly        = 5 -&amp;gt; (known after apply)
        private_networking   = false
      ~ region               = "nyc3" -&amp;gt; "nyc1" # forces replacement
        resize_disk          = true
        size                 = "s-1vcpu-1gb"
      ~ status               = "active" -&amp;gt; (known after apply)
      - tags                 = [] -&amp;gt; null
      ~ urn                  = "do:droplet:188070139" -&amp;gt; (known after apply)
      ~ vcpus                = 1 -&amp;gt; (known after apply)
      ~ volume_ids           = [] -&amp;gt; (known after apply)
    }

Plan: 1 to add, 0 to change, 1 to destroy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando essa situação ocorre, podemos ver exatamente qual o parâmetro está forçando uma recriação pois o terraform colocar uma mensagem “# forces replacements” ao lado desse parâmetro, além de colocar uma mensagem de alerta no próprio recurso avisando que “must be replaced”!&lt;/p&gt;

&lt;p&gt;Outro local que podemos ver isso é no fim do comando onde temos um compilado das informações dizendo que destruiremos 1 recurso, criaremos 1 recurso e não alteramos nenhum. Ou seja, no nosso caso vamos destruir o que existe e criar um novo.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>hashicorp</category>
      <category>curso</category>
    </item>
    <item>
      <title>Instalando terraform e criando conta na Digital Ocean</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Sun, 21 Mar 2021 12:48:16 +0000</pubDate>
      <link>https://dev.to/igordcsouzaaa/instalando-terraform-e-criando-conta-na-digital-ocean-3bhj</link>
      <guid>https://dev.to/igordcsouzaaa/instalando-terraform-e-criando-conta-na-digital-ocean-3bhj</guid>
      <description>&lt;h1&gt;
  
  
  Curso Completo Gratis!
&lt;/h1&gt;

&lt;p&gt;Esse post faz parte de um curso completo sobre Terraform, caso voce queira saber mais sobre terraform da um pulo no meu &lt;a href="https://igordcsouza.com"&gt;blog&lt;/a&gt; ou no meu &lt;a href="https://www.youtube.com/channel/UC3yoPZJdjwOjrHWy_iEP08A"&gt;youtube&lt;/a&gt; para ter acesso ao curso completo 100% gratuito.&lt;/p&gt;

&lt;h1&gt;
  
  
  Mas se quiser contribuir:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.udemy.com/course/terraform-na-pratica/?referralCode=6DAB87D1325C238B4745"&gt;Aqui no Udemy&lt;/a&gt; tem o mesmo curso que esta disponivel 100% gratuito no youtube pra quem quiser e puder contribuir financeiramete :)&lt;/p&gt;

&lt;h1&gt;
  
  
  Instalação no Linux
&lt;/h1&gt;

&lt;p&gt;Antes de mais nada precisamos instalar o Terraform na nossa máquina, &lt;br&gt;
a versão do linux que eu vou utilizar aqui é o Ubuntu 20.04.&lt;br&gt;
No site do Terraform precisamos baixar o pacote compatível com o nosso &lt;br&gt;
sistema operacional que, no caso, se encontra &lt;br&gt;
&lt;a href="https://releases.hashicorp.com/terraform/0.14.6/terraform_0.14.6_linux_amd64.zip"&gt;nesse link.&lt;/a&gt;&lt;br&gt;
No momento que escrevo a versão mais atual do Terraform é a 0.14.6!&lt;br&gt;
Por padrão o arquivo que baixamos vem no formato .zip e precisamos descompactar esse arquivo.&lt;/p&gt;

&lt;p&gt;Abra o terminal e digite&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/Downloads
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida vamos utilizar o comando unzip para descomprimir o arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;unzip terraform_0.14.6_linux_amd64.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A saída desse comando deve ser algo parecido com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  Downloads unzip terraform_0.14.6_linux_amd64.zip 
Archive:  terraform_0.14.6_linux_amd64.zip
  inflating: terraform 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se olharmos na pasta de Downloads veremos um binário chamado terraform, vamos testar. &lt;br&gt;
Ainda no terminal execute o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  ./terraform --version
Terraform v0.14.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora para evitar de precisarmos sempre passar o endereço completo do arquivo&lt;br&gt;
vamos colocar o arquivo no nosso path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mv terraform /usr/local/bin/terraform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Ubuntu pedirá para digitar a senha de root e por fim vamos testar &lt;br&gt;
novamente sem passar o endereço completo para termos certeza de que está &lt;br&gt;
tudo funcionando corretamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  terraform --version
Terraform v0.14.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Instalação no MacOS
&lt;/h1&gt;

&lt;p&gt;Se você quiser pode seguir o mesmo processo de instalação utilizado no Ubuntu, &lt;br&gt;
o único ponto de atenção é conferir se está baixando a versão para MacOs.&lt;br&gt;
Apesar de ser a única forma oficial mantida pela Hashicorp, o jeito mais recomendado &lt;br&gt;
é utilizar o brew. &lt;br&gt;
Se você tem um Mac e não conhece o comando brew dá uma corridinha lá no site, &lt;br&gt;
&lt;a href="https://brew.sh/index_pt-br"&gt;https://brew.sh/index_pt-br&lt;/a&gt; , que ele vai te ajudar muito a gerenciar os pacotes no mac!&lt;/p&gt;

&lt;p&gt;Para instalar o brew no MacOs basta abrir o terminal e executar um comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora podemos fazer a complicada tarefa de instalar o terraform executando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;brew install terraform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último vamos confirmar a versão instalada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  terraform --version
Terraform v0.14.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Instalação no Windows
&lt;/h1&gt;

&lt;p&gt;Apesar de todos os nossos exemplos serem executados em um sistema linux, caso você queira acompanhar utilizando o sistema operacional Windows precisará instalar o Chocolatey que ,assim como o Brew pro MacOs, funciona como um gerenciador de pacotes para o Windows.&lt;/p&gt;

&lt;p&gt;Acesse o site &lt;a href="https://chocolatey.org/"&gt;https://chocolatey.org/&lt;/a&gt; e siga o passo a passo para instalação e em seguida abra o cmd e digite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;choco install terraform
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para garantir que tudo está funcionando como deveria vamos fazer o seguinte:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform --version
Terraform v0.14.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Terraform com Docker
&lt;/h1&gt;

&lt;p&gt;Agora que já vimos como instalar em cada um dos principais sistemas operacionais, vamos brincar um pouco com o Docker. Caso você não conheça o docker, o que eu recomendo, pode instalar o terraform da forma padrão no seu sistema operacional e pular essa parte.&lt;br&gt;&lt;br&gt;
Sem mais delongas, por que deveríamos utilizar o terraform dentro de um container?&lt;br&gt;
Eu vou te dar um exemplo, enquanto escrevo estamos na versão 0.14.6 do terraform &lt;br&gt;
e na empresa que eu trabalho praticamente todos os nossos módulos ainda rodam na &lt;br&gt;
versão 0.13.x. Eu poderia utilizar algum gerenciador de versão &lt;br&gt;
(falaremos sobre isso mais pra frente), mas caso você goste de fazer backup das suas configs ou&lt;br&gt;
queira alterar inclusive as variáveis que são utilizadas em cada versão, o docker seria a melhor opção. &lt;br&gt;
O  que eu faço é estipular versões específicas para cada empresa, por exemplo:&lt;/p&gt;

&lt;p&gt;A empresa &lt;code&gt;igordcsouza&lt;/code&gt; usa a versão 0.13.x então quando eu rodar o comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform-igordcsouza --version
Terraform v0.13.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E se eu executar o comando que criei seria algo como:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform-tnp --version
Terraform v0.14.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E tudo isso sem precisar me preocupar com que pasta eu estou. &lt;br&gt;
Outro ponto importante são variáveis de ambientes. O Terraform possui algumas &lt;br&gt;
variáveis de ambiente que ele procura para tentar falar com a Digital Ocean, &lt;br&gt;
por exemplo. No meu caso, cada comando possui as variáveis corretas setadas, &lt;br&gt;
então eu não preciso me preocupar de tentar executar um comando do livro e ir &lt;br&gt;
parar na conta de um cliente.&lt;/p&gt;

&lt;p&gt;Vamos testar como isso funciona na prática agora. Caso você não possua o docker &lt;br&gt;
instalado na sua máquina existem várias formas de instalar, da uma olhada no site &lt;br&gt;
mas de forma geral você pode utilizar o comando a seguir no seu terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -fsSL https://get.docker.com | sh;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora podemos seguir e tentar executar o terraform, sim executar sem instalar nada mais. &lt;br&gt;
Basta passar o seguinte comando após ter instalado o docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run hashicorp/terraform:latest --version
Unable to find image 'hashicorp/terraform:latest' locally
latest: Pulling from hashicorp/terraform
c9b1b535fdd9: Pull complete 
011000b168e5: Pull complete 
4c096b23c4a8: Pull complete 
Digest: sha256:53fb1c0a78c8bb91c4a855c1b352ea7928f6fa65f8080dc7a845e240dd2a9bee
Status: Downloaded newer image for hashicorp/terraform:latest
Terraform v0.14.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ainda precisamos ajustar algumas coisas nesse comando para ele ficar utilizável, mas já temos o terraform “instalado” local. &lt;br&gt;
.Vamos adicionar os seguintes comandos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;--rm&lt;/li&gt;
&lt;li&gt;-v $(pwd):app&lt;/li&gt;
&lt;li&gt;-w /app/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;O comando final deve ficar da seguinte forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run --rm -it -v $(pwd):/app/ -w /app/ hashicorp/terraform:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para entender melhor cada um dos parâmetros dê uma olhada na documentação oficial do Docker.&lt;br&gt;
A última coisa que precisamos fazer para utilizar o terraform dentro do container é criar um atalho para esse comando. Seria muito complicado ficar digitando ele inteiro toda hora.&lt;br&gt;
Caso você esteja utilizando o terminal padrão, abra o arquivo com o seu editor preferido, normalmente o caminho é ~/.bashrc, e adicione o seguinte no fim do arquivo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alias terraform='docker run --rm -it -v $(pwd):/app/ -w /app/ hashicorp/terraform:latest'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em seguida recarregue o arquivo reiniciando o terminal ou executando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora podemos utilizar o comando sem maiores problemas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform --version
Unable to find image 'hashicorp/terraform:latest' locally
light: Pulling from hashicorp/terraform
Digest: sha256:53fb1c0a78c8bb91c4a855c1b352ea7928f6fa65f8080dc7a845e240dd2a9bee
Status: Downloaded newer image for hashicorp/terraform:light
Terraform v0.14.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora se você precisar rodar uma versão diferente do terraform basta trocar o nome do alias por algo similar a terraform-tnp e trocar a versão do container de latest para a desejada e pronto!&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando nossa conta na Digital Ocean
&lt;/h2&gt;

&lt;p&gt;Para aprendermos um pouco sobre o Terraform precisamos criar uma conta em algum provedor para executar nossos testes. A DigitalOcean tem um programa de referência que no momento está dando 100$ para cada pessoa que se inscrever pelo link: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://m.do.co/c/ee28782de1c9"&gt;https://m.do.co/c/ee28782de1c9&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para criar uma conta é só seguir o passo a passo no site. Eu recomendo utilizar a integração com o Google ou Github. Mesmo com todo esse crédito, a Digital Ocean exige que você cadastre uma forma de pagamento. Ela pode ser um cartão de crédito ou uma conta no paypal. Com a conta criada, vamos procurar pelo item “API” no menu, provavelmente no canto esquerdo.&lt;br&gt;
A primeira coisa que precisamos fazer nessa tela é gerar um novo token. Coloque um nome pra esse token, clique em salvar. Agora salve esse valor em algum local de fácil acesso pois precisaremos dela mais pra frente.&lt;br&gt;
O próximo passo é cadastrar nossa chave pública na nossa conta para que possamos acessar as máquinas via ssh. Clique na sua fotinha no canto superior direito e no menu clique em Account &amp;gt; Security &amp;gt; Add SSH Key.&lt;/p&gt;

&lt;p&gt;Volte para o terminal e verifique se você já possui uma chave configurada, o caminho default é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls ~/.ssh 
id_rsa  id_rsa.pub  known_hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso você não tenha nada nessa pasta vamos criar agora:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-keygen -t rsa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E aperte enter para todas as perguntas que serão feitas. Agora se executarmos o mesmo comando você deverá ver dois arquivos &lt;code&gt;id_rsa&lt;/code&gt; e &lt;code&gt;id_rsa.pub&lt;/code&gt;.&lt;br&gt;
Queremos o valor do id_rsa.pub para isso vamos executar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat ~/.ssh/id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copie a saída do comando e coloque lá na página do digitalocean. Dê um nome que tenha algum significado para essa chave, principalmente se você tiver mais de um notebook. Essa boa prática vai ter ajudar caso precise remover alguma chave por qualquer motivo. &lt;br&gt;
Clique em Add SSH Key, copie o valor do Fingerprint e salve junto com o token que criamos anteriormente.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>hashicorp</category>
      <category>digitalocean</category>
    </item>
    <item>
      <title>Introdução ao protocolo de Consenso (RAFT) no HashiCorp Consul</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Mon, 08 Feb 2021 13:38:10 +0000</pubDate>
      <link>https://dev.to/igordcsouzaaa/introducao-ao-protocolo-de-consenso-raft-no-hashicorp-consul-3b6h</link>
      <guid>https://dev.to/igordcsouzaaa/introducao-ao-protocolo-de-consenso-raft-no-hashicorp-consul-3b6h</guid>
      <description>&lt;h2&gt;
  
  
  O que é o RAFT?
&lt;/h2&gt;

&lt;p&gt;O RAFT faz parte de uma categoria de algoritmos chamados de Consensus Algorithm (Algoritmos de Consenso). Vamos entender o que são esses algoritmos antes de nos aprofundarmos no RAFT propriamente dito. &lt;/p&gt;

&lt;h2&gt;
  
  
  O que e um algoritmo de consensus?
&lt;/h2&gt;

&lt;p&gt;Consenso é problema fundamental para tolerância a falhas em sistemas distribuídos. Basicamente o problema em questão consiste em múltiplos servidores concordando (entrando em consenso). Um algoritmo de consenso típico funciona quando a maioria dos servidores se encontra disponível. Por exemplo, um cluster de 5 servidores consegue funcionar normalmente mesmo se dois dos seus servidores pararem de funcionar, isso acontece por que se mantem a maioria dos servidores funcionando. Ainda que mais servidores venham a falhar, por exemplo se 4 dos nossos 5 servidores falharem, ainda assim o servidor que sobrou sempre retornara resultados corretos, apesar de não conseguir mais avançar com novos valores. &lt;/p&gt;

&lt;p&gt;Esses algoritmos normalmente são utilizados no contexto de replicar maquinas de estado. Se voce fez faculdade alguma faculdade na area de computação muito provavelmente ouviu falar um pouco sobre maquina de estado. No caso, cada servidor possui uma maquina de estado e um log. A maquina de estado e o componente que queremos que seja tolerante a falhas, como por exemplo uma tabela de hashes. Para os servidores clientes vai parecer que eles estão se comunicando apenas com uma única maquina de estado, mesmo que a minoria dos servidores rodando os agentes em modo server falhem. &lt;/p&gt;

&lt;p&gt;Cada maquina de estado recebe como entrada um comando que vem do seu log. No exemplo usando uma tabela de hashes, o log poderia incluir comandos como por exemplo x é igual a 3. O algoritmo de consenso e utilizado para concordar, e de certa forma garantir, nos comandos que estão nos logs dos servidores. O que o algoritmo deve fazer nesses casos e garantir que se qualquer uma das maquinas de estado, os nossos agentes rodando em modo server, adicionar um comando “x = 3” como o comando na posição 10 do log, por exemplo, nenhum outro servidor poderá adicionar um comando diferente na posição 10.  O resultado disso e que cada maquina de estado tem os mesmos comandos na mesma ordem produzindo assim os mesmos resultados e chegando no mesmo estado.&lt;/p&gt;

&lt;p&gt;O RAFT e um algoritmo que foi projetado para ser simples de entender. Ele é equivalente a um outro protocolo muito conhecido chamado Paxos, tanto em tolerância a falhas quanto em performance. O RAFT separou os principais elementos do protocolo como eleição de um líder, replicação e logs, segurança e com isso foi possível reduzir o numero de estados que devem ser considerados. &lt;/p&gt;

&lt;p&gt;Como dito anteriormente, o RAFT e bem parecido com outros, vamos dar uma olhada em tres coisas que ele se destaca um pouco alem dos outros:&lt;br&gt;
&lt;strong&gt;- Simplicidade:&lt;/strong&gt; Primeiro vamos deixar claro ser mais simples que os outros algoritmos não torna ele trivial, e tudo bem se voce nao entender ele por completo. Mas existem estudos que comprovam que aprender o RAFT e bem mais simples do que Paxos. E sua implementação, que infelizmente não vamos tratar aqui, também e bem mais simples.&lt;br&gt;
&lt;strong&gt;- Leader mais forte:&lt;/strong&gt; RAFT usa uma forma de liderança diferente dos outros algoritmos. Por exemplo, entradas no log só são possíveis no líder e o fluxo segue do líder para os outros servidores. Isso simplifica bastante a gestão da replicação de logs.&lt;br&gt;
&lt;strong&gt;- Eleição do Líder:&lt;/strong&gt; A eleição e feita utilizando um cronômetro randômico. Isso adiciona um mecanismo simples ao heartbeat que e uma funcionalidade utilizada por qualquer algoritmo de consenso, enquanto resolve os conflitos durante a eleição de forma simples e rápida.&lt;br&gt;
&lt;strong&gt;- Mudança nos Membros:&lt;/strong&gt; Para mudar os membros de um cluster, o algoritmo utiliza um novo método de junção, onde a maioria entre duas configurações se sobrepõem. Isso permite que o cluster continue operando normalmente durante mudanças de configurações.&lt;/p&gt;

&lt;p&gt;Antes de prosseguirmos para entender como o Consul faz uso desse protocolo, temos alguns termos que precisamos ter em mente.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Log:&lt;/strong&gt; É o principal unidade de trabalho no sistema RAFT. O problema de consistência pode ser dividido em logs replicados. Como logs, entenda uma sequencia de entradas ordenadas por chegada. Essas entradas podem ser qualquer alteração no cluster. Consideramos que o log esta consistente se todos os membros concordam com as entradas e sua ordem.&lt;br&gt;
&lt;strong&gt;- FSM (Maquina de estado finita):&lt;/strong&gt; Uma FSM é uma coleção de estados que podem ser alterados entre eles. Quando novos logs são recebidos as maquinas de estado podem alterar seus estados. Vale ressaltar que a aplicação da mesma sequencia de logs deve sempre resultar no mesmo estado. Ou seja, o comportamento deve ser determinístico. &lt;br&gt;
&lt;strong&gt;- Peer set (Conjunto de Pares):&lt;/strong&gt; Chamamos de conjunto de pares o conjunto de todos os membros participando na replicação de logs. Se referindo a como o Consul trata o conjunto de pares, estamos falando apenas dos servidores que possuem agentes rodando em modo server. &lt;br&gt;
&lt;strong&gt;- Quórum:&lt;/strong&gt; Chamamos de quorum a maioria dos membros de um conjunto de pares. Imaginando um conjunto de 10 servidores, o nosso quorum seriam 6 servidores. A conta e feita no formato de (10/2)+1 ou de forma mais genérica (N/2)+1.&lt;br&gt;
&lt;strong&gt;- Committed Entry (Entrada Comprometida):&lt;/strong&gt; Uma entrada ou registro e considerada committed quando e armazenada em um quorum. Por exemplo, no caso onde temos 10 servidores assim que 6 deles tiverem a mesma entrada podemos dizer que ela e uma entrada comprometida. Essa tradução parece não ser das melhores mas pense em comprometida como alguém que esta comprometida a fazer algo. Como voce provavelmente se comprometeu a aprender mais sobre Consul por algum motivo :)&lt;br&gt;
&lt;strong&gt;- Líder:&lt;/strong&gt; Provavelmente o mais fácil de se entender, esse e o servidor Líder. Apenas um servidor pode ser o Líder por vez. O Líder é responsável por receber as entradas nos logs, replicar para os outros servidores do cluster e gerenciar quando uma entrada é considerada como comprometida.&lt;/p&gt;

&lt;p&gt;Todos os agentes em modo server sempre estão em um dos seguintes estados: Follower (Seguidor), Candidate (Candidato) ou Líder.&lt;br&gt;
Os servidores iniciam em modo seguidor. Nesse modo eles aceitam entradas de log vindo de um líder e tem direito de votar. Se nenhuma entrada for recebida durante algum tempo esses servidores podem se auto-promover para o estado de candidato. Nesse estado os servidores solicitam uma votação dos seus pares, se um candidato receber voto do quorum, então ele será promovido a líder. Como líder ele deve aceitar novos registros de log e replicar esses registros para os seguidores. &lt;/p&gt;

&lt;p&gt;Quando o líder recebe um novo registro, ele armazena em um local durável e tenta replicar para o quorum de seguidores. Lembra que falamos sobre uma configuração com quorum tomar o lugar da configuração anterior do cluster?  &lt;br&gt;
Quando esse log e considerado como comprometido ele pode ser convertido para uma maquina de estado finita. Esses estados finitos são específicos de aplicação para aplicação, no caso do Consul é utilizado o MemDB para manter o estado do cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raft no Consul
&lt;/h2&gt;

&lt;p&gt;Antes de mais nada, caso não tenha ficado claro anteriormente, precisamos ter em mente que apenas os agentes em modo server participam do protocolo RAFT no cluster. Todos os agentes em modo cliente simplesmente fazem um redirecionamento das requisições para um server. &lt;/p&gt;

&lt;p&gt;Quando iniciamos um Consul cluster utilizando apenas um servidor, precisamos utilizar o método bootstrap que serve para permitir que o servidor se auto eleja líder. Quando um líder é eleito, outros servidores podem ser adicionados como pares para preservar a consistência. Eventualmente, quando mais servidores tiverem sido adicionados podemos desabilitar esse modo e passar a utilizar o modelo padrão do raft.&lt;/p&gt;

&lt;p&gt;Por causa do tipo de replicação do RAFT, a performance e muito dependente da latência de rede. Por essa razão, cada datacenter elege um leader independente e mantem um conjunto de pares diferentes. Os dados são divididos por datacenter, assim cada líder e responsável apenas pelo seu próprio datacenter. Por datacenter entenda um cluster do consul. Podemos ter umas arquitetura multi-cluster que também pode ser chamada de multi-datacenter. &lt;/p&gt;

&lt;h2&gt;
  
  
  Modos de Consistência
&lt;/h2&gt;

&lt;p&gt;Apesar de todas as escritas serem replicadas através do RAFT, leituras podem ser mais flexíveis. O Consul suporta tres diferentes modos de consistência para leitura:&lt;br&gt;
&lt;strong&gt;- default:&lt;/strong&gt; RAFT faz uso de uma especie de alocação de líder, provendo uma janela de tempo onde o líder assume seu papel de forma estável. De toda forma, se o líder for separado dos demais pares um novo líder sera eleito enquanto o antigo continua na sua alocação. Ou seja, por algum tempo teremos 2 servidores no estado de líder. Mas ainda assim não existe um risco de split-brain já que lideres antigos serão incapazes de adicionar novos registros nos logs do cluster. Entretanto, se for requerido uma leitura no líder antigo, os valores fornecidos por ele podem ser potencialmente obsoletos. Esse modo depende apenas nessa alocação do líder, potencialmente expondo seu clientes a receberem valores obsoletos. A decisão de utilizar esse modo se da por que apesar desses possíveis problemas, leituras são normalmente rápidas e normalmente bem consistente. Existe sim a possibilidade do erro, mas a janela desse erro e bem pequena já que assim que o líder for separado dos seus pares ele mesmo deve se afastar desse papel por conta da segregação.&lt;br&gt;
&lt;strong&gt;- consistent:&lt;/strong&gt; Esse modo é extremamente consistente, ele requer que o líder verifique com um quorum de pares se ele ainda e o líder. O que adiciona mais uma chamada entre os servidores, fazendo com que a latência aumente mas em contra-partida aumentando a consistência dos dados. Importante entender dentro do seu cenário qual a melhor opção, no geral o modo default e o mais indicado, mas se pra voce a consistência for extremamente mais importante, vale a pena alterar o modo para consistent e analisar como seu cluster vai performer. Claro, isso se voce tiver um bom monitoramento do seu cluster. Caso você já tenha um cluster em produção e esteja procurando por esse tipo de aprimoramento, mas não tem um monitoramento pronto, fica tranquilo que vamos falar sobre isso mais pra frente.&lt;br&gt;
&lt;strong&gt;- stale:&lt;/strong&gt; A tradução da palavra stale seria velha, mas acho que podemos trabalhar com obsoleto pra fazer um pouco mais de sentido. Esse modo permite que qualquer servidor sirva uma leitura, independente se ele é o líder ou não . Isso quer dizer que leituras podem ser arbitrariamente obsoletas. O lado positivo desse modo e que a leitura é extremamente rápida e a escalabilidade de leituras e muito grande, por outro lado os valores são obsoletos. O que não  necessariamente quer dizer que sejam errados, mas podem ser. &lt;/p&gt;

&lt;p&gt;Se quiser saber mais sobre o protocolo esse documento explica em detalhes como ele funciona. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.usenix.org/system/files/conference/atc14/atc14-paper-ongaro.pdf"&gt;https://www.usenix.org/system/files/conference/atc14/atc14-paper-ongaro.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://raft.github.io"&gt;https://raft.github.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.consul.io/docs/architecture/consensus"&gt;https://www.consul.io/docs/architecture/consensus&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hashicorp</category>
      <category>consenso</category>
      <category>consul</category>
      <category>raft</category>
    </item>
    <item>
      <title>Scraping data with Selenium + Python</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Tue, 03 Nov 2020 03:00:00 +0000</pubDate>
      <link>https://dev.to/igordcsouzaaa/scraping-data-with-selenium-python-513i</link>
      <guid>https://dev.to/igordcsouzaaa/scraping-data-with-selenium-python-513i</guid>
      <description>&lt;p&gt;“Why I need to scrap data?” This is probably the first thing you had asked yourself when you saw that title, right? So I can give you at least two good motives: Collect data that is not available in a JSON/CSV format. Test our application. In this post, I’ll only...&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Minha caixa de ferramentas no inicio de 2020</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Thu, 16 Apr 2020 03:00:00 +0000</pubDate>
      <link>https://dev.to/igordcsouzaaa/minha-caixa-de-ferramentas-no-inicio-de-2020-cbi</link>
      <guid>https://dev.to/igordcsouzaaa/minha-caixa-de-ferramentas-no-inicio-de-2020-cbi</guid>
      <description>&lt;p&gt;Ta rolando uma thread no Twitter sobre isso e o Guto Carvalho fez um post que eu achei bem legal e resolvi copiar para acompanhar ao longo dos anos. Notebook Pessoal/Trabalho (DUAL BOOT) Ubuntu 18.04 Google Chrome 1Password ToDoIst Grammarly Notifier for Github VSCode Slack Dracula Theme OBS Audacity oh-my-zsh...&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Criando Review Apps com Github Action, Terraform e DigitalOcean!</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Fri, 15 Nov 2019 14:38:09 +0000</pubDate>
      <link>https://dev.to/igordcsouza_87/criando-review-apps-com-github-action-terraform-e-digitalocean-1n20</link>
      <guid>https://dev.to/igordcsouza_87/criando-review-apps-com-github-action-terraform-e-digitalocean-1n20</guid>
      <description>&lt;p&gt;Antes de mais nada... por que &lt;a href="https://docs.gitlab.com/ee/ci/review_apps/" rel="noopener noreferrer"&gt;Review Apps&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Um problema bem comum seja numa arquitetura de microservices, microlitos ou monolitos é que dependendo do tamanho do seu time podem existir diversas features sendo desenvolvidas de forma simultâneas e algumas vezes até com break changes. Um caso atual nosso e a migracao de uma app para a nova versao do ruby. &lt;/p&gt;

&lt;p&gt;No meu caso, existem 3 principais motivações para utilizar o RA(Review Apps).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validar que o código terraform está 100% funcional recriando ambiente necessário para a aplicação funcionar.&lt;/li&gt;
&lt;li&gt;Validar novas features junto ao PO antes de mandar pro ambiente de staging onde alguns clientes podem acessar.&lt;/li&gt;
&lt;li&gt;Dar ao time um ambiente seguro para testar não só mudanças em código mas mudanças que afetem banco de dados sem medo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos por partes!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Github Action&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nesse caso a escolha do &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Action&lt;/a&gt; foi completamente baseada em Hype eu estava querendo a oportunidade de brincar com as actions a algum tempo e pareceu uma boa hora, mas você pode utilizar qualquer plataforma de CI/CD, basta seguir a mesma linha de raciocínio e adaptar algumas linhas de código. 🙂&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Caso você não conheça o Terraform eu escrevi um texto sobre o &lt;a href="https://medium.com/@igordcsouza/terraform-uma-pequena-introdu%C3%A7%C3%A3o-eae86f22db55" rel="noopener noreferrer"&gt;básico do terraform&lt;/a&gt;, mas a ideia dele e codificar toda infra numa linguagem própria chamada HCL para que possamos criar e recriar a infraestrutura sempre que quisermos e também manter um histórico da sua evolução. Basicamente, tentar manter infra da forma que mantemos software!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DigitalOcean&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Apesar de ter um certificado do GCP e trabalhar no dia a dia com AWS, sempre que preciso fazer prova de conceitos ou sugerir uma cloud para clientes que não dependem de tantos servicos eu acabo sempre indicando a DigitalOcean não só pela facilidade em começar e manter uma infraestrutura, também pela facilidade em prever custos e pela sua API que é muito boa.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Vamos ao que interessa!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A primeira coisa a se fazer e criar um workflow, caso você não esteja vendo esse botão nos seus repositórios, pelo menos enquanto escrevo esse texto, você precisa aceitar fazer parte da &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;versão beta&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FNCf0Thw%2Fpost-01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FNCf0Thw%2Fpost-01.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando clicar em actions, você vai ver uma opção como &lt;code&gt;Set up a workflow yourself&lt;/code&gt;, que basicamente e para não utilizarmos um template e montarmos tudo com nossos próprios dedos.&lt;/p&gt;

&lt;p&gt;Vamos fazer isso 🙂 &lt;/p&gt;

&lt;p&gt;Voce deve cair em uma pagina parecida com essa:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQYFVfb3%2Fpost-02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FQYFVfb3%2Fpost-02.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se pra você nem todos os nomes forem explicativos como não foram pra mim ou quiser saber mais detalhes sobre os parametos aceitos por cada comando segue o link para o &lt;a href="https://help.github.com/en/actions/automating-your-workflow-with-github-actions" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, mas durante o texto voce vai entender os principais.&lt;/p&gt;

&lt;p&gt;Como nossa ideia é criar RA baseados apenas em pull requests abertos, vamos alterar a linha 3 para que esse workflow seja executado apenas em PR.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Review Apps
on:
  pull_request:
    types: [assigned, opened, synchronize, reopened, closed]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: Run a one-line script
      run: echo Hello, world!
    - name: Run a multi-line script
      run: |
        echo Add other actions to build,
        echo test, and deploy your project.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dessa forma abrangemos a maior parte dos eventos disponíveis no pull_request, ou seja sempre que alguém abrir o PR, commitar uma nova mudança ou mesmo fizer merge esse pipeline será executado. &lt;br&gt;
Tudo bem que ele ainda não faz muito além de fazer checkout do código.&lt;/p&gt;

&lt;p&gt;Como planejamos utilizar o terraform para isso, um pre requisito e ter o codigo terraform pronto para fazer deploy do ambiente.&lt;br&gt;
Nesse texto temos um exemplo bem simples com um código para criar um Droplet na DigitalOcean com o nome da maquina sendo o mesmo nome do workspace do terraform.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider "digitalocean" {}

provider "aws" {
  version = "~&amp;gt; 2.0"
  region  = "us-east-1"
}

terraform {
  backend "s3" {
    bucket = "icf-tf states-terraform"
    key    = "terratest/terraformt.tfstate"
    region = "us-east-1"
  }
}

resource "digitalocean_droplet" "web" {
  image  = "ubuntu-18-04-x64"
  name   = "${terraform.workspace}"
  region = "nyc3"
  size   = "s-1vcpu-1gb"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alguns pontos bem importantes aqui:&lt;/p&gt;

&lt;p&gt;O primeiro são as variaveis necessarias, no caso estamos usando 2 providers diferentes &lt;code&gt;DigitalOcean&lt;/code&gt; e &lt;code&gt;AWS&lt;/code&gt; e cada um precisa de variáveis diferentes para funcionar.&lt;br&gt;
Segundo e o fato de precisarmos utilizar um arquivo de estado remoto caso contrário perderíamos o nosso arquivo de estado após a primeira execução e se vc nao sabe o que e arquivo de estado e a sua importante e pq nao leu esse &lt;a href="https://medium.com/@igordcsouza/terraform-uma-pequena-introdu%C3%A7%C3%A3o-eae86f22db55" rel="noopener noreferrer"&gt;post&lt;/a&gt; então corre lá... eu espero pra continuar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/o5oLImoQgGsKY/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/o5oLImoQgGsKY/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Por último mas não menos importante e que o nome da máquina está utilizando uma variável do terraform que é o nome do workspace. O workspace padrao tem nome de &lt;code&gt;default&lt;/code&gt; mas vamos alterar esse nome durante a execução então segura aí!&lt;/p&gt;

&lt;p&gt;A primeira coisa a se fazer com o código terraform e executar um &lt;code&gt;terraform init&lt;/code&gt; então vamos adicionar esse passo no nosso workflow utilizando a &lt;a href="https://github.com/hashicorp/terraform-github-actions" rel="noopener noreferrer"&gt;action do terraform&lt;/a&gt; que se encontra no repositório criado e mantido pela própria &lt;a href="https://www.hashicorp.com/" rel="noopener noreferrer"&gt;Hashicorp&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Terraform Workflow
on:
  pull_request:
    types: [assigned, opened, synchronize, reopened, closed]
jobs:
  greeting:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: 'Terraform Init'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'init'
        tf_actions_working_dir: '.'
        tf_actions_comment: false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você tentou executar provavelmente tomou um erro, e pro bem dos seus conhecimentos em Terraform te recomendo entender o erro antes de continuar. Mas caso você queira seguir adiante, o problema e a falta de variáveis para comunicação com a AWS. &lt;br&gt;
Lembra que estamos utilizando arquivo remoto hospedado no S3? Então, pra que possamos ler esse arquivo precisamos de credenciais da AWS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Terraform Workflow
on:
  pull_request:
    types: [assigned, opened, synchronize, reopened, closed]
jobs:
  greeting:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: 'Terraform Init'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'init'
        tf_actions_working_dir: '.'
        tf_actions_comment: false
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora para o nosso pipeline funcionar precisamos cadastrar de alguma forma essas variáveis. Para isso você precisa ter acesso ao settings do seu repositório.&lt;/p&gt;

&lt;p&gt;Cadastrar os valores dessas variáveis e simples, talvez você tenha um pouco mais dificuldade em pegar os valores delas caso nunca tenha precisado fazer isso antes. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configurando Secrets no repositório&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Infelizmente eu não encontrei uma forma de criar essas variáveis para toda a conta, então vamos seguir criando direto no repositório. Mas se você souber como fazer para todos os meus repos seria de grande ajuda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FKLTM4hZ%2Fpost-03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FKLTM4hZ%2Fpost-03.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos aproveitar que estamos com a página aberta para cadastrar outras variáveis que vamos precisar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS_ACCESS_KEY_ID     = Chave fornecida pela AWS para acessar o nosso arquivo de estado 
AWS_SECRET_ACCESS_KEY = Chave fornecida pela AWS para acessar o nosso arquivo de estado
DIGITALOCEAN_TOKEN    = Vamos precisar dessa chave para que o terraform consiga fazer chamadas a API da DigitalOcean para criar recursos.
TOKEN                 = Vamos utilizar para setar uma variável de ambiente chamada BRANCH_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos commitar essas alterações numa branch qualquer e abrir um PR para master.&lt;br&gt;
Agora abra a aba de &lt;code&gt;Actions&lt;/code&gt; e o pipeline deve começar a qualquer segundo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FN19Bmy1%2Fpost-04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FN19Bmy1%2Fpost-04.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tudo certinho? Se nao, da uma olhada nas suas chaves e tente entender o log do erro.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;DICA IMPORTANTE!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Leiam o log de erro sempre, quase sempre a solução está na mensagem de erro!&lt;/p&gt;

&lt;p&gt;Uma coisa que você pode estar se perguntando e de onde saiu aquele 2 step &lt;code&gt;Build hashicorp/terraform-github-actions@master&lt;/code&gt; se não colocamos nada disso no código.&lt;br&gt;
Acontece que o Github Action faz build de todas as actions cadastradas no pipeline.  Esse é um dos motivos para seu workflow ser extremamente específico e deve evitar ao máximo utilizar as condicionais dentro dos steps mas isso é papo pra um outro texto.&lt;/p&gt;

&lt;p&gt;Agora que já conseguimos inicializar nosso código, vamos executar um &lt;code&gt;terraform plan&lt;/code&gt; para ver se o terraform vai criar o Droplet da forma que esperamos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Review Apps

on:
  pull_request:
    types: [assigned, opened, synchronize, reopened, closed]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: 'Terraform Init'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'init'
        tf_actions_working_dir: '.'
        tf_actions_comment: false
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    - name: 'Terraform Plan'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'plan'
        tf_actions_working_dir: '.'
        tf_actions_comment: true
      env:
        DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vamos olhar a saída do nosso workflow.&lt;/p&gt;

&lt;p&gt;Quero chamar atenção pro nome do droplet &lt;code&gt;default&lt;/code&gt; isso se dá porque falamos pro terraform utilizar o nome do workspace como nome do droplet e o nome do workspace padrão é &lt;code&gt;default&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para criar nossos review apps precisamos que o workspace utilizado tenha o mesmo nome da nossa branch, e é exatamente aqui que o GithubAction deixou um pouco a desejar e o terraform me surpreendeu 🙂 &lt;/p&gt;

&lt;p&gt;O Github tem uma variável &lt;code&gt;GITHUB _REF&lt;/code&gt; que na teoria te retorna a referência do commit, o problema é que quando estamos lidando com pull request essa variavel nao retorna o nome da branch e sim uma referência ao número do pull request aberto.&lt;br&gt;
Pra resolver isso eu criei uma action (&lt;a href="https://github.com/igordcsouza/github-action-get-branch-name" rel="noopener noreferrer"&gt;https://github.com/igordcsouza/github-action-get-branch-name&lt;/a&gt;) baseada nessa aqui (&lt;a href="https://github.com/jessfraz/branch-cleanup-action" rel="noopener noreferrer"&gt;https://github.com/jessfraz/branch-cleanup-action&lt;/a&gt;) para setar uma variavel chamada BRANCH_NAME.&lt;br&gt;
Vamos adicionar ela no nosso código.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Terraform Workflow

on:
  pull_request:
    types: [assigned, opened, synchronize, reopened, closed]

jobs:
  greeting:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: 'Terraform Init'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'init'
        tf_actions_working_dir: '.'
        tf_actions_comment: false
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    - uses: igordcsouza/github-action-get-branch-name@master
      env:
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
    - name: Set branch name as workspace
      run: echo ::set-env name=TF_WORKSPACE::${BRANCH_NAME}
    - name: 'Terraform Plan'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'plan'
        tf_actions_working_dir: '.'
        tf_actions_comment: true
      env:
        DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bom, agora temos uma variável com o nome da branch, mas ainda assim o terraform nao esta pegando esse valor pois a variavel nao esta ligada ao workspace de forma nenhuma. &lt;br&gt;
Aqui entra uma feature do terraform que até começar a fazer esse post eu não fazia ideia da existência dela.&lt;br&gt;
Essa variável e a &lt;code&gt;TF_WORKSPACE&lt;/code&gt; , que caso ela esteja setada com algum valor o terraform tenta utilizar o workspace com o mesmo nome e se ele não existir ele cria o workspace.&lt;br&gt;
Isso é uma MÃO NA RODA caso você esteja precisando criar workspace em tempo de execução de algum pipeline como nesse caso ou mesmo para substituir o &lt;code&gt;terraform workspace select name&lt;/code&gt; no seu Jenkins.&lt;/p&gt;

&lt;p&gt;Vamos setar essa variável com o nome da nossa branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Terraform Workflow

on:
  pull_request:
    types: [assigned, opened, synchronize, reopened, closed]

jobs:
  greeting:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: 'Terraform Init'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'init'
        tf_actions_working_dir: '.'
        tf_actions_comment: false
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    - uses: igordcsouza/github-action-get-branch-name@master
      env:
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
    - name: Set branch name as workspace
      run: echo ::set-env name=TF_WORKSPACE::${BRANCH_NAME}
    - name: 'Terraform Plan'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'plan'
        tf_actions_working_dir: '.'
        tf_actions_comment: true
      env:
        DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora estamos prontos e os passos são idênticos aos que você rodaria manualmente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Terraform Workflow
on:
  pull_request:
    types: [assigned, opened, synchronize, reopened, closed]
jobs:
  greeting:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v1
    - name: 'Terraform Init'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'init'
        tf_actions_working_dir: '.'
        tf_actions_comment: false
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    - uses: igordcsouza/github-action-get-branch-name@master
      env:
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
    - name: Set branch name as workspace
      run: echo ::set-env name=TF_WORKSPACE::${BRANCH_NAME}
    - name: 'Terraform Plan'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'plan'
        tf_actions_working_dir: '.'
        tf_actions_comment: true
      env:
        DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
    - name: 'Terraform Apply'
      uses: hashicorp/terraform-github-actions@master
      with:
        tf_actions_version: 0.12.13
        tf_actions_subcommand: 'apply'
        tf_actions_working_dir: '.'
        tf_actions_comment: true
      if: github.event.action != 'closed'
      env:
        DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 
        GITHUB_TOKEN: ${{ secrets.TOKEN }}
    - name: Terraform Destoy
      uses: igordcsouza/terraform-github-actions/destroy@master
      if: github.event.action == 'closed'
      env:
        DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_TOKEN }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um ponto muito importante aqui e o fato de pro destroy nao estarmos utilizando a action da Hashicorp, isso por que eles nao implementaram essa opcao. Eu cheguei a conversar com um maintainer mas ele falou que ainda nao viram necessidade de implementar o destroy. A ideia e que esse post seja traduzido pro ingles nos proximos dias e utilizado pra mostrar a real necessidade de ter um destroy tambem!&lt;/p&gt;

&lt;p&gt;Outra diferença e que precisamos adicionar um condicional no comando de destroy, caso contrário todo o fluxo seria executado a cada commit e você não seria capaz de acessar seu ambiente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if: github.event.action == 'closed'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Caso você esteja utilizando esse ambiente "apenas" para rodar alguns testes de integração ou coisas do tipo, poderia deixar sem essa condicional e executar alguma action especifica para rodar os testes entre o passo de criar e destruir.&lt;/p&gt;

&lt;p&gt;No nosso caso o ambiente só será destruído após fecharmos o PR, seja dando merge ou simplesmente fechando o mesmo.&lt;/p&gt;

&lt;p&gt;Abrindo nosso PR ou commitando em um ja aberto poderemos ver o log explicando que esta sendo criada uma máquina na digitalocean.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FKF1gVsX%2FScreenshot-from-2019-11-15-09-26-48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FKF1gVsX%2FScreenshot-from-2019-11-15-09-26-48.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após finalizarmos o trabalho no PR e darmos o merge para outra branch ou mesmo desistirmos de avançar com o PR e o fecharmos o github action se encarrega de destruir o ambiente executando novamente o workflow da seguinte maneira:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FxHBq2S6%2FScreenshot-from-2019-11-15-09-44-29.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FxHBq2S6%2FScreenshot-from-2019-11-15-09-44-29.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Poderiamos deixar o apply sendo executado durante o workflow de destroy, mas isso não seria muito proveitoso. Já que normalmente ele não teria nada para criar e mesmo que tivesse seria destruído em seguida. Entao nao faz muito sentido. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EXTRA&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Um ponto bem legal e que essa nova versao de actions do terraform possuem a capacidade de comentar o output no proprio PR, entao ficaria algo parecido com essa imagem:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FMctsHjz%2FScreenshot-from-2019-11-15-09-27-07.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FMctsHjz%2FScreenshot-from-2019-11-15-09-27-07.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se você leu até aqui deixa um joinha, se inscreve no canal e compartilha com os amiguinhos que isso ajuda bastante no crescimento do canal e... ops mídia errada! 🙂 &lt;/p&gt;

&lt;p&gt;É isso galera, e se o mundo não acabar em breve a gente se vê por ai 🙂 &lt;/p&gt;

</description>
      <category>terraform</category>
      <category>digitalocean</category>
      <category>githubaction</category>
      <category>reviewapp</category>
    </item>
    <item>
      <title>Moving resources from the default workspace to a new one on Terraform.</title>
      <dc:creator>Igor Souza</dc:creator>
      <pubDate>Wed, 05 Jun 2019 01:00:25 +0000</pubDate>
      <link>https://dev.to/igordcsouzaaa/migrating-resources-from-the-default-workspace-to-a-new-one-3ojc</link>
      <guid>https://dev.to/igordcsouzaaa/migrating-resources-from-the-default-workspace-to-a-new-one-3ojc</guid>
      <description>&lt;h2&gt;
  
  
  Step 1 - First things first
&lt;/h2&gt;

&lt;p&gt;I'll assume that you are using remote states for two main reasons:&lt;br&gt;
You should be doing this.&lt;br&gt;
It's harder to move the resources, so when I explain how to do this on remote states you will be able to do this on local states.&lt;/p&gt;

&lt;p&gt;First thing you need to do is remove your backend. You probably have something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  backend "s3" {
    bucket = "bucket-name"
    key    = "terraform.tfstate"
    region = "us-east-1"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You don't need to delete it, just comment all these lines.&lt;/p&gt;

&lt;p&gt;Why? &lt;br&gt;
Because we need to pull our &lt;code&gt;tfstate&lt;/code&gt; to our local machine.&lt;/p&gt;

&lt;p&gt;To pull the &lt;code&gt;tfstate&lt;/code&gt; from remote to local storage we just need to run &lt;code&gt;terraform init&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It will download all the modules and give you the following output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you want to migrate all workspaces to "local"?
 Both the existing "s3" backend and the newly configured "local" backend support workspaces. When migrating between backends, Terraform will copy all workspaces (with the same names). THIS WILL OVERWRITE any conflicting states in the destination.
 
 Terraform initialization doesn't currently migrate only select workspaces.
 If you want to migrate a select number of workspaces, you must manually
 pull and push those states.
 
 If you answer "yes", Terraform will migrate all states. If you answer
 "no", Terraform will abort.
Enter a value:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we don't have any other workspace yet, let's put yes and wait.&lt;br&gt;
Couple seconds should be enough to get the message:&lt;/p&gt;

&lt;p&gt;Terraform has been successfully initialized!&lt;br&gt;
Now, you can do a &lt;code&gt;ls terraform.state&lt;/code&gt; and you see the file created.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2 - Setting up the workspace
&lt;/h2&gt;

&lt;p&gt;Now that we already have the state file on our local storage, we can move the resources.&lt;br&gt;
If you are not using remote storage, you should be using, your work starts here!&lt;/p&gt;

&lt;p&gt;We need to create our workspace so let's run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform workspace new name_of_workspace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case I've done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform workspace new qa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To validate that we don't have any resources lets do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform workspace list
  default
* qa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check if we are in the correct workspace, then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform state list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should get something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No state file was found!
State management commands require a state file. Run this command
in a directory where Terraform has been run or use the -state flag
to point the command to a specific state location.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 - Let's do magic!
&lt;/h2&gt;

&lt;p&gt;You will need to pay a lot of attention here. We will use the terraform state push command.&lt;br&gt;
Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform state push terraform.tfstate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get some error we always had the -force tag ;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform state push -force terraform.tfstate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's run the terraform state list again :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform state list

module.qa_environment.aws_availability_zones.available
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4 - Cleaning up
&lt;/h2&gt;

&lt;p&gt;We can't leave the default workspace with the same resources, we can have problems with two workspaces managing the same resources, so let's clean it!&lt;br&gt;
First, we need to move to default workspace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform workspace select default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's list all the resources available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform state list
module.qa_environment.aws_availability_zones.available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, as I only have the &lt;code&gt;module qa_environment&lt;/code&gt; , I'll run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform state rm module.qa_environment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will remove all nested resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 - Moving data to remote storage.
&lt;/h2&gt;

&lt;p&gt;Let's just uncomment these lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  backend "s3" {
    bucket = "bucket-name"
    key    = "terraform.tfstate"
    region = "us-east-1"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will be asked if want to move all data to a new remove state. Just press yes and you are good to go! :)&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Tip
&lt;/h2&gt;

&lt;p&gt;If you are using some CI/CD tool, don't forget to add the following command as a pipeline step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform workspace select environment_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without this, you will try to recreate all resources on default workspace and probably will get some error.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>workspace</category>
      <category>hashicorp</category>
      <category>default</category>
    </item>
  </channel>
</rss>
