Se você já se encontrou em uma situação onde teve que gerenciar uma grande quantidade de recursos com os mesmos argumentos, e quando olha para o lado, você está lá editando um arquivo .tf
com pelo menos 1500 linhas, chato, repetitivo, cheio de recursos iguais, na base do copia-e-cola bem, talvez este artigo seja para você. Nele apresentarei uma forma para escrever um código menor e mais dinâmico com o uso de locals e loops for_each
com o objetivo de tornar a nossa vida um pouco melhor. Chega mais!
Vamos pegar o código abaixo como exemplo:
resource "aws_sqs_queue" "fila_01_dlq" {
name = "fila-01-dlq"
message_retention_seconds = 172800
delay_seconds = 0
max_message_size = 256000
visibility_timeout_seconds = 40
receive_wait_time_seconds = 20
}
resource "aws_sqs_queue" "fila_01" {
name = "fila-01"
message_retention_seconds = 172800
delay_seconds = 0
max_message_size = 256000
visibility_timeout_seconds = 40
receive_wait_time_seconds = 20
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.fila_01_dlq.arn
maxReceiveCount = 3
})
}
resource "aws_sqs_queue" "fila_02_dlq" {
name = "fila-02-dlq"
message_retention_seconds = 172800
delay_seconds = 0
max_message_size = 256000
visibility_timeout_seconds = 40
receive_wait_time_seconds = 20
}
resource "aws_sqs_queue" "fila_02" {
name = "fila-02"
message_retention_seconds = 172800
delay_seconds = 0
max_message_size = 256000
visibility_timeout_seconds = 40
receive_wait_time_seconds = 20
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.fila_02_dlq.arn
maxReceiveCount = 3
})
}
resource "aws_sqs_queue" "fila_03_dlq" {
name = "fila-03-dlq"
message_retention_seconds = 172800
delay_seconds = 0
max_message_size = 256000
visibility_timeout_seconds = 40
receive_wait_time_seconds = 20
}
resource "aws_sqs_queue" "fila_03" {
name = "fila-03"
message_retention_seconds = 172800
delay_seconds = 0
max_message_size = 256000
visibility_timeout_seconds = 40
receive_wait_time_seconds = 20
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.fila_03_dlq.arn
maxReceiveCount = 3
})
}
Nele, nós temos o seguinte:
São definidas 6 filas SQS, sendo 3 normais e suas respectivas DLQs (Dead-Letter Queues), ou seja, filas para onde as mensagens são enviadas caso não processadas;
Os atributos das 3 filas normais são os mesmos, assim como os das filas DLQs. Isso é importante porque nós temos um padrão de recurso para criação de um loop;
Temos vários valores de argumentos que se repetem, e nós podemos utilizar para eles variáveis, mantendo o nosso código DRY (Don't Repeat Yourself).
Vamos aplicar essas mudanças aos poucos para podermos analisar a melhoria gradual do arquivo. O primeiro desses passos será a substituição dos valores dos argumentos por variáveis:
variable "sqs_message_retention_seconds" {
type = number
default = 172800
}
variable "sqs_delay_seconds" {
type = number
default = 0
}
variable "sqs_max_message_size" {
type = number
default = 256000
}
variable "sqs_visibility_timeout_seconds" {
type = number
default = 40
}
variable "sqs_receive_wait_time_seconds" {
type = number
default = 20
}
variable "sqs_maxReceiveCount" {
type = number
default = 3
}
resource "aws_sqs_queue" "fila_01_dlq" {
name = "fila-01-dlq"
message_retention_seconds = var.sqs_message_retention_seconds
defay_seconds = var.sqs_delay_seconds
max_message_size = var.sqs_max_message_size
visibility_timeout_seconds = var.sqs_visibility_timeout_seconds
receive_wait_time_seconds = var.sqs_receive_wait_time_seconds
}
resource "aws_sqs_queue" "fila_01" {
name = "fila-01"
message_retention_seconds = var.message_retention_seconds
defay_seconds = var.sqs_delay_seconds
max_message_size = var.sqs_max_message_size
visibility_timeout_seconds = var.sqs_visibility_timeout_seconds
receive_wait_time_seconds = var.sqs_receive_wait_time_seconds
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.fila_01_dlq.arn
maxReceiveCount = var.sqs_maxReceiveCount
})
}
resource "aws_sqs_queue" "fila_02_dlq" {
name = "fila-02-dlq"
message_retention_seconds = var.message_retention_seconds
defay_seconds = var.sqs_delay_seconds
max_message_size = var.sqs_max_message_size
visibility_timeout_seconds = var.sqs_visibility_timeout_seconds
receive_wait_time_seconds = var.sqs_receive_wait_time_seconds
}
resource "aws_sqs_queue" "fila_02" {
name = "fila-02"
message_retention_seconds = var.message_retention_seconds
defay_seconds = var.sqs_delay_seconds
max_message_size = var.sqs_max_message_size
visibility_timeout_seconds = var.sqs_visibility_timeout_seconds
receive_wait_time_seconds = var.sqs_receive_wait_time_seconds
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.fila_02_dlq.arn
maxReceiveCount = var.sqs_maxReceiveCount
})
}
resource "aws_sqs_queue" "fila_03_dlq" {
name = "fila-03-dlq"
message_retention_seconds = var.message_retention_seconds
defay_seconds = var.sqs_delay_seconds
max_message_size = var.sqs_max_message_size
visibility_timeout_seconds = var.sqs_visibility_timeout_seconds
receive_wait_time_seconds = var.sqs_receive_wait_time_seconds
}
resource "aws_sqs_queue" "fila_03" {
name = "fila-03"
message_retention_seconds = var.message_retention_seconds
defay_seconds = var.sqs_delay_seconds
max_message_size = var.sqs_max_message_size
visibility_timeout_seconds = var.sqs_visibility_timeout_seconds
receive_wait_time_seconds = var.sqs_receive_wait_time_seconds
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.fila_03_dlq.arn
maxReceiveCount = var.sqs_maxReceiveCount
})
}
O nosso principal ganho com esta nova versão é que caso desejemos modificar o valor de um argumento, não precisamos fazê-lo em todos os resources, mas apenas na variável.
Agora vamos criar um bloco locals
para armazenar os nossos dados das filas normais e DLQ, assim como a criação dos resources padrão:
variable "sqs_message_retention_seconds" {
type = number
default = 172800
}
variable "sqs_delay_seconds" {
type = number
default = 0
}
variable "sqs_max_message_size" {
type = number
default = 256000
}
variable "sqs_visibility_timeout_seconds" {
type = number
default = 40
}
variable "sqs_receive_wait_time_seconds" {
type = number
default = 20
}
variable "sqs_maxReceiveCount" {
type = number
default = 3
}
locals {
aws_sqs_queues_dlq = {
fila_01_dlq = {
name = "fila-01-dlq"
}
fila_02_dlq = {
name = "fila-02-dlq"
}
fila_03_dlq = {
name = "fila-03-dlq"
}
fila_01 = {
name = "fila-01"
deadLetterTargetArn = aws_sqs_queue.aws_sqs_queues_dlq["fila_01_dlq"].arn
}
fila_02 = {
name = "fila-02"
deadLetterTargetArn = aws_sqs_queue.aws_sqs_queues_dlq["fila_02_dlq"].arn
}
fila_03 = {
name = "fila-03"
deadLetterTargetArn = aws_sqs_queue.aws_sqs_queues_dlq["fila_03_dlq"].arn
}
}
}
resource "aws_sqs_queue" "aws_sqs_queues_dlq" {
for_each = local.aws_sqs_queues_dlq
name = each.value.name
message_retention_seconds = try(each.value.message_retention_seconds, var.sqs_message_retention_seconds)
delay_seconds = try(each.value.delay_seconds, var.sqs_delay_seconds)
max_message_size = try(each.value.delay_seconds, var.sqs_max_message_size)
visibility_timeout_seconds = try(each.value.visibility_timeout_seconds, var.sqs_visibility_timeout_seconds)
receive_wait_time_seconds = try(each.value.receive_wait_time_seconds, var.sqs_receive_wait_time_seconds)
}
resource "aws_sqs_queue" "aws_sqs_queues" {
for_each = local.aws_sqs_queue
name = each.value.name
message_retention_seconds = try(each.value.message_retention_seconds, var.sqs_message_retention_seconds)
delay_seconds = try(each.value.delay_seconds, var.sqs_delay_seconds)
max_message_size = try(each.value.delay_seconds, var.sqs_max_message_size)
visibility_timeout_seconds = try(each.value.visibility_timeout_seconds, var.sqs_visibility_timeout_seconds)
receive_wait_time_seconds = try(each.value.receive_wait_time_seconds, var.sqs_receive_wait_time_seconds)
redrive_policy = jsonencode({
deadLetterTargetArn = each.value.deadLetterTargetArn
maxReceiveCount = try(each.value.maxReceiveCount, var.sqs_maxReceiveCount)
})
}
Pontos sobre esta nova versão:
- Dentro do bloco
locals
foram criados dois maps: um para armazenar as nossas filas normais chamadoaws_sqs_queues
, e outro chamadoaws_sqs_queues_dlq
para as filas DLQ. Dentro de cada um estamos definindo os atributos que serão consumidos pelos resources (name
,deadLetterTargetArn
, etc.). A escolha pelo uso de locals sobre variáveis normais dá-se devido ao fato de que diferentemente de linguagens de programação normais, o Terraform não suporta que variáveis tenham como seus valores resultados de expressões, atributos de resources ou que os mesmos sejam sobreescritos ao longo da execução do Terraform; - Em cada um dos dois resources, temos um loop
for_each
iterando sobre o respectivo map. A nossa preocupação aqui é definir um resource padrão, onde tentamos resgatar os valores do map com o uso da funçãotry()
, e caso não consigamos, ele tentará pegar o valor da variável.
É possível melhorar ainda mais esta estrutura com a utilização de módulos, abstraindo ainda mais a infraestrutura, mas fica para um próximo artigo.
Top comments (0)