Создание нескольких объектов с помощью локалей и циклов

Если вы когда-нибудь оказывались в ситуации, когда вам приходилось управлять большим количеством ресурсов с одинаковыми аргументами, а когда вы отворачивались, вы редактировали файл .tf, содержащий не менее 1500 строк, скучный, повторяющийся, полный одних и тех же ресурсов, на основе копирования и вставки — что ж, возможно, эта статья для вас. В ней я расскажу о том, как написать более компактный и динамичный код с использованием локалей и циклов for_each, чтобы сделать нашу жизнь немного лучше. Хватит!

В качестве примера рассмотрим приведенный ниже код:

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
  })
}
Войдите в полноэкранный режим Выход из полноэкранного режима

В нем мы имеем следующее:

  • Определено 6 очередей SQS, 3 из которых являются обычными очередями и соответствующие им DLQ (Dead-Letter Queues), т.е. очереди, в которые отправляются сообщения, если они не обрабатываются;

  • Атрибуты 3 обычных очередей одинаковы, также как и атрибуты очередей DLQ. Это важно, потому что у нас есть ресурсный шаблон для создания цикла;

  • У нас есть несколько значений аргументов, которые повторяются, и мы можем использовать для них переменные, сохраняя наш код DRY (Don’t Repeat Yourself).

Давайте применять эти изменения постепенно, чтобы мы могли проанализировать постепенное улучшение файла. Первым из этих шагов будет замена значений аргументов на переменные:

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
  })
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Наше главное преимущество новой версии заключается в том, что если мы хотим изменить значение аргумента, нам не нужно делать это во всех ресурсах, а только в переменной.

Теперь создадим блок locals для хранения данных обычной и DLQ очередей, а также создания ресурсов по умолчанию:

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)
  })
}
Войдите в полноэкранный режим Выход из полноэкранного режима

Особенности новой версии:

  • В блоке locals были созданы две карты: одна для хранения наших обычных очередей под названием aws_sqs_queues, а другая под названием aws_sqs_queues_dlq для очередей DLQ. Внутри каждого из них мы определяем атрибуты, которые будут потребляться ресурсами (name, deadLetterTargetArn и т.д.). Выбор использования локальных переменных вместо обычных переменных связан с тем, что в отличие от обычных языков программирования, Terraform не поддерживает переменные, которые имеют в качестве значений результаты выражений, атрибуты ресурсов или которые перезаписываются во время выполнения Terraform;
  • В каждом из двух ресурсов у нас есть цикл for_each, итерирующий соответствующую карту. Наша задача здесь — определить ресурс по умолчанию, в котором мы попытаемся получить значения из карты с помощью функции try(), а если не получится, то попытаемся получить значение из переменной.

Можно усовершенствовать эту структуру и дальше, используя модули, еще больше абстрагируя инфраструктуру, но это уже для будущей статьи.

Оцените статью
Procodings.ru
Добавить комментарий