I have a requirement to increment the priority in the below resource block for each of the data items present. eg: priority =1, priority =2 and so on.
resource "okta_app_group_assignments" "idc_app_assignments" {
app_id = okta_app_saml.aws_identity_center.id
for_each = data.okta_groups.all_groups
group {
id = each.value.groups.0.id
priority = 1
}
}
I could not use index function because data.okta_groups.all_groups is an object and it is not supported. Also, tried using a local variable and use that under priority, but it does not seem to work. Please let me know, if there is any way to achieve it.
data "okta_groups" "all_groups" {
for_each = {
for okta_account in local.aws_okta_accounts :
"${okta_account.name}.${okta_account.role}.${okta_account.env_name}" => okta_account}
q = "${each.value.name}-${each.value.env_name}#AWS#OKTA#${each.value.role}#${each.value.account_id}"
#example value for q - abc-dev#AWS#OKTA#dev#12345
}
example for data.okta_groups.all_groups:
+ "abc.dev.qa" = {
+ groups = [
+ {
+ custom_profile_attributes = jsonencode({})
+ description = ""
+ id = "00xxxxxxxxxxxxxb416"
+ name = "abc-qa#AWS#OKTA#dev#12345"
+ type = "OKTA_GROUP"
},
]
+ id = "987654"
+ q = "abc-qa#AWS#OKTA#dev#12345"
+ search = null
+ type = null
}
A Terraform map is not an ordered data structure, so there isn't any meaningful answer for "the index of a map element".
For collections that have a meaningful order, a list is the more appropriate data structure because it preserves the order in which the elements are defined. Therefore I would suggest changing your approach to use a list instead of a map.
I can't show a full example that works with your existing configuration because you've only included a small snippet of what you have, but here's a more contrived example showing the principle which hopefully you can adapt to suit your requirements:
variable "groups" {
type = list(object({
id = string
# (and any other attributes you need)
}))
}
resource "okta_app_group_assignments" "idc_app_assignments" {
app_id = okta_app_saml.aws_identity_center.id
dynamic "group" {
for_each = var.groups
content {
id = group.value.id
priority = group.key + 1
}
}
}
It seems like your situation needs a single resource with multiple group
blocks rather than a separate resource for each group, so here I've used a dynamic
block to achieve that.
dynamic
blocks allow collections of any type in their for_each
because, unlike with resource
-level for_each
, Terraform does not need to individually track each block For nested blocks, that's the provider's responsibility, and providers can decide whether to treat a sequences of blocks as an ordered list or as some other kind of data structure.
Inside the content
block of dynamic "group"
, group.key
represents the key of the current element, and since var.groups
is a list the "keys" in this case are the list element indices. group.key
will therefore be integers counting up from zero, and so I added one to instead produce integers counting up from one.
group.value
is the current element value, similar to each.value
for resource-level for_each
, and so group.value.id
is the id
attribute from the current element.
If you did need to do this with resource
-level for_each
instead of a dynamic
block then that's possible too, but it requires an extra step: Terraform cannot use a list for resource-level for_each
because that doesn't give Terraform enough information to decide a tracking key for each instance of the resource.
In that case then, the typical answer is to use a for
expression to project the list into a map just before assigning it to for_each
, like this:
resource "example" "example" {
for_each = tomap({
for idx, group in var.groups : group.id => merge(
group,
{ priority = idx + 1 },
)
})
# ...
}
This for
expression produces a map that has one element for each element of the given list, and switches it to identify each element by its id
attribute instead of by its index.
But the index is still needed to decide the priority, so the merge
call adds an extra priority
attribute to each object which would then be available as each.value.priority
for other arguments in the resource
block.