I have the below Terraform configuration file (alerts.tf) which is intended to set up an Azure Monitoring Alert and Action Group on each of our environments. For this illustration, I've limited the number of environments to only 3, i.e. Sandbox, Dev and Test.
Through the use of a for_each
loop, an additional Terraform configuration file (main.tf) will then call the alerts.tf
configuration to provision the resources in each environment.
The entire solution is being implemented through an Azure DevOps (ADO) Pipeline, with each environment set up as an ADO Pipeline 'Stage', and herein lies the issue we're facing.
If the pipeline is triggered without any additional pipeline configuration, it will iterate through the alerts.tf configuration and provision the resources on all 3 environments successfully. However, if for example I choose to select a deployment to only the DEV environment, the pipeline fails with an error message worded similar to the below:
Error: Invalid index
local.monitor_alerts is object with one attribute "SANDBOX"
environment is "DEV"
The given key does not identify an element in this collection value.
Any ideas or suggestions on how we can get round this error?
[[ alerts.tf ]]
locals {
alerts_resource_group = "rg-resources"
}
locals {
monitor_alert_webhook_service_name = "apply"
monitor_alerts = {
SANDBOX = {
apply_sys_failure = {
alert_type = "metric"
name = "service-alert-failure"
resource_group_name = var.rg-monitor-alerts
location = var.location
description = "Sandbox - One or more API calls to the backend service have failed"
scopes = [data.azurerm_application_insights.service_app_insights.id]
auto_mitigation_enabled = false
enabled = true
evaluation_frequency = "PT1M"
window_duration = "PT5M"
severity = 1
target_resource_type = "Microsoft.Insights/components"
skip_query_validation = "false"
criteria = [
{
metric_namespace = "Azure.ApplicationInsights"
metric_name = "SubmitOrder Failures"
aggregation = "Count"
operator = "GreaterThan"
threshold = 0
skip_metric_validation = false
}
]
action = [
{
action_group_id = try(module.azurerm_monitor_action_group["rg_engineers"].action_group.id, "")
webhook_properties = {
service = local.monitor_alert_webhook_service_name
}
}
]
}
}
DEV = {
apply_sys_failure = {
alert_type = "metric"
name = "service-alert-failure"
resource_group_name = var.rg-monitor-alerts
location = var.location
description = "Dev - One or more API calls to the backend service have failed"
scopes = [data.azurerm_application_insights.service_app_insights.id]
auto_mitigation_enabled = false
enabled = true
evaluation_frequency = "PT1M"
window_duration = "PT5M"
severity = 1
target_resource_type = "Microsoft.Insights/components"
skip_query_validation = "false"
criteria = [
{
metric_namespace = "Azure.ApplicationInsights"
metric_name = "SubmitOrder Failures"
aggregation = "Count"
operator = "GreaterThan"
threshold = 0
skip_metric_validation = false
}
]
action = [
{
action_group_id = try(module.azurerm_monitor_action_group["rg_engineers"].action_group.id, "")
webhook_properties = {
service = local.monitor_alert_webhook_service_name
}
}
]
}
}
TEST = {
apply_sys_failure = {
alert_type = "metric"
name = "service-alert-failure"
resource_group_name = var.rg-monitor-alerts
location = var.location
description = "TEST - One or more API calls to the backend service have failed"
scopes = [data.azurerm_application_insights.service_app_insights.id]
auto_mitigation_enabled = false
enabled = true
evaluation_frequency = "PT1M"
window_duration = "PT5M"
severity = 1
target_resource_type = "Microsoft.Insights/components"
skip_query_validation = "false"
criteria = [
{
metric_namespace = "Azure.ApplicationInsights"
metric_name = "SubmitOrder Failures"
aggregation = "Count"
operator = "GreaterThan"
threshold = 0
skip_metric_validation = false
}
]
action = [
{
action_group_id = try(module.azurerm_monitor_action_group["rg_engineers"].action_group.id, "")
webhook_properties = {
service = local.monitor_alert_webhook_service_name
}
}
]
}
}
}
monitor_action_groups = {
SANDBOX = {
rg_engineers = {
name = "acg-rg-engineers"
resource_group_name = local.alerts_resource_group
short_name = "RgEng"
enabled = true
email_receiver = [
{
name = "Incidents Mailbox"
email_address = "rgincidents@rg.com"
}
]
}
}
DEV = {
rg_engineers = {
name = "acg-rg-engineers"
resource_group_name = local.alerts_resource_group
short_name = "RgEng"
enabled = true
email_receiver = [
{
name = "Incidents Mailbox"
email_address = "rgincidents@rg.com"
}
]
}
}
TEST = {
rg_engineers = {
name = "acg-rg-engineers"
resource_group_name = local.alerts_resource_group
short_name = "RgEng"
enabled = true
email_receiver = [
{
name = "Incidents Mailbox"
email_address = "rgincidents@rg.com"
}
]
}
}
}
[[ main.tf ]]
# Create Alerts
module "azurerm_monitor_alert" {
source = "git::https://[ADO-URL]/_git/module-tf-azurerm-monitor-alert"
for_each = local.monitor_alerts
alert = each.value
resource_group_name = each.value.resource_group_name
tags = var.tags
depends_on = [
local.alerts_resource_group
]
}
# Create Action Groups
module "azurerm_monitor_action_group" {
source = "git::https://[ADO-URL]/_git/module-tf-azurerm-monitor-alert"
for_each = local.monitor_alerts
action_group = each.value
resource_group_name = each.value.resource_group_name
tags = var.tags
depends_on = [
local.alerts_resource_group
]
}
}
Greatly appreciate and most grateful for all the prompt feedback. Fortunately, it turns out that the entire Terraform configuration was actually correct........well, almost all correct!
What had happened was that in the locals.monitor_alerts
code block, there was a stray closing curly brace }
that had made its way into the SANDBOX section and so everything beyond that, i.e. the remaining environments, fell outside the monitor_alerts
scope.
Removing the closing brace fixed the issue and so now I can trigger the pipeline by selecting any single stage as my target environment and deploy to that environment only as expected. If I also wish to deploy to multiple or all other environments sequentially, that's also achievable.