Terraform, an Infrastructure as Code tool, allows the use of various data types for variables. Two commonly used types are lists and maps. Understanding when and how to use each can greatly enhance your Terraform configurations. Let's delve into their usage, benefits, and limitations, using a practical example.
Understanding Lists and Maps in Terraform
Lists in Terraform
A list is an ordered collection of values where each item can be accessed by its index. In Terraform, lists are declared using square brackets []
.
variable "example_list" {
type = list(string)
default = ["item1", "item2", "item3"]
}
Use Cases for Lists:
- When the order of elements is important.
- For a homogeneous collection of items (all items of the same type).
- When you need to iterate over values with functions like
count.index
.
Maps in Terraform
A map is a collection of key-value pairs. Maps are useful when you want to associate each item in a collection with a unique key.
variable "example_map" {
type = map(string)
default = {
key1 = "value1"
key2 = "value2"
}
}
Use Cases for Maps:
- When you need to retrieve values based on keys.
- For heterogeneous data types or when each item in the collection has additional attributes.
- When manipulating specific elements without affecting the entire structure.
Practical Example: Azure SQL DB Metric Alerts
Consider the scenario of configuring Azure SQL DB metric alerts in Terraform. Initially, a list of objects was used:
variable "alert_metrics" {
type = list(object({
metric_type = string
metric_name = string
// Other attributes...
}))
// Default values...
}
Challenges with Lists
- Direct Access: Accessing a specific alert configuration requires knowing its index, which is not intuitive.
- Scalability: As the list grows, managing and referencing specific elements becomes cumbersome.
- Iteration Complexity: Iterating over lists, especially with nested structures, can get complex.
Transitioning to Maps
To overcome these challenges, the structure was changed to a map:
variable "alert_metrics" {
type = map(object({
metric_type = string
metric_name = string
// Other attributes...
}))
default = {
sql_instance_memory_percent = { /* ... */ }
sql_instance_cpu_percent = { /* ... */ }
// More metrics...
}
}
Advantages of Using Maps:
- Clarity: Each metric configuration is associated with a clear, meaningful key.
- Ease of Access: Directly access or modify a metric configuration using its key.
- Scalability: More manageable as the number of metrics grows.
Terraform Configuration with Maps
With the map approach, for_each
can be used more effectively in resources:
resource "azurerm_monitor_metric_alert" "db_metrics_alert" {
for_each = var.alert_metrics
name = "${each.value.metric_type} - ${var.database_name}"
criteria {
metric_name = each.value.metric_name
// Other configurations...
}
// Additional settings...
}
JSON Example
Terraform also supports JSON syntax, offering an alternative way to define configurations. Here’s how our map variable can be represented in JSON:
{
"alert_metrics": {
"sql_instance_memory_percent": {
"metric_type": "SQL DB Instance Memory Usage",
"metric_name": "sql_instance_memory_percent",
// Other attributes...
},
"sql_instance_cpu_percent": {
// Attributes...
}
// More metrics...
}
}
Conclusion
Choosing between lists and maps in Terraform depends on the specific requirements of your infrastructure configuration. Maps offer more flexibility and direct access capabilities, making them suitable for complex structures like our Azure SQL DB metric alerts. As your Terraform configurations evolve, consider the scalability and manageability of your variables to select the most appropriate data type.