Передача атрибута из ресурса с числом [0 или 1], определенным для модуля - возможно? - PullRequest
0 голосов
/ 11 ноября 2019

Terraform 0.12.13, поставщик Azurerm 1.35

Некоторые сведения. У меня есть набор служб приложений Azure, размещенных в плане обслуживания приложений в группе ресурсов в расположении Azure. Теперь мне нужно продублировать этот стек в другом месте Azure и добавить некоторые дополнительные ресурсы, такие как диспетчеры трафика и CNAME, и тому подобное, чтобы реализовать высокую доступность. Архитектурно у нас есть Первичные ресурсы, а затем меньшее подмножество Вторичных ресурсов во вторичном регионе (не все должно дублироваться). Не каждое развертывание потребует высокой доступности, поэтому мне нужно иметь возможность создавать или не создавать экземпляры Secondary во время выполнения.

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

Проблема, с которой я столкнулся сейчас, заключается в том, что я использую старый трюк со счетом + троичным операторомконтролировать, создаются ли вторичные ресурсы, и это ломается, потому что 1) счетчик пока не разрешен как мета-аргумент модуля и 2) я не могу понять, как передать экспортированные атрибуты из ресурса, контролируемого мета-счетчиком-аргумент модуля в качестве входной переменной.

Следующий код может сделать это более понятным.

resource "azurerm_resource_group" "appservices_secondary" {
  name     = "foo-services-ca-${local.secondary_release_stage_name}-${var.pipeline}-rg"
  location = local.secondary_location

  count = var.enable_high_availability ? 1 : 0
}

# Create the app service plan to host the secondary app services
module "plan_secondary" {
  source                     = "./app_service_plan"
  release_stage_name         = local.secondary_release_stage_name

  # HERE'S THE PROBLEMATIC LINE
  appsvc_resource_group_name = azurerm_resource_group.appservices_secondary[0].name

  location                   = local.secondary_location
  pipeline                   = var.pipeline
}

Если счетчик разрешается в 1 (var.enable_high_availability = true), то все в порядке. Если значение count равно 0 (var.enable_high_availability = false), то terraform plan завершается неудачно:

Error: Invalid index

  on .terraform\modules\services\secondary.tf line 25, in module "plan_secondary":
  25:   appsvc_resource_group_name = azurerm_resource_group.appservices_secondary[0].name
    |----------------
    | azurerm_resource_group.appservices_secondary is empty tuple

The given key does not identify an element in this collection value.

Если я изменю значение входной переменной на azurerm_resource_group.appservices_secondary.name, тогда оно не пройдет terraform validate, потому что распознает, что оноНужно [count.index].

Есть ли простой способ решить эту проблему? Я все чаще думаю, что это проблема проектирования, и я должен был построить модули с count = [1..2], а не count = 1 (основной) и count = [0 ||1] (вторично), но для этого потребуется, чтобы я переписал все модули, и я бы хотел избежать этого, если есть какой-нибудь умный обходной путь.

1 Ответ

1 голос
/ 12 ноября 2019

Чтобы решить эту проблему, вы можете использовать условное выражение для appsvc_resource_group_name, чтобы указать какое-то альтернативное значение для использования, когда ресурс azurerm_resource_group.appservices_secondary имеет count = 0:

  appsvc_resource_group_name = length(azurerm_resource_group.appservices_secondary) > 0 ? azurerm_resource_group.appservices_secondary[0].name : "default-value"

Похоже на это другоеМодуль бесполезен в ситуациях, когда высокая доступность отключена. В этом случае вы можете определить переменную как необязательную со значением по умолчанию null, чтобы вы могли распознать, когда она не установлена ​​в модуле:

variable "appsvc_resource_group_name" {
  type    = string
  default = null
}

В других местах конфигурации, которую вы используете. можно проверить var.appsvc_resource_group_name != null, чтобы увидеть, включен ли он.


При следовании шаблонам компоновки модулей Я, скорее всего, вместо этого построю это как два модуля, используя одну из следующих двух стратегий:

  • Один модуль для построения "нормального" стека (не HA) и другой модуль для построения стека HA, а затем выберите, какой из них использовать в корневом модуле каждой конфигурации, в зависимости от того,для конкретной конфигурации требуется нормальный режим или режим HA.
  • В качестве альтернативы, если стек HA всегда является надмножеством «нормального» стека, имеется один модуль для нормального стека, а затем другой модуль, который потребляет выходные данныепервый и описывает расширенные ресурсы, необходимые для режима HA.

Вот пример второго из этих подходов, просточтобы проиллюстрировать, что я имею в виду под этим:

module "primary_example" {
  source = "./primary_example"

  # whatever arguments are needed
}

module "secondary_example" {
  source = "./secondary_example"

  # Make sure the primary module exports as outputs all of the
  # values required to extend to HA mode, and then just pass
  # that whole object through to secondary.
  primary = module.primary_example
}

В конфигурации, в которой не требуется режим HA, вы можете опустить module "secondary_example".

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

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

...