I am designing a monitoring solution for a project and would like to create some alert rules for certain resources (for example application insights).
If I'd like to set up a log search alert, I need to define a specific query and tell the alert what to do.
However, I have not written a log query alert before and do not know how I could set that up.
Currently, I have written an example for a log search in Bicep:
#description('Location of the resource.')
param location string
#description('Log Analytics workspace ID to associate with your Application Insights resource.')
param workspaceId string
#allowed([
0
1
2
3
4])
#description('Severity of the alert.')
param severity int = 2
resource appInsightsLogRule 'Microsoft.Insights/scheduledQueryRules#2022-06-15' = {
name: appInsightsLogRuleName
location: location
properties: {
displayName: appInsightsLogRuleName
severity: severity
enabled: true
evaluationFrequency: 'PT5M'
scopes: [
workspaceId
]
targetResourceTypes: [
'Microsoft.Insights/components'
]
windowSize: 'PT5M'
criteria: {
allOf: [
{
query: 'tbd.'
timeAggregation: 'Count'
dimensions: []
operator: 'GreaterThan'
threshold: 0
failingPeriods: {
numberOfEvaluationPeriods: 1
minFailingPeriodsToAlert: 3
}
}
]
}
autoMitigate: true
actions: {
actionGroups: [
actiongroups_team_blue
]
}
}
}
The query is currently still empty, as I don't know how I could fill this one.
Could someone maybe please share samples or queries for a useful scenario (for example Application Insights, Network Watcher, Sentinel, etc.) for a scheduledQueryAlert or general alert rule? Thank you very much!
First of all, Check the parameter.json file to avoid these kind of empty output issues and check whether the given query is valid.
Referring to MSDoc, I tried to create a sample scheduled log alert for log analytics workspace resource and verify that it was sent to the given email address. It worked and was successfully deployed as follows.
#description('Log Analytics workspace Resource ID.')
param sourceId string = ''
param location string = ''
param actionGroupId string = ''
resource logQueryAlert 'Microsoft.Insights/scheduledQueryRules#2018-04-16' = {
name: 'xxxxx log query alert'
location: location
properties: {
description: 'This is a sample alert'
enabled: 'true'
source: {
query: 'Event | where EventLevelName == "warning" | summarize count() by Computer' #query as per the requirement
dataSourceId: sourceId
queryType: 'ResultCount'
}
schedule: {
frequencyInMinutes: 15
timeWindowInMinutes: 60
}
action: {
'odata.type': 'Microsoft.WindowsAzure.Management.Monitoring.Alerts.Models.Microsoft.AppInsights.Nexus.DataContracts.Resources.ScheduledQueryRules.AlertingAction'
severity: '4'
aznsAction: {
actionGroup: array(actionGroupId)
emailSubject: 'xxxx Log Alert mail subject'
customWebhookPayload: '{ "alertname":"#samplealertrulename", "IncludeSearchResults":true }'
}
trigger: {
thresholdOperator: 'GreaterThan'
threshold: 1
}
}
}
}
Deployment succeeded:
Azure Portal:
Log query alert:
Mail triggered successfully:
Related
I have already budgets created by the bicep and work perfectly. But I want to change the amount on an existing budget by bicep file. Is it possible to do that? I'm receiving errors with the date, or is the budget already exist, .... finally I cannot change it. Below my bicep files:
targetScope = 'subscription'
#description('Name of the Budget. It should be unique within a resource group.')
param budgetName string = 'ConsumptionBudget'
#description('The total amount of cost or usage to track with the budget')
param budgetAmount int
#description('Threshold value associated with a notification. Notification is sent when the cost exceeded the threshold. It is always percent and has to be between 0.01 and 1000.')
param firstPercentageThreshold int = 75
#description('First action group name')
param firstActionGroup string
#description('Threshold value associated with a notification. Notification is sent when the cost exceeded the threshold. It is always percent and has to be between 0.01 and 1000.')
param secondPercentageThreshold int = 100
#description('Second action group name')
param secondActionGroup string
#description('Threshold value associated with a notification. Notification is sent when the cost exceeded the threshold. It is always percent and has to be between 0.01 and 1000.')
param thirdPercentageThreshold int = 110
#description('First action group name')
param thirdActionGroup string
#description('The list of email addresses to send the budget notification to when the threshold is exceeded.')
param contactEmails array = []
param contactRoles array = [
'Owner'
]
#description('The start date must be first of the month in YYYY-MM-DD format. Future start date should not be more than three months. Past start date should be selected within the timegrain preiod.')
param startDate string = '${utcNow('yyyy-MM')}-01'
#description('The time covered by a budget. Tracking of the amount will be reset based on the time grain.')
#allowed([
'Monthly'
'Quarterly'
'Annually'
])
param timeGrain string = 'Monthly'
#description('Subscription id on which budget will be created')
param subscriptionId string
#description('Resource group name in which action groups are located - Action groups passed in firstActionGroup, secondActionGroup, thirdActionGroup')
param resourceGroupName string
var category = 'Cost'
var operator = 'GreaterThan'
resource budgetExists 'Microsoft.Consumption/budgets#2021-10-01' existing = {
name: budgetName
}
resource budget 'Microsoft.Consumption/budgets#2021-10-01' = if(budgetExists.id==null){
name: budgetName
properties: {
timePeriod: {
startDate: startDate
}
timeGrain: timeGrain
category: category
amount: budgetAmount
notifications: {
NotificationForExceededBudget1: {
enabled: true
contactEmails: contactEmails
threshold: firstPercentageThreshold
operator: operator
contactRoles: contactRoles
contactGroups: [
'/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/microsoft.insights/actionGroups/${firstActionGroup}'
]
}
NotificationForExceededBudget2: {
enabled: true
contactEmails: contactEmails
threshold: secondPercentageThreshold
operator: operator
contactRoles: contactRoles
contactGroups: [
'/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/microsoft.insights/actionGroups/${secondActionGroup}'
]
}
NotificationForExceededBudget3: {
enabled: true
contactEmails: contactEmails
threshold: thirdPercentageThreshold
operator: operator
contactRoles: contactRoles
contactGroups: [
'/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/microsoft.insights/actionGroups/${thirdActionGroup}'
]
}
}
}
}
resource budgetUpdate 'Microsoft.Consumption/budgets#2021-10-01' = if(budgetExists.id != null) {
name: budgetName
eTag: budgetExists.eTag
properties: {
timePeriod: {
startDate: budgetExists.properties.timePeriod.startDate
endDate: budgetExists.properties.timePeriod.endDate
}
timeGrain: budgetExists.properties.timeGrain
category: budgetExists.properties.category
amount: budgetAmount
filter: {}
notifications: {
NotificationForExceededBudget1: {
enabled: true
contactEmails: contactEmails
threshold: firstPercentageThreshold
operator: operator
contactRoles: contactRoles
contactGroups: [
'/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/microsoft.insights/actionGroups/${firstActionGroup}'
]
}
NotificationForExceededBudget2: {
enabled: true
contactEmails: contactEmails
threshold: secondPercentageThreshold
operator: operator
contactRoles: contactRoles
contactGroups: [
'/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/microsoft.insights/actionGroups/${secondActionGroup}'
]
}
NotificationForExceededBudget3: {
enabled: true
contactEmails: contactEmails
threshold: thirdPercentageThreshold
operator: operator
contactRoles: contactRoles
contactGroups: [
'/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/microsoft.insights/actionGroups/${thirdActionGroup}'
]
}
}
}
}
Below exceptions from pipelines:
nner Errors:
2023-01-31T08:08:56.4475545Z {"code": "InvalidTemplate", "target": "/subscriptions/d955395e-9c5f-4fa0-ad91-c46ea57d4646/providers/Microsoft.Resources/deployments/budget_20230131080855", "message": "Deployment template validation failed: 'The resource 'Microsoft.Consumption/budgets/ConsumptionBudget' at line '1' and column '3675' is defined multiple times in a template. Please see https://aka.ms/arm-syntax-resources for usage details.'.", "additionalInfo": [{"type": "TemplateViolation", "info": {"lineNumber": 1, "linePosition": 3675, "path": "properties.template.resources[0]"}}]}
This is because you cannot define same resource in a deployment twice :) Looking at your bicep Microsoft.Consumption/budgets/ is indeed defined twice, just with a different condition. Having condition doesn't count, it is still a duplicate :|
What is more, the way you check for existence won't work, as 'existing' keyword in bicep is simply translated to subscriptionResourceId('Microsoft.Consumption/budgets', parameters('budgetName') while compiling to ARM, and this will never be NULL as it is just a helper method to calculate full resource ID, not checking its existence.
So I create following bicep based on https://learn.microsoft.com/en-us/azure/templates/microsoft.storage/2022-05-01/storageaccounts/managementpolicies?pivots=deployment-language-bicep.
It works fine and creates rule, however it deletes all the existing rules. Even they are more than one rule (all different names of course), it delete all the existing rules and replace it with one rule in the bicep script. What am I missing?
resource storage_lifecycle 'Microsoft.Storage/storageAccounts/managementPolicies#2022-05-01' = {
name: 'default'
parent:storageAccount
properties: {
policy: {
rules: [
{
name: 'lifeCycleRule'
enabled: true
type: 'Lifecycle'
definition: {
filters: {
blobTypes: [
'blockBlob'
]
}
actions: {
baseBlob: {
tierToCool: {
daysAfterModificationGreaterThan: 30
}
tierToArchive: {
daysAfterModificationGreaterThan: 30
}
delete: {
daysAfterModificationGreaterThan: 30
}
}
}
}
}
]
}
}
}
Based on this stack answer: Unable to add new rule in Storage Management Policy on Azure, and my experience with Azure API Gateway, you will need to add the existing rules to the new policy.
I've been banging my head against a brick wall on this.
I'm trying to deploy via Azure DevOps pipeline, a bicep/ARM Template an API Connection that uses a Custom Connector that is linked to an On-prem API via a Data Gateway.
Here is my bicep file...
param connectionName string
param displayName string
param gatewayResourceGroup string
param gatewayName string
param connectorName string
param location string = resourceGroup().location
resource connector 'Microsoft.Web/customApis#2016-06-01' existing = {
name: connectorName
}
resource gatewayApi 'Microsoft.Web/connectionGateways#2016-06-01' existing = {
name: gatewayName
scope: resourceGroup(gatewayResourceGroup)
}
resource apiConnection 'Microsoft.Web/connections#2016-06-01' = {
name: connectionName
location: location
properties: {
displayName: displayName
nonSecretParameterValues: {
authType: 'anonymous'
#disable-next-line BCP036
gateway: {
name: gatewayName
id: gatewayApi.id
type: 'Microsoft.Web/connectionGateways'
}
}
api: {
name: connector.name
displayName: 'CONNECTOR ${connectorName}'
id: connector.id
type: 'Microsoft.Web/customApis'
}
}
}
I issue is the nonSecretParameterValues.
They don't go anywhere.
The API Connection is deployed like...
What makes this a little worse is the deployment is successful...
But if I drill into the Operation details I can see there were two issues...
"overallStatus": "Error",
"statuses": [
{
"status": "Error",
"target": "authType",
"error": {
"code": "ConfigurationNeeded",
"message": "Parameter value missing."
}
},
{
"status": "Error",
"target": "gateway",
"error": {
"code": "ConfigurationNeeded",
"message": "Parameter value missing."
}
}
],
Very frustrating.
Now I can manually add the values I intended to be there for the authType and gateway parameters after the deployment is "successful". Then my logic app that uses this API Connection and Custom Connector to Onprem Gateway works as expected.
But the exported template for the API Connection does not change between the connection having missing parameters (in the UI) or after I manually enter the values.
I have also tried added some Powershell after the deployment to pick up the connection and to try settings the "missing" values and updating the resource from there.
I can see another API Connection via Powershell which is correctly set with the authType and gateway parameters.
But when I try, to set these on the resource I need to "fix" it also complains...
I would really like to have the API Connection deployment fully via Azure DevOps pipeline.
NOTE: I find it very odd to have to use the #disable-next-line BCP036 to disable the warning in VSCode. And even opening the built ARM Template will give a warning on the "gateway" property name. I even tried replacing the "object" with just the resource id and that didn't help.
The parameters should be in a parameterValues property object:
resource apiConnection 'Microsoft.Web/connections#2016-06-01' = {
name: connectionName
location: location
properties: {
displayName: displayName
parameterValues: {
authType: 'anonymous'
gateway: {
id: gatewayApi.id
}
}
...
}
}
Suggestion:
The nonSecretParameterValues object must be in the format of a dictionary. I cannot find any hard documentation about this as a data structure, but it's mentioned several times.
nonSecretParameterValues: {
authType: 'anonymous'
gateway-name: gatewayName
gateway-id: gatewayApi.id
gateway-type: 'Microsoft.Web/connectionGateways'
}
Hope this helps.
I am using Bicep to deploy open api json into Azure API Management. The snippet looks like this.
resource fuseintegrationsapi 'Microsoft.ApiManagement/service/apis#2021-08-01' = {
name: '${apim.name}/integrations-api-${environment_name}'
properties: {
description: 'Contains integrations apis used to control the platform.'
type: 'http'
apiRevision: '1234'
isCurrent: true
subscriptionRequired: false
displayName: 'Integrations Api'
serviceUrl: '${api_backend_url}/api/test/v1/integrations'
path: '${environment_name}/api/test/v1/integrations'
protocols: [
protocol
]
value: api_link
format: 'openapi+json-link'
apiType: 'http'
}
dependsOn: [
api2
]
resource symbolicname 'policies' = {
name: 'policy'
properties: {
value: anonymous_operation_policy
format: 'rawxml'
}
}
}
Even though revision is hardcoded to 1234 it's always using default 1 and the API is not updating with latest open api specification.
I had the same problem and figured out that you have to put the revision in the name also.
name: '${apim.name}/integrations-api-${environment_name};rev=1234'
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?
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
}
}]