Terraform provides a for_each
iterator which allows you to loop over elements of a list, and perform an operation with each element. For example, to grant multiple permissions for myself on a Snowflake schema, I could do something like this:
resource "snowflake_schema_grant" "write_permissions" {
for_each = toset(["CREATE TABLE", "CREATE VIEW", "USAGE"])
database_name = "MY_DATABASE"
privilege = each.key
roles = "DAVE"
schema_name = "MY_SCHEMA"
}
This loops over each element in the for_each
list, and substitutes it as the privilege
using each.key
.
Unfortunately, there is no way in Terraform to to nest this for_each
list within another for_each
list. Terraform does however support nested loops when creating local data structures, and it has a flatten
function which can flatten the resulting list-of-lists. We can combine these two features to create a flat list of objects suitable for use with for_each
.
Suppose we have a list of schemas, and I want to give myself a list of permissions on each of them as we did for the MY_SCHEMA
schema above:
locals {
schemas = [
"PRIVATE",
"PUBLIC",
"MY_SCHEMA",
]
privileges = [
"CREATE TABLE",
"CREATE VIEW",
"USAGE",
]
# Nested loop over both lists, and flatten the result.
schema_privileges = distinct(flatten([
for schema in local.schemas : [
for privilege in local.privileges : {
privilege = privilege
schema = schema
}
]
]))
}
This gives us a list of objects with an entry for each operation we want to perform:
[
{ privilege: "CREATE TABLE", schema: "PRIVATE" },
{ privilege: "CREATE VIEW", schema: "PRIVATE" },
{ privilege: "USAGE", schema: "PRIVATE" },
{ privilege: "CREATE TABLE", schema: "PUBLIC" },
{ privilege: "CREATE VIEW", schema: "PUBLIC" },
{ privilege: "USAGE", schema: "PUBLIC" },
{ privilege: "CREATE TABLE", schema: "MY_SCHEMA" },
{ privilege: "CREATE VIEW", schema: "MY_SCHEMA" },
{ privilege: "USAGE", schema: "MY_SCHEMA" },
]
We can then feed this map into for_each
to grant the permissions:
resource "snowflake_schema_grant" "write_permissions" {
# We need a map to use for_each, so we convert our list into a map by adding a unique key:
for_each = { for entry in local.schema_privileges: "${entry.schema}.${entry.privilege}" => entry }
database_name = "MY_DATABASE"
privilege = each.value.privilege
roles = "DAVE"
schema_name = each.value.schema
}