I would like to iterate over a list of values ONLY if the object contains a specific property. Is that possible?
For this use case I want to provision GitHub Repository Variables and Secrets if the local variable has the 'variables' property.
Locals.tf
locals {
repos = {
"terraform-tfe" : {
description = "Automation for Terraform Cloud"
visibility = "private"
}
"terraform-github" : {
description = "Automation for Github Repos"
visibility = "private"
}
"terraform-testapp" : {
description = "Test web app "
visibility = "private"
variables = ["STORAGEACCOUNT","HOSTURL"]
secrets = ["CLIENTID", "CLIENTSECRET]
}
}
}
Main.tf
resource "github_repository" "repos" {
for_each = local.repos
name = each.key
description = each.value.description
visibility = each.value.visibility
}
resource "github_actions_variable" "repository_variables" {
for_each = local.repos
# IF each has 'variables' property
repository = each.key
# Iterate over variables in each.value.repositories
}
resource "github_actions_secrets" "repository_secrets" {
for_each = local.repos
# IF each has 'secrets' property
repository = each.key
# Iterate over secrets in each.value.secrets
}
As mentioned in Filtering elements, a for
expression can also include an optional if
clause to filter elements from the source collection:
locals {
repos = { ... }
secrets = {
for repo_name, repo in local.repos :
repo_name => repo.secrets
if can(repo.secrets)
}
}
In this case, the can function returns false
if the secrets
property doesn't exist.
Full working example:
locals {
repos = {
"terraform-tfe" : {
description = "Automation for Terraform Cloud"
visibility = "private"
variables = [
"STORAGEACCOUNT_1"
]
}
"terraform-github" : {
description = "Automation for Github Repos"
visibility = "private"
secrets = [
"CLIENTID_1",
"CLIENTSECRET_1"
]
}
"terraform-testapp" : {
description = "Test web app "
visibility = "private"
variables = [
"STORAGEACCOUNT_2",
"HOSTURL_2"
]
secrets = [
"CLIENTID_2",
"CLIENTSECRET_2"
]
}
}
secrets = {
for repo_name, repo in local.repos :
repo_name => repo.secrets
if can(repo.secrets)
}
variables = {
for repo_name, repo in local.repos :
repo_name => repo.variables
if can(repo.variables)
}
}
output "secrets" {
value = local.secrets
description = "Secret variables for all repos."
}
output "variables" {
value = local.variables
description = "Variables for all repos."
}
Running terraform plan
:
Changes to Outputs:
+ secrets = {
+ terraform-github = [
+ "CLIENTID_1",
+ "CLIENTSECRET_1",
]
+ terraform-testapp = [
+ "CLIENTID_2",
+ "CLIENTSECRET_2",
]
}
+ variables = {
+ terraform-testapp = [
+ "STORAGEACCOUNT_2",
+ "HOSTURL_2",
]
+ terraform-tfe = [
+ "STORAGEACCOUNT_1",
]
}
You can apply this plan to save these new output values to the Terraform
state, without changing any real infrastructure.