Search code examples
azurefor-loopforeachterraformazure-pipelines

Using Terraform For_Each Loop for Azure Pipeline Stages


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
  ]
}


}

Solution

  • 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.