I am trying to iterate over a variable i.e. map(any) as below:
variable "api_operation" {
description = "(optional) describe your variable"
type = map(any)
default = {
"example-api" = {
"user-delete" = {
"display_name" = "Delete User Operation"
"method" = "DELETE"
"url_template" = "/users/{id}/delete"
"description" = "This can only be done by the logged in user."
},
"user-get" = {
"display_name" = "Get User Operation"
"method" = "GET"
"url_template" = "/users/{id}/get"
"description" = "This can only be done by the logged in user."
}
},
"example-api2" = {
"user-delete" = {
"display_name" = "Delete User Operation"
"method" = "DELETE"
"url_template" = "/users/{id}/delete"
"description" = "This can only be done by the logged in user."
},
"user-get" = {
"display_name" = "Get User Operation"
"method" = "GET"
"url_template" = "/users/{id}/get"
"description" = "This can only be done by the logged in user."
},
"user-put" = {
"display_name" = "PUT User Operation"
"method" = "PUT"
"url_template" = "/users/{id}/put"
"description" = "This can only be done by the logged in user."
}
}
}
}
How to use this in a resource. I have tried in below way. But unable to achieve
You can’t directly use a map of maps like this to create resources. Instead, you need to make sure your data structure matches what you need here: a single-level map with all the attributes needed to make a resource.
I’m not familiar with this resource, so bear with me if I have any mistakes. It looks like the attributes you need are:
api_name , e.g. "example-api"
operation_id, e.g. "user-get"
…and all the attributes in your leaf nodes: display_name, method, url_template, and description
You can flatten this structure down. Instead of:
{
"example-api" = {
"user-delete" = {
"display_name" = "Delete User Operation"
"method" = "DELETE"
"url_template" = "/users/{id}/delete"
"description" = "This can only be done by the logged in user."
},
"user-get" = {
"display_name" = "Get User Operation"
"method" = "GET"
"url_template" = "/users/{id}/get"
"description" = "This can only be done by the logged in user."
}
},
}
You need something like:
{
"example-api-user-delete" = {
"api_name" = "example-api"
"display_name" = "Delete User Operation"
"method" = "DELETE"
"url_template" = "/users/{id}/delete"
"description" = "This can only be done by the logged in user."
},
"example-api-user-get" = {
"api_name" = "example-api"
"display_name" = "Get User Operation"
"method" = "GET"
"url_template" = "/users/{id}/get"
"description" = "This can only be done by the logged in user."
}
},
Differences:
Top-level keys have the API name and the operation ID, so they’re globally unique
Additional elements "api_name" and "operation_id" in the map for the values that were previously keys
Bonus: if you want to keep your original data structure, you can convert it in a local variable using for expressions along with the merge function and the splat expression:
locals {
flattened_operations = merge([
for api, ops in var.api_operation : {
for op, attrs in ops : "${api}-${op}" => merge(
{ api_name : api, operation_id : op },
attrs
)
}
]...)
}
Then you can use for_each = local.flattened_operations in the resource.
That’s strange. Did you copy and paste the locals definition I gave? I tested it locally (with Terraform 0.13.2) and it works for me.
If it’s still not working, please reduce your configuration as much as possible while still preserving the error, paste it here, and let me know which Terraform version you’re using.