Использование terraform yamldecode для доступа к многоуровневому элементу - PullRequest
0 голосов
/ 09 апреля 2020

У меня есть файл yaml (также используемый в конвейере azure devops, поэтому должен быть в этом формате), который содержит некоторые настройки, к которым я бы хотел получить прямой доступ из моего модуля terraform.

Файл выглядит примерно так:

variables:
  - name: tenantsList
    value: tenanta,tenantb
  - name: unitName
    value: canary

Мне бы хотелось иметь такой модуль для доступа к настройкам, но я не вижу, как добраться до нижнего уровня:

locals {
  settings = yamldecode(file("../settings.yml"))
}

module "infra" {
  source = "../../../infra/terraform/"
  unitname = local.settings.variables.unitName
}

Но terraform plan ошибок с этим:

Error: Unsupported attribute

  on canary.tf line 16, in module "infra":
  16:   unitname  = local.settings.variables.unitName
    |----------------
    | local.settings.variables is tuple with 2 elements

This value does not have any attributes.

1 Ответ

1 голос
/ 10 апреля 2020

Кажется, что главная причина, по которой это сложно, состоит в том, что этот файл YAML представляет собой то, что логически представляет собой одну карту, но физически представляется в виде списка карт YAML.

При чтении данных из отдельного файла, например Для этого я хотел бы написать явное выражение, чтобы нормализовать его и при желании преобразовать его для более удобного использования в остальной части модуля Terraform. В этом случае кажется, что variables в качестве карты было бы наиболее полезным представлением в качестве значения Terraform, поэтому мы можем написать выражение преобразования следующим образом:

locals {
  raw_settings = yamldecode(file("${path.module}/../settings.yml"))
  settings = {
    variables = tomap({
      for v in local.raw_settings.variables : v.name => v.value
    })
  }
}

В приведенном выше примере используется for выражение для проецирования списка карт на одну карту с использованием значений name в качестве ключей.

С помощью списка карт, преобразованного в одну карту, вы можете получить к нему доступ как вы изначально пытались:

module "infra" {
  source = "../../../infra/terraform/"
  unitname = local.settings.variables.unitName
}

Если бы вы вывели преобразованное значение local.settings в виде YAML, это выглядело бы примерно так, поэтому доступ к элементам карты напрямую теперь возможно:

variables:
  tenantsList: tenanta,tenantb
  unitName: canary

Это будет работать, только если все строки name в вашем входе уникальны, потому что иначе не было бы уникального ключа карты для каждого элемента.


(Запись выражения нормализации, подобного этому, также удваивается как некоторая неявная проверка для формы этого файла YAML: если variables не было списком или если значения не были все одинаковыми да тогда Terraform вызовет ошибку типа при оценке этого выражения. Даже если преобразование не требуется, я все равно хотел бы выписать такое выражение, поскольку оно служит некоторой документацией для определения формы файла YAML, а не для изучения всех ссылок на него в остальной части конфигурации.)

...