-
Notifications
You must be signed in to change notification settings - Fork 708
Continue with Optional Attributes
This section explains the optional attributes that illustrate some of the patterns described in the Specific Design Patterns guide
From the Terraform Registry documentation, each resource supports only one optional filter block

Within a filter block, there are other nested blocks

This example illustrates how to add a single filter
block that could have multiple optional dimension
blocks
Start by implementing the optional filter
block without handling the criteria for multiple optional dimension blocks. This means starting with a single dimension
block in examples/consumption_budget/100-consumption-budget-rg/configuration.tfvars
filter = {
dimensions = {
explicit_name = {
name = "ResourceGroupName"
values = [
"example",
]
}
}
}
Then in the resource, add a dynamic
block to handle the optional filter
. This pattern is described in Single optional block. Essentially, this is handled by the null
check and the feature flag that uses []
, and [1]
conditionally
dynamic "filter" {
for_each = try(var.settings.filter, null) == null ? [] : [1]
content {
dynamic "dimension" {
for_each = var.settings.filter.dimensions
content {
name = dimension.value.name
values = dimension.value.values
}
}
}
}
Building on the previous example, first start by adding more dimension
blocks to the examples in examples/consumption_budget/100-consumption-budget-rg/configuration.tfvars
. In the snippet below, this filter
block contains 2 dimensions. The first uses the given name
that is part of the valid list in the Terraform registry documentation, ResourceGroupName
. The second uses the resource_group_key
name to look up the resource group ID from an object of resource groups.
filter = {
dimensions = {
explicit_name = {
name = "ResourceGroupName"
operator = "In"
values = [
"example",
]
},
resource_group_key = {
# lz_key = "examples"
name = "resource_group_key"
values = [
"test",
]
}
}
}
In this case, the resource will need a map of resource group keys to its attribtues (like the ID). This map is provided by the local.combined_objects_resource_groups
and is explained in Integrating remote and local state. Note that the client_config
is also passed as an additional variable because this is used to lookup a landingzone_key
that allows remote resource groups to be referenced.
module "consumption_budgets_resource_groups" {
source = "./modules/consumption_budget/resource_group"
# truncated
client_config = local.client_config
resource_groups = local.combined_objects_resource_groups
settings = each.value
}
Then modify the modules/consumption_budget/variables.tf
to accept these new variables
variable "client_config" {
description = "Client configuration object"
}
# truncated
variable "resource_groups" {
description = "Map of resource group keys to resource group attributes"
}
These variables are used in modules/consumption_budget/resource_group_budget.tf
dynamic "filter" {
for_each = try(var.settings.filter, null) == null ? [] : [1]
content {
dynamic "dimension" {
for_each = {
for key, value in try(var.settings.filter.dimensions, {}) : key => value
if lower(value.name) != "resource_group_key"
}
content {
name = dimension.value.name
operator = try(dimension.value.operator, "In")
values = dimension.value.values
}
}
dynamic "dimension" {
for_each = {
for key, value in try(var.settings.filter.dimensions, {}) : key => value
if lower(value.name) == "resource_group_key"
}
content {
name = "ResourceId"
operator = try(dimension.value.operator, "In")
values = try(flatten([
for key, value in var.resource_groups[try(dimension.value.lz_key, var.client_config.landingzone_key)] : value.id
if contains(dimension.value.values, key)
]), [])
}
}
}
}
- The
filter
block feature flag pattern remains the same since it is still a single optional block - The
dimension
block adopts a slightly different pattern. 2dynamic
blocks are declared to handle this since we want to condition on thename
that is injected. - The first block handles the default case of using a valid
name
that is part of the Terraform registry documentation. This is done by first destructuringvar.settings.filter.dimensions
to get the key and value wherevalue.name
can be used to get thename
attribute that was defined inconfiguration.tfvars
. In this example,value.name
translates toResourceGroupName
. - The second block handles the case where the
name
inconfiguration.tfvars
wasresource_group_key
. Here it uses this name to reference theid
attribute from theresource_groups
variable that was passed into this resource.
Repeat similar patterns for the tag
and not
blocks