Menu

Virtual Geek

Tales from real IT system administrators world and non-production environment

Create CPU quota usage alerts for subscription using Azure ARM templates

This article is about Implementing of CPU Quota Usage Alert for Azure Subscription. As part of my recent assignment, I successfully created a CPU quota usage alert for an Azure subscription using Azure Resource Manager (ARM) templates. The deployment enables real-time monitoring of CPU quota usage, providing proactive alerts to prevent potential resource exhaustion.

Upon deployment, the alert rules are accessible within the Azure Subscription portal, under Usage + Quotas > Total Regional vCPUs > Location. This view lists all alert rules associated with specific quota names and locations. Please note that any modifications to quota names or locations for an alert rule may affect its visibility in this list.

By fulfilling these requirements and leveraging ARM templates, the CPU quota usage alert system provides enhanced visibility and control over resource utilization, enabling prompt action to prevent quota breaches.

While creating this setup there are few prerequisite which I mentioned below.

Arm Azure Templates Subscriptions Usage Quotas Total Regional vCPUs Alert rule preview location Quota usage and limit exceeded trigger configuration Arm template json.png

Before creating alert I have already have created common Resource Group and User Assigned Identity as a prerequisite. These resources will be used while creating Quota usage alerts and action groups resources. Below is the PowerShell script you can use to deploy with ARM templates.

Download this code CPU_Quota_Alert_Azure_ARM_templates.zip here or it is also available on github.com.

New-AzResourceGroupDeployment -ResourceGroupName 'vcloud-lab.com'  `
                               -TemplateFile "$PSScriptRoot\CPU_Quota_Alert_combined_template.json" `
                               -TemplateParameterFile "$PSScriptRoot\CPU_Quota_Alert_template_parameters.json" `
                               -Verbose
#########################################################################################################
<#
#Another way 2: Deploy Using a Parameters File
# Variables
# $resourceGroupName = "vcloud-lab.com"
# $deploymentName = "QuotaAlertDeployment"
# $templateFilePath = "D:\Projects\PowerShell\\subscription_quota_rule\action_group_template.json"  # Path to your ARM template

# # Define parameters inline
# $parameters = @{
#     "Action_Group_Name" = "QuotaAlertRules-AG-2"
#     "Action_Group_ShortName" = "QuotaAlert2"
#     "Email_Address" = "[email protected]"
# }

# # Deploy the template
# New-AzResourceGroupDeployment `
#     -ResourceGroupName $resourceGroupName `
#     -TemplateFile $templateFilePath `
#     -TemplateParameterObject $parameters `
#     -DeploymentName $deploymentName

Below is the output after deploying Azure ARM template with parameters files from PowerShell Az module. All the resources are created successfully with this command on the Azure Cloud.

Azure ARM Templates PowerShell Action Group shortname quota alert user managed identity subscription scopes dimensions location type compute powershell deployments configuration.png

Here is ARM template in JSON format to deploy Action Group and Schedule Query rule for subscription. There are few items I marked in red inside the KUSTO query language, which you need to modify accordingly as per your infrastructure. If you want to totally automate values inside Kusto, you can make use of templating to create a template from required values.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "Action_Group_Name": {
            "defaultValue": "Action_Group01",
            "type": "string"
        },
        "Action_Group_ShortName": {
            "defaultValue": "actiongroup",
            "type": "string"
        },
        "Email_Address": {
            "defaultValue": "[email protected]",
            "type": "string"
        },
        "Quota_Alert_Name": {
            "defaultValue": "Quota_Alert01",
            "type": "string"
        },
        "User_Managed_Identity": {
            "defaultValue": "/subscriptions/9exxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vcloud-lab.com/providers/Microsoft.ManagedIdentity/userAssignedIdentities/dev",
            "type": "string"
        },
        "Scopes": {
            "defaultValue": "/subscriptions/9exxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
            "type": "string"
        },
        "Dimensions_Type": {
            "defaultValue": "microsoft.compute/locations/usages",
            "type": "string"
        },
        "Dimensions_Location": {
            "defaultValue": "eastus",
            "type": "string"
        },
        "Dimensions_Quota_Name": {
            "defaultValue": "cores",
            "type": "string"
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "microsoft.insights/actionGroups",
            "apiVersion": "2023-09-01-preview",
            "name": "[parameters('Action_Group_Name')]",
            "location": "Global",
            "properties": {
                "groupShortName": "[parameters('Action_Group_ShortName')]",
                "enabled": true,
                "emailReceivers": [
                    {
                        "name": "EmailAction",
                        "emailAddress": "[parameters('Email_Address')]",
                        "useCommonAlertSchema": true
                    }
                ],
                "smsReceivers": [],
                "webhookReceivers": [],
                "eventHubReceivers": [],
                "itsmReceivers": [],
                "azureAppPushReceivers": [],
                "automationRunbookReceivers": [],
                "voiceReceivers": [],
                "logicAppReceivers": [],
                "azureFunctionReceivers": [],
                "armRoleReceivers": [
                    {
                        "name": "EmailARMRole",
                        "roleId": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635",
                        "useCommonAlertSchema": true
                    }
                ]
            }
        },
        {
            "type": "microsoft.insights/scheduledqueryrules",
            "apiVersion": "2023-03-15-preview",
            "name": "[parameters('Quota_Alert_Name')]",
            "location": "[parameters('Dimensions_Location')]",
            "identity": {
                "type": "UserAssigned",
                "userAssignedIdentities": {
                    "[parameters('User_Managed_Identity')]": {}
                }
            },
            "properties": {
                "severity": 4,
                "enabled": true,
                "evaluationFrequency": "PT15M",
                "scopes": [
                    "[parameters('Scopes')]"
                ],
                "windowSize": "PT15M",
                "criteria": {
                    "allOf": [
                        {
                            "query": "arg(\"\").QuotaResources \n| where subscriptionId =~ '9exxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'\n| where type =~ 'microsoft.compute/locations/usages'\n| where isnotempty(properties)\n| mv-expand propertyJson = properties.value limit 400\n| extend\n    usage = propertyJson.currentValue,\n    quota = propertyJson.['limit'],\n    quotaName = tostring(propertyJson.['name'].value)\n| extend usagePercent = toint(usage)*100 / toint(quota)| project-away properties| where location in~ ('eastus')| where quotaName in~ ('cores')",
                            "timeAggregation": "Maximum",
                            "metricMeasureColumn": "usagePercent",
                            "dimensions": [
                                {
                                    "name": "type",
                                    "operator": "Include",
                                    "values": [
                                        "[parameters('Dimensions_Type')]"
                                    ]
                                },
                                {
                                    "name": "location",
                                    "operator": "Include",
                                    "values": [
                                        "[parameters('Dimensions_Location')]"
                                    ]
                                },
                                {
                                    "name": "quotaName",
                                    "operator": "Include",
                                    "values": [
                                        "[parameters('Dimensions_Quota_Name')]"
                                    ]
                                }
                            ],
                            "operator": "GreaterThanOrEqual",
                            "threshold": 80,
                            "failingPeriods": {
                                "numberOfEvaluationPeriods": 1,
                                "minFailingPeriodsToAlert": 1
                            }
                        }
                    ]
                },
                "actions": {
                    "actionGroups": [
                        "[resourceId('microsoft.insights/actionGroups', parameters('Action_Group_Name'))]"
                    ]
                }
            }
        }
    ]
}

This is ARM parameters file, If you don't want to use separate ARM parameters file. You can mention them in the PowerShell  parameters Object as shown in the above PS option 2 example.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "Action_Group_Name": {
            "value": "Action_Group01"
        },
        "Action_Group_ShortName": {
            "value": "actiongroup"
        },
        "Email_Address": {
            "value": "[email protected]"
        },
        "Quota_Alert_Name": {
            "value": "Quota_Alert01"
        },
        "User_Managed_Identity": {
            "value": "/subscriptions/9exxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/vcloud-lab.com/providers/Microsoft.ManagedIdentity/userAssignedIdentities/dev"
        },
        "Scopes": {
            "value": "/subscriptions/9exxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
        },
        "Dimensions_Type": {
            "value": "microsoft.compute/locations/usages"
        },
        "Dimensions_Location": {
            "value": "eastus"
        },
        "Dimensions_Quota_Name": {
            "value": "cores"
        }
    }
}

After deployment completed you can see two resources are create Action Group and Log search alert rule (Schedule query rule).

Azure ARM Templates azure cloud deployment automation PowerShell user assigned Identity log search alert quota alert action group subscription quota alert CPU usage and quota region location configuration.png

Useful Articles
Terraform variable multiple validation advanced blocks example
Terraform variable type list with for_each for loop examples
Terraform convert single string to list or set
Terraform workspaces with example
Terraform map of object for loop with if condition example
Terraform for_each for loop list of object without count example
Terraform using for loop in attribute value without for_each
Part 0: HashiCorp HCP Terraform Cloud backend configuration
Part 1: Create GitHub repository and branches using Terraform
Part 2 Terraform modules using a github.com repository as a source
Part 3 Automating and Planning Azure Resources with Terraform and GitHub Actions
Part 4 GitHub Actions deploy azure resources with Terraform backend
Part 4.1 GitHub Actions deploy azure resources with PowerShell
Part 4.2 GitHub Actions manage Microsoft Azure Cloud with az CLI
Azure OIDC OpenID Connect password less with GitHub Actions
GitHub repository integration with Terraform Cloud to Deploy and Manage Azure
Resolved Terraform Error: POST https api.github.com user repos 401 Requires authentication
Azure DevOps Enable creation of classic build release pipelines grayed out
Adding parameters in Azure DevOps pipelines examples Part 1
Azure Web App Containers Cannot perform credential operations for providers Microsoft.ContainerRegistry ad admin user is disabled, enable it

Go Back

Comment

Blog Search

Page Views

12406357

Follow me on Blogarama