DEV Community

Stefano Martins
Stefano Martins

Posted on

Criação de múltiplos objetos utilizando locals e loops

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
  })
}
Enter fullscreen mode Exit fullscreen mode

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
  })
}
Enter fullscreen mode Exit fullscreen mode

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)
  })
}
Enter fullscreen mode Exit fullscreen mode

Pontos sobre esta nova versão:

  • Dentro do bloco locals foram criados dois maps: um para armazenar as nossas filas normais chamado aws_sqs_queues, e outro chamado aws_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ção try(), 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.

Latest comments (0)