Terraform — вложенный цикл для изменения количества атрибутов

# #terraform #nested-loops #terraform-provider-gitlab

Вопрос:

Описание

У меня следующая структура ввода (*.tfvars.json)

 {  "projects":[  {  "name":"Project 1",  "gitlab":{  "variables":[  {  "name":"Variable 1",  "value":"Value 1"  }  ]  }  }  ] }  

Анализируется в следующую переменную tf:

 variable "projects" {  type = list(  object({  name = string  gitlab = object({  variables = list(  object({  name = string  value = string  })  )  }) }  

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

Сначала я создаю проекты (поставщик gitlab) с помощью простого мета-параметра «количество» :

 resource "gitlab_project" "projects" {  count = length(var.projects)  name = var.projects[count.index].name  (...) }  

но тогда я изо всех сил пытаюсь создать переменные проектов.

Вопрос

Использование «подсчета» не будет работать, так как оно не поддерживает вложенность;
поэтому другой подход, который я нашел, состоял в том, чтобы использовать для каждого цикла.
Я выровнял карту:

 locals {  project_variables = flatten([  for project in var.projects : [  for variable in project.gitlab.variables : {  project_name = project.name  variable = variable  }  ]  ]) }  

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

 resource "gitlab_project_variable" "project_variables" {  project = gitlab_project.projects[...].id  key = ""  value = "" }  

Это действительно кажется достаточно простым требованием (просто вложенный цикл, который использует первый итератор цикла в качестве индекса для извлечения идентификатора проекта), но решения, которые я нахожу, либо не охватывают этот конкретный случай (с неопределенным/переменным числом аргументов в циклах), либо чрезмерно сложны…

Не могли бы вы, ребята, поделиться тем, как бы вы подошли к такой проблеме с новичком в терраформировании?

Комментарии:

1. * Я знаю, что технически ресурс «gitlab_project_variable» может получать имя проекта в качестве атрибута «проект», но почему — то это не работает для моего экземпляра GitLab — /api/v4/проекты/{идентификатор} работает, а /api/v4/проекты/{имя} — нет.

Ответ №1:

Вы правы, вы должны сгладить свои projects , но по-другому:

 variable "projects" {  type = list(  object({  name = string  gitlab = object({  variables = list(  object({  name = string  value = string  })  )  })  }))     default = [  {  "name":"Project 1",  "gitlab":{  "variables":[  {  "name":"Variable 1",  "value":"Value 1"  }  ]  }  },  {  "name":"Project 2",  "gitlab":{  "variables":[  {  "name":"Variable 2",  "value":"Value 2"  },  {  "name":"Variable 3",  "value":"Value 3"  }   ]  }  },     ] }    locals {   project_names = distinct([for project in var.projects: project.name])   project_variables = merge([  for project in var.projects:  {  for variable in project["gitlab"]["variables"]:  "${project.name}-${variable.name}" =gt; {  project_name = project["name"]  var_name = variable.name  var_value = variable.value  }  }  ]...) # do NOT remove the dots }    

что даст:

 project_variables = {  "Project 1-Variable 1" = {  "project_name" = "Project 1"  "var_name" = "Variable 1"  "var_value" = "Value 1"  }  "Project 2-Variable 2" = {  "project_name" = "Project 2"  "var_name" = "Variable 2"  "var_value" = "Value 2"  }  "Project 2-Variable 3" = {  "project_name" = "Project 2"  "var_name" = "Variable 3"  "var_value" = "Value 3"  }  

затем:

 resource "gitlab_project" "projects" {  for_each = toset(local.project_names)  name = each.key  (...) }  resource "gitlab_project_variable" "project_variables" {    for_each = local.project_variables    project = gitlab_project.projects[each.value.project_name].id  key = each.value.var_name  value = each.value.var_value }  

Комментарии:

1. Спасибо @Marcin, я начинаю понимать. И просто продолжение: если в объекте «проект» есть больше данных, кроме имени (описание и т. Д.); вы бы изменили набор на карту с именем в качестве ключа и другим объектом с остальными данными в качестве значения? Или есть какое-то лучшее решение?

2. @jarobar435 Я бы расширил внутреннюю карту, как я это сделал project_name . Также могут быть возможны другие, более автоматизированные способы, такие как merge . В любом случае, попробуйте, что сможете, и если вы застряли, пожалуйста, задайте новый вопрос. Кроме того, если бы мой ответ был полезен, мы были бы признательны за его принятие.