Terraform - 不同属性数的嵌套循环

Terraform - nested loop for vary attributes number

描述

我有以下输入结构 (*.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
  (...)
}

但后来我很难创建项目的变量。

问题

使用“计数”将不起作用,因为它不支持嵌套;
所以我发现的另一种方法是使用 for-each 循环。
我已将地图展平:

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

但它仍然没有给我任何信息,因为我没有看到使用唯一属性(如名称)检索创建的项目 ID 的选项,并且需要项目 ID 来创建变量资源:

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

这看起来确实是一个相当简单的要求(只是一个使用第一个循环迭代器作为索引来检索项目 ID 的嵌套循环),但我找到的解决方案要么没有涵盖这种特殊情况(有一个undefined/variable 循环中的参数数量),或者过于复杂...

你们能分享一下你们如何用 terraform-newbie 解决这样的问题吗?

你是对的,你必须展平你的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}" => {
                     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
}