0

I am trying to set up alerts in Azure bicep resources/modules. The goal is to have 3 files, one where the initial resource structure is created and parameterized:

param metricAlertsName string
param description string
param severity int
param enabled bool = true
param scopes array = []
param evaluationFrequency string
param windowSize string
param targetResourceRegion string = resourceGroup().location
param allOf array = []
param actionGroupName string

var actionGroupId = resourceId(resourceGroup().name, 'microsoft.insights/actionGroups', actionGroupName)

resource dealsMetricAlerts 'Microsoft.Insights/metricAlerts@2018-03-01' = [for appService in appServices : {
  name: metricAlertsName
  location: 'global'
  tags: {}
  properties: {
    description: description
    severity: severity
    enabled: enabled
    scopes: scopes
    evaluationFrequency: evaluationFrequency
    windowSize: windowSize
    targetResourceRegion: targetResourceRegion
    criteria: {
      'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'
      allOf: allOf
    }
    actions: [
      {
        actionGroupId: actionGroupId
      }
    ]
  }
}]

A second file, main.bicep where all of my resources are being consumed as modules:

module dealsMetricAlerts '../modules/management/metric-alert.bicep' = [for (alert, index) in alertConfig.metricAlerts: {
  name: alert.name
  params: {
    metricAlertsName: alert.params.metricAlertsName
    actionGroupName: actionGroupName
    description: alert.params.description
    evaluationFrequency: alert.params.evaluationFrequency
    severity: alert.params.severity
    windowSize: alert.params.windowSize
    allOf: alert.params.allOf
    scopes: [
      resourceId(resourceGroup().name,'Microsoft.Web/sites', 'gbt-${env1}-${env}-${location}-webapp')
    ]
  }
}]

And the third file which is a parameter file in which I can loop over, enter its values into the module in main.bicep to create multiple resources without having to write more than one module:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "alertConfig": {
      "value": {
        "metricAlerts": [
          {
            "name": "403ErrorTest",
            "params": {
              "metricAlertsName": "AppService403ErrorTest",
              "actionGroupName": "actionGroupName",
              "description": "Alert fires whenever the App Service throws a 403 error",
              "evaluationFrequency": "PT5M",
              "severity": 2,
              "windowSize": "PT15M",
              "allOf": [
                {
                  "name": "403errorTest",
                  "metricName": "Http403",
                  "dimensions": [],
                  "operator": "GreaterThan",
                  "threshold": 0,
                  "timeAggregation": "Count"
                }
              ]
            }
          },
          {
            "name": "5XXErrorTest",
            "params": {
             // Values for 500 error
            }
          }
        ]
      }
    }
  }
}

I have a total of 5 app services, 1 web app and 4 function apps. If I was to hard code the name of the app service like above then that one web app is deployed with the 2 errors exactly as it should.

The issue that I'm having is to try and use another loop on the scopes param to have the 2 errors attached to all 5 app services.

I tried something like:

// Created an array with the names of the app services
var appServices = [
  'dda-webApp'
  'dealservice-fnapp'
  'itemdata-fnapp'
  'refdata-fnapp'
  'userprofile-fnapp'
]

// Update the scopes param to loop through the names\
scopes: [for appService in appServices: [
  resourceId(resourceGroup().name,'Microsoft.Web/sites', 'gbt-${env1}-${env}-${location}-${appService}')
]]

This most often gives me an error saying: Unexpected token array in scopes[0].

I believe what's happening is when it's trying to look up the resource by name in resourceId it's looping through all of the appServices names and attaching the entire array onto the resource name making it invalid.

Is there another way to loop through these scopes in order to attach the 403 and 500 alerts to each of my 5 app services?

Thomas
  • 24,234
  • 6
  • 81
  • 125
agw2021
  • 266
  • 2
  • 22

1 Answers1

0

Looking at the documentation, you can't do inner loops:

Using loops in Bicep has these limitations:

  • Loop iterations can't be a negative number or exceed 800 iterations.
  • Can't loop a resource with nested child resources. Change the child resources to top-level resources. See Iteration for a child resource.
  • Can't loop on multiple levels of properties.

In you case, you can define a variable and create the array outside of the module loop:

// Created an array with the names of the app services
var appServices = [
  'dda-webApp'
  'dealservice-fnapp'
  'itemdata-fnapp'
  'refdata-fnapp'
  'userprofile-fnapp'
]

// Create an array of app service resource ids
var appServiceIds = [for appService in appServices: resourceId(resourceGroup().name,'Microsoft.Web/sites', 'gbt-${env1}-${env}-${location}-${appService}')]


// Set the scope param with this variable
module dealsMetricAlerts '../modules/management/metric-alert.bicep' = [for (alert, index) in alertConfig.metricAlerts: {
  name: alert.name
  params: {
    ...
    scopes: appServiceIds
  }
}]
Thomas
  • 24,234
  • 6
  • 81
  • 125
  • Hmm, I was able to get a different error this time. I think this should be the solution and that there may be a limitation in Bicep. It says: `"Scopes property is invalid. Only single resource is allowed for criteria type SingleResourceMultipleMetricCriteria. If you want to create an alert on multiple resources, use MultipleResourceMultipleMetricCriteria odata.type."` And if I change to MultipleResource criteria I get: `Alerts are currently not supported with multi resource level for microsoft.web/sites.` – agw2021 Nov 01 '21 at 20:12
  • Ok so you need to create an alert per error code per app in fact ? – Thomas Nov 02 '21 at 05:57
  • Ho can you change this line: `'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria'` to be `'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria'` in the alert module ? – Thomas Nov 02 '21 at 05:59