Terraform APPLY + DESTROY
Tags: terraform, hashicorp, curso
Published: 2021-03-21 12:53:19

---
title: Terraform APPLY + DESTROY
published: true
description: Aprenda os conceitos envolvendo os comandos apply e destroy
tags: terraform, hashicorp, curso
cover_image: https://cdn.cycloid.io/s3fs-public/2020-05/terraform_logo_300.png
---

# Curso Completo Gratis!

Esse post faz parte de um curso completo sobre Terraform, caso voce queira saber mais sobre terraform da um pulo no meu [blog](https://igordcsouza.com) ou no meu [youtube](https://www.youtube.com/channel/UC3yoPZJdjwOjrHWy_iEP08A) para ter acesso ao curso completo 100% gratuito.

# Mas se quiser contribuir:
[Aqui no Udemy](https://www.udemy.com/course/terraform-na-pratica/?referralCode=6DAB87D1325C238B4745) tem o mesmo curso que esta disponivel 100% gratuito no youtube pra quem quiser e puder contribuir financeiramete :)

## Terraform Apply

Vamos utilizar o comando `terraform apply` para tentarmos criar nosso droplet.

```
 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:
```

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

Se você quiser burlar esse plan e simplesmente aceitar o que vai ser criado, basta executar `terraform apply -auto-approve`.

```
terraform apply -auto-approve
digitalocean_droplet.web: Creating...

Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you
```

Achou que eu ia te livrar de todos os erros? Achou errado!

Bom, `401 Unable to authenticate you` 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.

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 `generate new token` de um nome para o seu token e copie o token que vai aparecer para você. Algo como:

```
 b783123asd294f002c5ea9af1231298327903284kmmsadoiu48d02707a2018588d
```

Agora vamos seguir o jeito mais simples e completamente 

```
variable "do_token" {
  default = "b783123asd294f002c5ea9af1231298327903284kmmsadoiu48d02707a2018588d"
}

provider "digitalocean" {
  token = var.do_token
}
```


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


Vamos executar novamente nosso apply:
```
terraform apply -auto-approve
digitalocean_droplet.web: Creating...

Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you
```

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.

```
 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"
}
```

Agora o provider `digitalocean` sabe que ele deve procurar por uma variável chamada `do_token` e utilizar no parâmetro `token`.

Vamos tentar mais uma vez criar nossa máquina.

```
terraform apply -auto-approve
digitalocean_droplet.web: Creating...

Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 422 nyc2 is unavailable.
```

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 `422 nyc2 nao esta disponivel`. Acontece que apesar da documentação do provider dar o exemplo com a região `nyc2`, 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 `ams3` que e a região de Amsterdam pra ficar mais pertinho de mim, mas você pode usar outra qualquer como `nyc3` por exemplo.

Mais uma tentativa:

```
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.
```

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?

Pra isso vamos utilizar os `outputs`.

## Terraform Output

Toda documentação de um resource é dividido em pelo menos tres níveis. 

* Exemplo de Uso
* Referência de Argumento (ou parâmetro)
* Referência de Atributos

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.

O `output` 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 `output` que é retornar os valores de um módulo. Mas fica tranquilo que isso é mais pra frente.

Por hora vamos adicionar o seguinte num arquivo chamado `output.tf`, que esteja na mesma pasta que nosso `main.tf`.

```
output "droplet_ip" {
  value = "hashicourse"
}
```

Vamos executar novamente o comando `apply` e vamos ver que agora temos mais um retorno no nosso código.

```
terraform apply -auto-approve
digitalocean_droplet.web: Refreshing state... [id=232247846]

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

Outputs:

droplet_ip = "hashicourse"
```

Nada foi criado ou alterado, como esperado, mas vemos um `Outputs:` 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. 

Primeiro, deixa eu te mostrar o código:

```
 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
}
```

.A forma de chegarmos nesse atributo é bem simples.
* [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. 
* [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?
* [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.

Por fim basta montar sempre no formato A.B.C :) 

Se você rodar o seu código agora deve ter um retorno como o seguinte:

```
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"
```

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

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 `terraform output`:

```
terraform output
droplet_ip = "104.248.203.68"
```

## Terraform Destroy

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 `destroy`.
O `terraform destroy` é o oposto do `apply`. 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 `plan` chamado de `-destroy`. E esse é o parâmetro que o terraform usa quando a gente executa o `terraform destroy`, a saída deve ser parecida com a seguinte:

```
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 -> null
      - created_at           = "2021-02-17T19:34:37Z" -> null
      - disk                 = 25 -> null
      - id                   = "232254786" -> null
      - image                = "ubuntu-20-04-x64" -> null
      - ipv4_address         = "104.248.197.79" -> null
      - ipv4_address_private = "10.110.0.2" -> null
      - ipv6                 = false -> null
      - locked               = false -> null
      - memory               = 1024 -> null
      - monitoring           = false -> null
      - name                 = "web-1" -> null
      - price_hourly         = 0.00744 -> null
      - price_monthly        = 5 -> null
      - private_networking   = true -> null
      - region               = "ams3" -> null
      - resize_disk          = true -> null
      - size                 = "s-1vcpu-1gb" -> null
      - status               = "active" -> null
      - urn                  = "do:droplet:232254786" -> null
      - vcpus                = 1 -> null
      - volume_ids           = [] -> null
      - vpc_uuid             = "b83009d3-8cb0-4545-8123-6f2238e40284" -> null
    }

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

Changes to Outputs:
  - droplet_ip = "104.248.197.79" -> 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:
```

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

```
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.
```

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. 

## Arquivo de Variaveis

Uma coisa comum de se ver são códigos que utilizam uma variável da seguinte forma:

```
 variable "do_token" {
  description = "Uma descricao bacana!"
  type        = string
}
```

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. 

Uma solução, bem gambiarra, que eu já fiz muito é colocar um valor `default` 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 `terraform` te dá a possibilidade de usar um arquivo só para adicionar esse valores. Basta criarmos um arquivo `qualquer_coisa.tfvars`. Normalmente as pessoas utilizam `terraform.tfvars` ou então `nome_do_ambiente.tfvars`. Vamos criar o nosso como `terraform.tfvars` mesmo.

```
 do_token = "b783123asd294f002c5ea9af1231298327903284kmmsadoiu48d02707a2018588d"
```

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 `terraform` que ele deve buscar os valores das variáveis primeiro nesse arquivo, para isso vamos executar o `apply` novamente passando o `-var-file` como parâmetro. Esse `-varfile` vale para o `plan` e o `destroy` também. 

```
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"
```