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