DEV Community

Stefano Martins
Stefano Martins

Posted on

5 2

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.

Reinvent your career. Join DEV.

It takes one minute and is worth it for your career.

Get started

Top comments (0)

Billboard image

Try REST API Generation for Snowflake

DevOps for Private APIs. Automate the building, securing, and documenting of internal/private REST APIs with built-in enterprise security on bare-metal, VMs, or containers.

  • Auto-generated live APIs mapped from Snowflake database schema
  • Interactive Swagger API documentation
  • Scripting engine to customize your API
  • Built-in role-based access control

Learn more