From 70b732609b0799b2f2b8c573850bee023b89cea6 Mon Sep 17 00:00:00 2001 From: austinmccollum Date: Wed, 19 Aug 2026 12:53:55 -0500 Subject: [PATCH] Add VM Insights V2 onboarding scenario with ARM and Bicep templates Adds a parameterized ARM template and an equivalent modular Bicep implementation that onboard an existing Azure VM to VM Insights V2 in a single deployment. Covers managed identity, Azure Monitor workspace, Log Analytics workspace, data collection rule and association, the Azure Monitor Agent extension, and optional recommended alert rules. Six parameter files cover the common standard and per-process scenarios in both ARM and Bicep parameter formats. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 4a30eb2e-5701-4a75-bae0-489b7a8fb2b7 --- .../README.md | 348 ++++++++ .../bicep/main.bicep | 268 +++++++ .../bicep/modules/alert-guest.bicep | 203 +++++ .../bicep/modules/alert-host.bicep | 30 + .../bicep/modules/ama-extension.bicep | 15 + .../bicep/modules/amw.bicep | 10 + .../bicep/modules/dcr-per-process.bicep | 57 ++ .../bicep/modules/dcr-standard.bicep | 37 + .../bicep/modules/dcra.bicep | 15 + .../bicep/modules/log-analytics.bicep | 13 + .../bicep/modules/vm-identity.bicep | 11 + .../bicep/parameters/existing-dcr.bicepparam | 16 + ...rocess-existing-amw-existing-la.bicepparam | 20 + ...per-process-new-all-with-alerts.bicepparam | 21 + .../standard-existing-amw-new-dcr.bicepparam | 16 + .../standard-new-amw-new-dcr.bicepparam | 16 + .../standard-new-amw-with-alerts.bicepparam | 18 + .../parameters/existing-dcr.parameters.json | 19 + ...s-existing-amw-existing-la.parameters.json | 21 + ...rocess-new-all-with-alerts.parameters.json | 22 + ...ndard-existing-amw-new-dcr.parameters.json | 19 + .../standard-new-amw-new-dcr.parameters.json | 19 + ...andard-new-amw-with-alerts.parameters.json | 20 + .../vmi-v2-onboard.json | 746 ++++++++++++++++++ 24 files changed, 1980 insertions(+) create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/README.md create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/main.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-guest.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-host.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/ama-extension.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/amw.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-per-process.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-standard.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcra.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/log-analytics.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/vm-identity.bicep create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/existing-dcr.bicepparam create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-existing-amw-existing-la.bicepparam create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-new-all-with-alerts.bicepparam create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-existing-amw-new-dcr.bicepparam create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-new-dcr.bicepparam create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-with-alerts.bicepparam create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/parameters/existing-dcr.parameters.json create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-existing-amw-existing-la.parameters.json create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-new-all-with-alerts.parameters.json create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-existing-amw-new-dcr.parameters.json create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-new-dcr.parameters.json create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-with-alerts.parameters.json create mode 100644 Scenarios/How to onboard VMs to VM Insights V2/vmi-v2-onboard.json diff --git a/Scenarios/How to onboard VMs to VM Insights V2/README.md b/Scenarios/How to onboard VMs to VM Insights V2/README.md new file mode 100644 index 00000000..b1a8c653 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/README.md @@ -0,0 +1,348 @@ +# VM Insights V2 Onboarding Templates + +ARM and Bicep templates for onboarding Azure Virtual Machines to **VM Insights V2**. A single parameterized template handles all combinations of resource provisioning, metrics tiers, and alert rules. + +## Glossary + +| Term | Meaning | +|------|---------| +| **AMW** | Azure Monitor Workspace. Stores OTel (OpenTelemetry) metrics from the VM | +| **LA** | Log Analytics workspace. Stores `InsightsMetrics` for per-process/detailed metrics | +| **DCR** | Data Collection Rule. Defines which metrics to collect and where to send them | +| **DCRA** | Data Collection Rule Association. Links a DCR to a specific VM | +| **AMA** | Azure Monitor Agent. The VM extension that collects and ships metrics | +| **OTel** | OpenTelemetry. The metrics format used by VM Insights V2 | +| **UAMI** | User-Assigned Managed Identity. Required for PromQL-based guest OS alerts | +| **PromQL** | Prometheus Query Language. Used by guest OS alert rules to query OTel metrics | + +## What This Does + +These templates onboard an **existing** VM to VM Insights V2 by: + +1. Enabling a managed identity on the VM (required by AMA) +2. Optionally creating an Azure Monitor Workspace (AMW) and/or Log Analytics workspace +3. Creating (or reusing) a Data Collection Rule (DCR) for VM Insights metrics +4. Associating the DCR with the VM +5. Installing the Azure Monitor Agent (AMA) extension on the VM +6. Optionally creating recommended alert rules + +### What this does NOT do + +- Create the VM itself, which must already exist +- Create resource groups. All referenced resource groups must already exist +- Create a User-Assigned Managed Identity (UAMI). Create it beforehand if using alerts +- Assign RBAC roles to the UAMI. You must grant Monitoring Reader on the AMW +- Create or attach action groups. Alert rules are created but do not send notifications by default (see [Alert Rules](#alert-rules-when-enabled)) +- Onboard VMSS or Azure Arc-connected machines (VM-only) + +### Cost implications + +- **Standard tier** sends OTel metrics to Azure Monitor Workspace at no additional charge beyond the AMW. +- **Per-process tier** adds more OTel counters and sends `DetailedMetrics` to Log Analytics, which incurs Log Analytics ingestion and retention charges. Review [Azure Monitor pricing](https://azure.microsoft.com/pricing/details/monitor/) before enabling. + +## Choose Your Scenario + +| Scenario | Metrics | Resources created | Parameter file | +|----------|---------|-------------------|----------------| +| **Standard, new everything** | Free | AMW + DCR | `standard-new-amw-new-dcr` | +| **Standard, existing AMW** | Free | DCR only | `standard-existing-amw-new-dcr` | +| **Reuse existing DCR** | Free | DCRA + AMA only (fastest) | `existing-dcr` | +| **Standard + alerts** | Free | AMW + DCR + 8 alert rules | `standard-new-amw-with-alerts` | +| **Per-process, new everything + alerts** | Paid | AMW + LA + DCR + 8 alert rules | `per-process-new-all-with-alerts` | +| **Per-process, existing infra** | Paid | DCR only (reuses AMW + LA) | `per-process-existing-amw-existing-la` | + +## Prerequisites + +- **Azure subscription** with Contributor role (or equivalent) to create resources +- **Azure CLI** v2.20+ ([install guide](https://learn.microsoft.com/cli/azure/install-azure-cli)), which includes Bicep support +- **An existing VM** to onboard +- **All referenced resource groups** must already exist (the template does not create them) +- If enabling alerts: + 1. Create a [User-Assigned Managed Identity](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/how-manage-user-assigned-managed-identities): + ```bash + az identity create --name --resource-group --location + ``` + 2. Grant it **Monitoring Reader** on the Azure Monitor Workspace: + ```bash + # Get the UAMI principal ID + UAMI_PRINCIPAL_ID=$(az identity show --name --resource-group --query principalId -o tsv) + + # Assign Monitoring Reader on the AMW + az role assignment create \ + --assignee-object-id $UAMI_PRINCIPAL_ID \ + --assignee-principal-type ServicePrincipal \ + --role "Monitoring Reader" \ + --scope + ``` + +## Deploy + +### Step 1: Fill in parameters + +Copy the parameter file for your scenario and replace all `` values: + +```jsonc +// Example: parameters/standard-new-amw-new-dcr.parameters.json +{ + "parameters": { + "vmName": { "value": "my-vm" }, + "vmResourceGroup": { "value": "my-rg" }, + "vmSubscriptionId": { "value": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }, + "location": { "value": "eastus2" }, + "osType": { "value": "Linux" }, + "createNewAmw": { "value": true }, + "amwName": { "value": "my-amw" }, + "createNewDcr": { "value": true } + } +} +``` + +### Step 2: Run the deployment + +#### ARM template (Azure CLI) + +```bash +az deployment group create \ + --resource-group \ + --template-file vmi-v2-onboard.json \ + --parameters @parameters/standard-new-amw-new-dcr.parameters.json +``` + +> **Why `az deployment group create`?** The ARM JSON template is deployed at resource-group scope. It uses nested `Microsoft.Resources/deployments` with explicit `subscriptionId` and `resourceGroup` on each resource to place them in the correct resource groups (VM RG, AMW RG, DCR RG, etc.). The `--resource-group` value is simply the parent deployment's home resource group. Use the VM resource group. + +#### ARM template (PowerShell) + +```powershell +New-AzResourceGroupDeployment ` + -ResourceGroupName ` + -TemplateFile vmi-v2-onboard.json ` + -TemplateParameterFile parameters\standard-new-amw-new-dcr.parameters.json +``` + +#### Bicep + +```bash +az deployment sub create \ + --location \ + --template-file bicep/main.bicep \ + --parameters bicep/parameters/standard-new-amw-new-dcr.bicepparam +``` + +> **Why `az deployment sub create`?** The Bicep template uses `targetScope = 'subscription'` because its modules deploy into potentially different resource groups. This requires a subscription-level deployment. + +#### Inline parameters (no parameter file) + +```bash +az deployment group create \ + --resource-group my-rg \ + --template-file vmi-v2-onboard.json \ + --parameters vmName=my-vm vmResourceGroup=my-rg \ + vmSubscriptionId=$(az account show --query id -o tsv) \ + location=eastus2 osType=Linux \ + createNewAmw=true amwName=my-amw \ + createNewDcr=true +``` + +> **ARM and Bicep deploy the same resources.** The only operational difference is deployment scope: ARM JSON is orchestrated from a resource-group deployment using nested deployments, while Bicep is authored at subscription scope because its modules target multiple resource groups. + +### Step 3: Verify + +After deployment, confirm onboarding succeeded: + +```bash +# Check AMA extension is installed (use AzureMonitorWindowsAgent for Windows VMs) +az vm extension show \ + --resource-group --vm-name \ + --name AzureMonitorLinuxAgent \ + --query "{name:name, status:provisioningState}" -o table + +# Check the DCR association exists +az monitor data-collection rule association list \ + --resource "/subscriptions//resourceGroups//providers/Microsoft.Compute/virtualMachines/" \ + --query "[].{name:name, ruleId:dataCollectionRuleId}" -o table +``` + +In the Azure portal: +- **VM > Extensions**: AMA extension should show "Provisioning succeeded" +- **VM > Monitoring > Data collection rules**: DCR association should appear +- **Azure Monitor > Metrics** (AMW): OTel metrics should appear within ~5 minutes +- If per-process: **Log Analytics workspace > Logs**: query `InsightsMetrics | take 10` +- If alerts: **Monitor > Alerts > Alert rules**: 8 alert rules should be listed + +## Common Scenarios + +### Onboard multiple VMs to the same DCR + +Deploy the first VM with a new DCR, then reuse it for additional VMs: + +```bash +# First VM, creates AMW + DCR +az deployment group create --resource-group my-rg \ + --template-file vmi-v2-onboard.json \ + --parameters @parameters/standard-new-amw-new-dcr.parameters.json + +# Subsequent VMs, reuse the existing DCR +az deployment group create --resource-group my-rg \ + --template-file vmi-v2-onboard.json \ + --parameters vmName=vm-2 vmResourceGroup=my-rg \ + vmSubscriptionId=xxxx location=eastus2 osType=Linux \ + createNewAmw=false createNewDcr=false \ + existingDcrId="/subscriptions//resourceGroups//providers/Microsoft.Insights/dataCollectionRules/msvmi-eastus2-vm-1" +``` + +### Onboard a Windows VM with per-process metrics and alerts + +```bash +az deployment group create --resource-group my-rg \ + --template-file vmi-v2-onboard.json \ + --parameters vmName=my-windows-vm vmResourceGroup=my-rg \ + vmSubscriptionId=xxxx location=eastus2 osType=Windows \ + createNewAmw=true amwName=my-amw \ + createNewLogAnalyticsWorkspace=true logAnalyticsWorkspaceName=my-la \ + createNewDcr=true enablePerProcessMetrics=true \ + enableAlerts=true \ + uamiResourceId="/subscriptions//resourceGroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-uami" +``` + +## Parameter Reference + +### Required (always) + +| Parameter | Type | Description | +|-----------|------|-------------| +| `vmName` | string | Name of the existing VM to onboard | +| `vmResourceGroup` | string | Resource group containing the VM | +| `vmSubscriptionId` | string | Subscription ID of the VM | +| `location` | string | Azure region, must match the VM (e.g. `eastus2`) | + +### VM & Identity + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `osType` | string | `Linux` | `Windows` or `Linux`, determines the AMA extension type | +| `enableSystemAssignedIdentity` | bool | `true` | Enable system-assigned managed identity (required by AMA) | +| `identityType` | string | `SystemAssigned` | Use `SystemAssigned, UserAssigned` if the VM already has user-assigned identities | + +> ⚠️ **Warning:** Setting `identityType=SystemAssigned` on a VM that already uses user-assigned identities may disrupt existing identity configuration. Use `SystemAssigned, UserAssigned` to preserve existing UAMIs. + +### Azure Monitor Workspace + +| Parameter | Type | Default | Required when | +|-----------|------|---------|---------------| +| `createNewAmw` | bool | `false` | n/a | +| `amwName` | string | `""` | `createNewAmw=true` | +| `amwResourceGroup` | string | VM RG | `createNewAmw=true` (optional, defaults to VM RG) | +| `existingAmwResourceId` | string | `""` | `createNewAmw=false` AND `createNewDcr=true` | + +### Log Analytics Workspace + +Only relevant when `enablePerProcessMetrics=true`. + +| Parameter | Type | Default | Required when | +|-----------|------|---------|---------------| +| `createNewLogAnalyticsWorkspace` | bool | `false` | n/a | +| `logAnalyticsWorkspaceName` | string | `""` | `enablePerProcessMetrics=true` AND `createNewLogAnalyticsWorkspace=true` | +| `logAnalyticsResourceGroup` | string | VM RG | (optional, defaults to VM RG) | +| `existingLogAnalyticsWorkspaceId` | string | `""` | `enablePerProcessMetrics=true` AND `createNewLogAnalyticsWorkspace=false` | + +### Data Collection Rule + +| Parameter | Type | Default | Required when | +|-----------|------|---------|---------------| +| `createNewDcr` | bool | `true` | n/a | +| `dcrName` | string | `msvmi-{location}-{vmName}` | `createNewDcr=true` (optional, has default) | +| `dcrResourceGroup` | string | VM RG | `createNewDcr=true` (optional, defaults to VM RG) | +| `existingDcrId` | string | `""` | `createNewDcr=false` | + +> ⚠️ **Existing DCR requirements:** When reusing an existing DCR, it must already be configured for VM Insights V2. For standard metrics, the DCR must include `performanceCountersOTel` with stream `Microsoft-OtelPerfMetrics` and an AMW destination. For per-process metrics, it must also include the relevant `process.*` counters and a Log Analytics destination for `InsightsMetrics`. The DCR must be in the same region as the VM. + +### Metrics & Alerts + +| Parameter | Type | Default | Required when | +|-----------|------|---------|---------------| +| `enablePerProcessMetrics` | bool | `false` | n/a | +| `enableAlerts` | bool | `false` | n/a | +| `uamiResourceId` | string | `""` | `enableAlerts=true` | + +## What Gets Deployed + +### Standard (free) tier + +``` +VM ← AMA Extension +VM ← DCRA (VirtualMachineInsightsExtension) + └── DCR (performanceCountersOTel) + 10 system.* OTel metrics → AMW +``` + +**OTel counters:** `system.cpu.time`, `system.memory.usage`, `system.disk.io`, `system.disk.operations`, `system.disk.operation_time`, `system.filesystem.usage`, `system.network.io`, `system.network.dropped`, `system.network.errors`, `system.uptime` + +### Per-process (paid) tier + +``` +VM ← AMA Extension +VM ← DCRA (VirtualMachineInsightsExtension) + └── DCR (combined) + ├── performanceCountersOTel + │ 25+ counters (system.* + process.*) → AMW + └── performanceCounters + \VmInsights\DetailedMetrics → LA Workspace +``` + +**Additional per-process counters:** `process.uptime`, `process.cpu.time`, `process.cpu.utilization`, `process.memory.usage`, `process.memory.virtual`, `process.memory.utilization`, `process.disk.io`, `process.disk.operations`, `process.paging.faults`, `process.open_file_descriptors`, `process.threads`, `process.handles`, `process.context_switches`, `process.signals_pending`, `system.processes.count`, `system.processes.created` + +### Alert rules (when enabled) + +| Alert | Type | Condition | +|-------|------|-----------| +| **VM Availability** | Platform metric | Availability < 1 over 5 min | +| **Guest OS CPU Usage** | PromQL | CPU utilization > 80% over 5 min | +| **Guest OS Memory Usage** | PromQL | Available memory < 1 GB over 5 min | +| **Guest OS Disk IOPS** | PromQL | Disk operations > 5000/sec over 5 min | +| **Guest OS Network In** | PromQL | Inbound traffic > 100 GB/day | +| **Guest OS Network Out** | PromQL | Outbound traffic > 50 GB/day | +| **Guest OS Network Errors** | PromQL | Network errors > 10 in 5 min | +| **Guest OS Disk Operation Time** | PromQL | Avg disk op time > 100ms over 5 min | + +All guest OS alerts use a 2-minute failing period and auto-resolve after 2 minutes. VM Availability is a platform metric alert (no UAMI needed); all guest OS alerts use PromQL and require a UAMI with Monitoring Reader on the AMW. + +> ⚠️ **No notifications by default.** Alert rules are created without action groups, so no email/SMS/webhook notifications are sent when alerts fire. To receive notifications, [attach an action group](https://learn.microsoft.com/azure/azure-monitor/alerts/action-groups) to each alert rule after deployment, or extend the template to include action group references. + +## ARM vs Bicep: Which to Use? + +| | ARM (`vmi-v2-onboard.json`) | Bicep (`bicep/main.bicep`) | +|---|---|---| +| **Best for** | Portal "Deploy a custom template", REST API, existing ARM pipelines | Azure CLI, CI/CD pipelines, composing into larger deployments | +| **Single file** | ✅ One JSON file | ❌ Main + 8 modules | +| **Readability** | Verbose JSON | Concise, commented | +| **Extensibility** | Edit one large file | Add/swap modules independently | + +The Bicep modules in `bicep/modules/` can also be referenced individually from your own Bicep templates if you only need specific pieces (e.g., just the DCR or just the alerts). + +## Repository Structure + +``` +├── vmi-v2-onboard.json # ARM: parameterized template +├── parameters/ # ARM: parameter files for common scenarios +│ ├── standard-new-amw-new-dcr.parameters.json +│ ├── standard-existing-amw-new-dcr.parameters.json +│ ├── existing-dcr.parameters.json +│ ├── standard-new-amw-with-alerts.parameters.json +│ ├── per-process-new-all-with-alerts.parameters.json +│ └── per-process-existing-amw-existing-la.parameters.json +├── bicep/ # Bicep: modular equivalent +│ ├── main.bicep # orchestrator +│ ├── modules/ # individual resource modules +│ │ ├── vm-identity.bicep +│ │ ├── amw.bicep +│ │ ├── log-analytics.bicep +│ │ ├── dcr-standard.bicep +│ │ ├── dcr-per-process.bicep +│ │ ├── dcra.bicep +│ │ ├── ama-extension.bicep +│ │ ├── alert-host.bicep +│ │ └── alert-guest.bicep +│ └── parameters/ # .bicepparam files +│ └── (same scenarios as ARM) +└── README.md +``` diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/main.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/main.bicep new file mode 100644 index 00000000..39f6048e --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/main.bicep @@ -0,0 +1,268 @@ +// ============================================================================ +// VM Insights V2 Onboarding (Bicep) +// +// Single parameterized template covering: +// - New or existing Azure Monitor Workspace (AMW) +// - New or existing Log Analytics workspace (for per-process metrics) +// - New or existing Data Collection Rule (DCR) +// - Standard (free) or per-process (paid) metrics tier +// - Optional recommended alert rules +// ============================================================================ + +targetScope = 'subscription' + +// --------------------------------------------------------------------------- +// VM Configuration +// --------------------------------------------------------------------------- + +@description('Name of the existing virtual machine to onboard.') +param vmName string + +@description('Resource group containing the VM.') +param vmResourceGroup string + +@description('Subscription ID of the VM.') +param vmSubscriptionId string + +@description('Azure region (must match VM location, e.g. eastus2).') +param location string + +@allowed(['Windows', 'Linux']) +@description('OS type of the VM, which determines the AMA extension to install.') +param osType string = 'Linux' + +// --------------------------------------------------------------------------- +// Managed Identity +// --------------------------------------------------------------------------- + +@description('Enable system-assigned managed identity on the VM (required by AMA). Safe to set true even if already enabled.') +param enableSystemAssignedIdentity bool = true + +@allowed(['SystemAssigned', 'SystemAssigned, UserAssigned']) +@description('Use "SystemAssigned, UserAssigned" if the VM already has user-assigned identities to avoid overwriting them.') +param identityType string = 'SystemAssigned' + +// --------------------------------------------------------------------------- +// Azure Monitor Workspace +// --------------------------------------------------------------------------- + +@description('Set to true to create a new Azure Monitor Workspace. Set to false to use an existing one via existingAmwResourceId.') +param createNewAmw bool = false + +@description('Name for the new Azure Monitor Workspace. Required when createNewAmw=true.') +param amwName string = '' + +@description('Resource group for the new AMW. Defaults to VM resource group.') +param amwResourceGroup string = vmResourceGroup + +@description('Full resource ID of an existing Azure Monitor Workspace. Required when createNewAmw=false.') +param existingAmwResourceId string = '' + +// --------------------------------------------------------------------------- +// Log Analytics Workspace (required for per-process metrics) +// --------------------------------------------------------------------------- + +@description('Set to true to create a new Log Analytics workspace. Only used when enablePerProcessMetrics=true.') +param createNewLogAnalyticsWorkspace bool = false + +@description('Name for the new Log Analytics workspace. Required when createNewLogAnalyticsWorkspace=true.') +param logAnalyticsWorkspaceName string = '' + +@description('Resource group for the new Log Analytics workspace. Defaults to VM resource group.') +param logAnalyticsResourceGroup string = vmResourceGroup + +@description('Full resource ID of an existing Log Analytics workspace. Required when enablePerProcessMetrics=true and createNewLogAnalyticsWorkspace=false.') +param existingLogAnalyticsWorkspaceId string = '' + +// --------------------------------------------------------------------------- +// Data Collection Rule +// --------------------------------------------------------------------------- + +@description('Set to true to create a new Data Collection Rule. Set to false to use an existing one via existingDcrId.') +param createNewDcr bool = true + +@description('Name for the new DCR. Defaults to msvmi-{location}-{vmName}.') +param dcrName string = 'msvmi-${location}-${vmName}' + +@description('Resource group for the new DCR. Defaults to VM resource group.') +param dcrResourceGroup string = vmResourceGroup + +@description('Full resource ID of an existing DCR. Required when createNewDcr=false.') +param existingDcrId string = '' + +// --------------------------------------------------------------------------- +// Metrics Tier +// --------------------------------------------------------------------------- + +@description('Enable per-process metrics (paid tier). Adds process.* OTel counters and InsightsMetrics/DetailedMetrics via Log Analytics. Requires a Log Analytics workspace.') +param enablePerProcessMetrics bool = false + +// --------------------------------------------------------------------------- +// Alerts +// --------------------------------------------------------------------------- + +@description('Create recommended VM Insights alert rules (VM Availability + guest OS alerts for CPU, memory, disk, network).') +param enableAlerts bool = false + +@description('Full resource ID of a User-Assigned Managed Identity for guest OS PromQL-based alerts. Required when enableAlerts=true.') +param uamiResourceId string = '' + +// --------------------------------------------------------------------------- +// Computed values +// --------------------------------------------------------------------------- + +var vmResourceId = '/subscriptions/${vmSubscriptionId}/resourceGroups/${vmResourceGroup}/providers/Microsoft.Compute/virtualMachines/${vmName}' +var amaExtensionType = osType == 'Windows' ? 'AzureMonitorWindowsAgent' : 'AzureMonitorLinuxAgent' + +var amwResourceId = createNewAmw + ? '/subscriptions/${vmSubscriptionId}/resourceGroups/${amwResourceGroup}/providers/microsoft.monitor/accounts/${amwName}' + : existingAmwResourceId + +var logAnalyticsWorkspaceId = createNewLogAnalyticsWorkspace + ? '/subscriptions/${vmSubscriptionId}/resourceGroups/${logAnalyticsResourceGroup}/providers/microsoft.operationalinsights/workspaces/${logAnalyticsWorkspaceName}' + : existingLogAnalyticsWorkspaceId + +var dcrResourceId = createNewDcr + ? '/subscriptions/${vmSubscriptionId}/resourceGroups/${dcrResourceGroup}/providers/Microsoft.Insights/dataCollectionRules/${dcrName}' + : existingDcrId + +var standardOtelCounters = [ + 'system.filesystem.usage' + 'system.disk.io' + 'system.disk.operation_time' + 'system.disk.operations' + 'system.memory.usage' + 'system.network.io' + 'system.cpu.time' + 'system.network.dropped' + 'system.network.errors' + 'system.uptime' +] + +var processOtelCounters = [ + 'process.uptime' + 'process.cpu.time' + 'process.cpu.utilization' + 'process.memory.usage' + 'process.memory.virtual' + 'process.memory.utilization' + 'process.disk.io' + 'process.disk.operations' + 'process.paging.faults' + 'process.open_file_descriptors' + 'process.threads' + 'process.handles' + 'process.context_switches' + 'process.signals_pending' + 'system.processes.count' + 'system.processes.created' +] + +var allOtelCounters = concat(standardOtelCounters, processOtelCounters) + +// ============================================================================ +// Module deployments (scoped to their respective resource groups) +// ============================================================================ + +// --- Enable system-assigned managed identity on the VM --- +module enableIdentity 'modules/vm-identity.bicep' = if (enableSystemAssignedIdentity) { + name: 'EnableVMSystemIdentity' + scope: resourceGroup(vmSubscriptionId, vmResourceGroup) + params: { + vmName: vmName + location: location + identityType: identityType + } +} + +// --- Create a new Azure Monitor Workspace --- +module createAmw 'modules/amw.bicep' = if (createNewAmw) { + name: 'CreateAMW' + scope: resourceGroup(vmSubscriptionId, amwResourceGroup) + params: { + amwName: amwName + location: location + } +} + +// --- Create a new Log Analytics workspace (for per-process metrics) --- +module createLa 'modules/log-analytics.bicep' = if (createNewLogAnalyticsWorkspace && enablePerProcessMetrics) { + name: 'CreateLogAnalyticsWorkspace' + scope: resourceGroup(vmSubscriptionId, logAnalyticsResourceGroup) + params: { + workspaceName: logAnalyticsWorkspaceName + location: location + } +} + +// --- DCR: Standard OTel metrics only (free tier) --- +module createStandardDcr 'modules/dcr-standard.bicep' = if (createNewDcr && !enablePerProcessMetrics) { + name: 'CreateStandardDCR' + scope: resourceGroup(vmSubscriptionId, dcrResourceGroup) + dependsOn: [createAmw] + params: { + dcrName: dcrName + location: location + amwResourceId: amwResourceId + counterSpecifiers: standardOtelCounters + } +} + +// --- DCR: Per-process metrics (paid tier) --- +module createPerProcessDcr 'modules/dcr-per-process.bicep' = if (createNewDcr && enablePerProcessMetrics) { + name: 'CreatePerProcessDCR' + scope: resourceGroup(vmSubscriptionId, dcrResourceGroup) + dependsOn: [createAmw, createLa] + params: { + dcrName: dcrName + location: location + amwResourceId: amwResourceId + logAnalyticsWorkspaceId: logAnalyticsWorkspaceId + counterSpecifiers: allOtelCounters + } +} + +// --- Associate DCR with VM --- +module createDcra 'modules/dcra.bicep' = { + name: 'CreateDCRA' + scope: resourceGroup(vmSubscriptionId, vmResourceGroup) + dependsOn: [createStandardDcr, createPerProcessDcr] + params: { + vmResourceId: vmResourceId + dcrResourceId: dcrResourceId + } +} + +// --- Install Azure Monitor Agent extension --- +module installAma 'modules/ama-extension.bicep' = { + name: 'InstallAMAExtension' + scope: resourceGroup(vmSubscriptionId, vmResourceGroup) + dependsOn: [createDcra, enableIdentity] + params: { + vmName: vmName + location: location + amaExtensionType: amaExtensionType + } +} + +// --- Host alert: VM Availability --- +module hostAlerts 'modules/alert-host.bicep' = if (enableAlerts) { + name: 'CreateHostAlertRules' + scope: resourceGroup(vmSubscriptionId, vmResourceGroup) + params: { + vmName: vmName + vmResourceId: vmResourceId + } +} + +// --- Guest OS alerts (PromQL-based, requires UAMI) --- +module guestAlerts 'modules/alert-guest.bicep' = if (enableAlerts) { + name: 'CreateGuestAlertRules' + scope: resourceGroup(vmSubscriptionId, vmResourceGroup) + params: { + vmName: vmName + location: location + vmResourceId: vmResourceId + uamiResourceId: uamiResourceId + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-guest.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-guest.bicep new file mode 100644 index 00000000..93772e47 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-guest.bicep @@ -0,0 +1,203 @@ +param vmName string +param location string +param vmResourceId string +param uamiResourceId string + +var uamiIdentity = { + type: 'UserAssigned' + userAssignedIdentities: { + '${uamiResourceId}': {} + } +} + +var failingPeriods = { for: 'PT2M' } +var resolveConfig = { autoResolved: true, timeToResolve: 'PT2M' } + +// --- Guest OS CPU Usage --- +resource cpuAlert 'Microsoft.Insights/metricAlerts@2024-03-01-preview' = { + name: 'Guest OS CPU Usage - ${vmName}' + location: location + identity: uamiIdentity + properties: { + description: 'CPU usage has exceeded 80% threshold over the last 5 minutes' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT1M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.PromQLCriteria' + allOf: [ + { + name: 'Metric1' + query: 'avg_over_time(((sum (irate({"system.cpu.time","state" !~ "idle|iowait|steal"}[2m]))) / (sum (irate({"system.cpu.time"}[2m]))))[5m:]) * 100 > 80' + criterionType: 'StaticThresholdCriterion' + } + ] + failingPeriods: failingPeriods + } + resolveConfiguration: resolveConfig + actions: [] + } +} + +// --- Guest OS Memory Usage --- +resource memoryAlert 'Microsoft.Insights/metricAlerts@2024-03-01-preview' = { + name: 'Guest OS Memory Usage - ${vmName}' + location: location + identity: uamiIdentity + properties: { + description: 'Available memory has dropped below 1 GB over the last 5 minutes' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT1M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.PromQLCriteria' + allOf: [ + { + name: 'Metric1' + query: 'min_over_time((sum ({"system.memory.usage", state=~"free|cached|buffered|slab_reclaimable"}))[5m:]) < (1 * 1024 * 1024 * 1024)' + criterionType: 'StaticThresholdCriterion' + } + ] + failingPeriods: failingPeriods + } + resolveConfiguration: resolveConfig + actions: [] + } +} + +// --- Guest OS Disk IOPS --- +resource diskIopsAlert 'Microsoft.Insights/metricAlerts@2024-03-01-preview' = { + name: 'Guest OS Disk IOPS - ${vmName}' + location: location + identity: uamiIdentity + properties: { + description: 'Disk IOPS has exceeded 5000 operations per second over the last 5 minutes' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT1M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.PromQLCriteria' + allOf: [ + { + name: 'Metric1' + query: 'max_over_time((sum (irate({"system.disk.operations"}[2m])))[5m:]) > 5000' + criterionType: 'StaticThresholdCriterion' + } + ] + failingPeriods: failingPeriods + } + resolveConfiguration: resolveConfig + actions: [] + } +} + +// --- Guest OS Network In --- +resource networkInAlert 'Microsoft.Insights/metricAlerts@2024-03-01-preview' = { + name: 'Guest OS Network In - ${vmName}' + location: location + identity: uamiIdentity + properties: { + description: 'Total network inbound traffic has exceeded 100 GB over the last day' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT1M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.PromQLCriteria' + allOf: [ + { + name: 'Metric1' + query: 'sum_over_time((sum (irate({"system.network.io", direction="receive"}[2m])))[1d:]) > (100 * 1024 * 1024 * 1024)' + criterionType: 'StaticThresholdCriterion' + } + ] + failingPeriods: failingPeriods + } + resolveConfiguration: resolveConfig + actions: [] + } +} + +// --- Guest OS Network Out --- +resource networkOutAlert 'Microsoft.Insights/metricAlerts@2024-03-01-preview' = { + name: 'Guest OS Network Out - ${vmName}' + location: location + identity: uamiIdentity + properties: { + description: 'Total network outbound traffic has exceeded 50 GB over the last day' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT1M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.PromQLCriteria' + allOf: [ + { + name: 'Metric1' + query: 'sum_over_time((sum (irate({"system.network.io", direction="transmit"}[2m])))[1d:]) > (50 * 1024 * 1024 * 1024)' + criterionType: 'StaticThresholdCriterion' + } + ] + failingPeriods: failingPeriods + } + resolveConfiguration: resolveConfig + actions: [] + } +} + +// --- Guest OS Network Errors --- +resource networkErrorsAlert 'Microsoft.Insights/metricAlerts@2024-03-01-preview' = { + name: 'Guest OS Network Errors - ${vmName}' + location: location + identity: uamiIdentity + properties: { + description: 'Network errors have exceeded 10 total errors over the last 5 minutes' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT1M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.PromQLCriteria' + allOf: [ + { + name: 'Metric1' + query: 'sum_over_time((sum (irate({"system.network.errors"}[2m])))[5m:]) > 10' + criterionType: 'StaticThresholdCriterion' + } + ] + failingPeriods: failingPeriods + } + resolveConfiguration: resolveConfig + actions: [] + } +} + +// --- Guest OS Disk Operation Time --- +resource diskOpTimeAlert 'Microsoft.Insights/metricAlerts@2024-03-01-preview' = { + name: 'Guest OS Disk Operation Time - ${vmName}' + location: location + identity: uamiIdentity + properties: { + description: 'Average disk operation time has exceeded 100ms over the last 5 minutes' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT1M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.PromQLCriteria' + allOf: [ + { + name: 'Metric1' + query: 'avg_over_time(((sum (irate({"system.disk.operation_time"}[2m]))) / (sum (irate({"system.disk.operations"}[2m]))))[5m:]) * 1000 > 100' + criterionType: 'StaticThresholdCriterion' + } + ] + failingPeriods: failingPeriods + } + resolveConfiguration: resolveConfig + actions: [] + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-host.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-host.bicep new file mode 100644 index 00000000..361f961f --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/alert-host.bicep @@ -0,0 +1,30 @@ +param vmName string +param vmResourceId string + +resource vmAvailabilityAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = { + name: 'VM Availability - ${vmName}' + location: 'global' + properties: { + description: 'VM is unavailable or not responding' + severity: 3 + enabled: true + scopes: [vmResourceId] + evaluationFrequency: 'PT5M' + windowSize: 'PT5M' + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria' + allOf: [ + { + name: 'Metric1' + metricName: 'VmAvailabilityMetric' + metricNamespace: 'Microsoft.Compute/virtualMachines' + operator: 'LessThan' + threshold: 1 + timeAggregation: 'Average' + criterionType: 'StaticThresholdCriterion' + } + ] + } + actions: [] + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/ama-extension.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/ama-extension.bicep new file mode 100644 index 00000000..753b24b6 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/ama-extension.bicep @@ -0,0 +1,15 @@ +param vmName string +param location string +param amaExtensionType string + +resource amaExtension 'Microsoft.Compute/virtualMachines/extensions@2022-11-01' = { + name: '${vmName}/${amaExtensionType}' + location: location + properties: { + publisher: 'Microsoft.Azure.Monitor' + type: amaExtensionType + typeHandlerVersion: '1.0' + autoUpgradeMinorVersion: true + enableAutomaticUpgrade: true + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/amw.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/amw.bicep new file mode 100644 index 00000000..5f487c81 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/amw.bicep @@ -0,0 +1,10 @@ +param amwName string +param location string + +resource amw 'microsoft.monitor/accounts@2023-04-03' = { + name: amwName + location: location + properties: {} +} + +output amwResourceId string = amw.id diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-per-process.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-per-process.bicep new file mode 100644 index 00000000..51985cba --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-per-process.bicep @@ -0,0 +1,57 @@ +param dcrName string +param location string +param amwResourceId string +param logAnalyticsWorkspaceId string +param counterSpecifiers array + +resource dcr 'Microsoft.Insights/dataCollectionRules@2024-03-11' = { + name: dcrName + location: location + properties: { + dataSources: { + performanceCounters: [ + { + name: 'Microsoft-InsightsMetrics' + streams: ['Microsoft-InsightsMetrics'] + scheduledTransferPeriod: 'PT1M' + samplingFrequencyInSeconds: 60 + counterSpecifiers: ['\\VmInsights\\DetailedMetrics'] + } + ] + performanceCountersOTel: [ + { + name: 'OtelDataSource' + streams: ['Microsoft-OtelPerfMetrics'] + samplingFrequencyInSeconds: 60 + counterSpecifiers: counterSpecifiers + } + ] + } + destinations: { + logAnalytics: [ + { + workspaceResourceId: logAnalyticsWorkspaceId + name: 'vmInsightworkspace' + } + ] + monitoringAccounts: [ + { + accountResourceId: amwResourceId + name: 'MonitoringAccountDestination' + } + ] + } + dataFlows: [ + { + streams: ['Microsoft-InsightsMetrics'] + destinations: ['vmInsightworkspace'] + } + { + streams: ['Microsoft-OtelPerfMetrics'] + destinations: ['MonitoringAccountDestination'] + } + ] + } +} + +output dcrId string = dcr.id diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-standard.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-standard.bicep new file mode 100644 index 00000000..fbdc479d --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcr-standard.bicep @@ -0,0 +1,37 @@ +param dcrName string +param location string +param amwResourceId string +param counterSpecifiers array + +resource dcr 'Microsoft.Insights/dataCollectionRules@2024-03-11' = { + name: dcrName + location: location + properties: { + dataSources: { + performanceCountersOTel: [ + { + name: 'OtelDataSource' + streams: ['Microsoft-OtelPerfMetrics'] + samplingFrequencyInSeconds: 60 + counterSpecifiers: counterSpecifiers + } + ] + } + destinations: { + monitoringAccounts: [ + { + accountResourceId: amwResourceId + name: 'MonitoringAccountDestination' + } + ] + } + dataFlows: [ + { + streams: ['Microsoft-OtelPerfMetrics'] + destinations: ['MonitoringAccountDestination'] + } + ] + } +} + +output dcrId string = dcr.id diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcra.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcra.bicep new file mode 100644 index 00000000..d5c4a140 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/dcra.bicep @@ -0,0 +1,15 @@ +param vmResourceId string +param dcrResourceId string + +resource dcra 'Microsoft.Insights/dataCollectionRuleAssociations@2022-06-01' = { + name: 'VirtualMachineInsightsExtension' + scope: existing_vm + properties: { + description: 'Association of data collection rule. Deleting this association will break the data collection for this virtual machine.' + dataCollectionRuleId: dcrResourceId + } +} + +resource existing_vm 'Microsoft.Compute/virtualMachines@2022-11-01' existing = { + name: last(split(vmResourceId, '/')) +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/log-analytics.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/log-analytics.bicep new file mode 100644 index 00000000..c056b52f --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/log-analytics.bicep @@ -0,0 +1,13 @@ +param workspaceName string +param location string + +resource workspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: workspaceName + location: location + properties: { + sku: { name: 'PerGB2018' } + retentionInDays: 30 + } +} + +output workspaceId string = workspace.id diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/vm-identity.bicep b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/vm-identity.bicep new file mode 100644 index 00000000..60135b09 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/modules/vm-identity.bicep @@ -0,0 +1,11 @@ +param vmName string +param location string +param identityType string + +resource vm 'Microsoft.Compute/virtualMachines@2022-11-01' = { + name: vmName + location: location + identity: { + type: identityType + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/existing-dcr.bicepparam b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/existing-dcr.bicepparam new file mode 100644 index 00000000..7a529cb4 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/existing-dcr.bicepparam @@ -0,0 +1,16 @@ +using '../main.bicep' + +// Reuse existing DCR, the fastest onboarding path + +param vmName = '' +param vmResourceGroup = '' +param vmSubscriptionId = '' +param location = '' +param osType = 'Linux' + +param createNewAmw = false +param createNewDcr = false +param existingDcrId = '/subscriptions//resourceGroups//providers/Microsoft.Insights/dataCollectionRules/' + +param enablePerProcessMetrics = false +param enableAlerts = false diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-existing-amw-existing-la.bicepparam b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-existing-amw-existing-la.bicepparam new file mode 100644 index 00000000..452ebdbd --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-existing-amw-existing-la.bicepparam @@ -0,0 +1,20 @@ +using '../main.bicep' + +// Per-process (paid) tier: existing AMW + existing LA, new DCR, no alerts + +param vmName = '' +param vmResourceGroup = '' +param vmSubscriptionId = '' +param location = '' +param osType = 'Linux' + +param createNewAmw = false +param existingAmwResourceId = '/subscriptions//resourceGroups//providers/microsoft.monitor/accounts/' + +param createNewLogAnalyticsWorkspace = false +param existingLogAnalyticsWorkspaceId = '/subscriptions//resourceGroups//providers/microsoft.operationalinsights/workspaces/' + +param createNewDcr = true +param enablePerProcessMetrics = true + +param enableAlerts = false diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-new-all-with-alerts.bicepparam b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-new-all-with-alerts.bicepparam new file mode 100644 index 00000000..0fa9ae44 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/per-process-new-all-with-alerts.bicepparam @@ -0,0 +1,21 @@ +using '../main.bicep' + +// Per-process (paid) tier: new AMW + LA + DCR + all alerts + +param vmName = '' +param vmResourceGroup = '' +param vmSubscriptionId = '' +param location = '' +param osType = 'Linux' + +param createNewAmw = true +param amwName = '' + +param createNewLogAnalyticsWorkspace = true +param logAnalyticsWorkspaceName = '' + +param createNewDcr = true +param enablePerProcessMetrics = true + +param enableAlerts = true +param uamiResourceId = '/subscriptions//resourceGroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/' diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-existing-amw-new-dcr.bicepparam b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-existing-amw-new-dcr.bicepparam new file mode 100644 index 00000000..f8f2af17 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-existing-amw-new-dcr.bicepparam @@ -0,0 +1,16 @@ +using '../main.bicep' + +// Standard free-tier: existing AMW, new DCR + +param vmName = '' +param vmResourceGroup = '' +param vmSubscriptionId = '' +param location = '' +param osType = 'Linux' + +param createNewAmw = false +param existingAmwResourceId = '/subscriptions//resourceGroups//providers/microsoft.monitor/accounts/' + +param createNewDcr = true +param enablePerProcessMetrics = false +param enableAlerts = false diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-new-dcr.bicepparam b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-new-dcr.bicepparam new file mode 100644 index 00000000..5a0b7526 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-new-dcr.bicepparam @@ -0,0 +1,16 @@ +using '../main.bicep' + +// Standard free-tier: new AMW + new DCR, no per-process, no alerts + +param vmName = '' +param vmResourceGroup = '' +param vmSubscriptionId = '' +param location = '' +param osType = 'Linux' + +param createNewAmw = true +param amwName = '' + +param createNewDcr = true +param enablePerProcessMetrics = false +param enableAlerts = false diff --git a/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-with-alerts.bicepparam b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-with-alerts.bicepparam new file mode 100644 index 00000000..e5eee9f3 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/bicep/parameters/standard-new-amw-with-alerts.bicepparam @@ -0,0 +1,18 @@ +using '../main.bicep' + +// Standard free-tier with all recommended alerts + +param vmName = '' +param vmResourceGroup = '' +param vmSubscriptionId = '' +param location = '' +param osType = 'Linux' + +param createNewAmw = true +param amwName = '' + +param createNewDcr = true +param enablePerProcessMetrics = false + +param enableAlerts = true +param uamiResourceId = '/subscriptions//resourceGroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/' diff --git a/Scenarios/How to onboard VMs to VM Insights V2/parameters/existing-dcr.parameters.json b/Scenarios/How to onboard VMs to VM Insights V2/parameters/existing-dcr.parameters.json new file mode 100644 index 00000000..c6203faa --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/parameters/existing-dcr.parameters.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Reuse an existing DCR. Only creates the DCRA association and installs the AMA extension. Fastest onboarding for VMs sharing a DCR." + }, + "parameters": { + "vmName": { "value": "" }, + "vmResourceGroup": { "value": "" }, + "vmSubscriptionId": { "value": "" }, + "location": { "value": "" }, + "osType": { "value": "Linux" }, + "createNewAmw": { "value": false }, + "createNewDcr": { "value": false }, + "existingDcrId": { "value": "/subscriptions//resourceGroups//providers/Microsoft.Insights/dataCollectionRules/" }, + "enablePerProcessMetrics": { "value": false }, + "enableAlerts": { "value": false } + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-existing-amw-existing-la.parameters.json b/Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-existing-amw-existing-la.parameters.json new file mode 100644 index 00000000..01849062 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-existing-amw-existing-la.parameters.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Per-process metrics (paid tier) using existing AMW and existing LA workspace. Creates a new DCR. No alerts." + }, + "parameters": { + "vmName": { "value": "" }, + "vmResourceGroup": { "value": "" }, + "vmSubscriptionId": { "value": "" }, + "location": { "value": "" }, + "osType": { "value": "Linux" }, + "createNewAmw": { "value": false }, + "existingAmwResourceId": { "value": "/subscriptions//resourceGroups//providers/microsoft.monitor/accounts/" }, + "createNewLogAnalyticsWorkspace": { "value": false }, + "existingLogAnalyticsWorkspaceId": { "value": "/subscriptions//resourceGroups//providers/microsoft.operationalinsights/workspaces/" }, + "createNewDcr": { "value": true }, + "enablePerProcessMetrics": { "value": true }, + "enableAlerts": { "value": false } + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-new-all-with-alerts.parameters.json b/Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-new-all-with-alerts.parameters.json new file mode 100644 index 00000000..6e9e5fa5 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/parameters/per-process-new-all-with-alerts.parameters.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Per-process metrics (paid tier) with all recommended alerts. Creates new AMW, LA workspace, and DCR with both OTel and InsightsMetrics/DetailedMetrics data sources." + }, + "parameters": { + "vmName": { "value": "" }, + "vmResourceGroup": { "value": "" }, + "vmSubscriptionId": { "value": "" }, + "location": { "value": "" }, + "osType": { "value": "Linux" }, + "createNewAmw": { "value": true }, + "amwName": { "value": "" }, + "createNewLogAnalyticsWorkspace": { "value": true }, + "logAnalyticsWorkspaceName": { "value": "" }, + "createNewDcr": { "value": true }, + "enablePerProcessMetrics": { "value": true }, + "enableAlerts": { "value": true }, + "uamiResourceId": { "value": "/subscriptions//resourceGroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/" } + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-existing-amw-new-dcr.parameters.json b/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-existing-amw-new-dcr.parameters.json new file mode 100644 index 00000000..5e18c753 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-existing-amw-new-dcr.parameters.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Standard free-tier VMI onboarding: creates a new DCR using an existing AMW. No per-process metrics, no alerts." + }, + "parameters": { + "vmName": { "value": "" }, + "vmResourceGroup": { "value": "" }, + "vmSubscriptionId": { "value": "" }, + "location": { "value": "" }, + "osType": { "value": "Linux" }, + "createNewAmw": { "value": false }, + "existingAmwResourceId": { "value": "/subscriptions//resourceGroups//providers/microsoft.monitor/accounts/" }, + "createNewDcr": { "value": true }, + "enablePerProcessMetrics": { "value": false }, + "enableAlerts": { "value": false } + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-new-dcr.parameters.json b/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-new-dcr.parameters.json new file mode 100644 index 00000000..24f7c075 --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-new-dcr.parameters.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Standard free-tier VMI onboarding: creates a new AMW and new DCR with system-level OTel metrics. No per-process metrics, no alerts." + }, + "parameters": { + "vmName": { "value": "" }, + "vmResourceGroup": { "value": "" }, + "vmSubscriptionId": { "value": "" }, + "location": { "value": "" }, + "osType": { "value": "Linux" }, + "createNewAmw": { "value": true }, + "amwName": { "value": "" }, + "createNewDcr": { "value": true }, + "enablePerProcessMetrics": { "value": false }, + "enableAlerts": { "value": false } + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-with-alerts.parameters.json b/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-with-alerts.parameters.json new file mode 100644 index 00000000..59bbe0de --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/parameters/standard-new-amw-with-alerts.parameters.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "description": "Standard free-tier with recommended alerts. Creates new AMW and DCR, plus VM Availability and guest OS alert rules." + }, + "parameters": { + "vmName": { "value": "" }, + "vmResourceGroup": { "value": "" }, + "vmSubscriptionId": { "value": "" }, + "location": { "value": "" }, + "osType": { "value": "Linux" }, + "createNewAmw": { "value": true }, + "amwName": { "value": "" }, + "createNewDcr": { "value": true }, + "enablePerProcessMetrics": { "value": false }, + "enableAlerts": { "value": true }, + "uamiResourceId": { "value": "/subscriptions//resourceGroups//providers/Microsoft.ManagedIdentity/userAssignedIdentities/" } + } +} diff --git a/Scenarios/How to onboard VMs to VM Insights V2/vmi-v2-onboard.json b/Scenarios/How to onboard VMs to VM Insights V2/vmi-v2-onboard.json new file mode 100644 index 00000000..f487993e --- /dev/null +++ b/Scenarios/How to onboard VMs to VM Insights V2/vmi-v2-onboard.json @@ -0,0 +1,746 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "vmName": { + "type": "string", + "metadata": { "description": "Name of the existing virtual machine to onboard." } + }, + "vmResourceGroup": { + "type": "string", + "metadata": { "description": "Resource group containing the VM." } + }, + "vmSubscriptionId": { + "type": "string", + "metadata": { "description": "Subscription ID of the VM." } + }, + "location": { + "type": "string", + "metadata": { "description": "Azure region (must match VM location, e.g. eastus2)." } + }, + "osType": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ "Windows", "Linux" ], + "metadata": { "description": "OS type of the VM, which determines the AMA extension to install." } + }, + "enableSystemAssignedIdentity": { + "type": "bool", + "defaultValue": true, + "metadata": { "description": "Enable system-assigned managed identity on the VM (required by AMA). Safe to set true even if already enabled." } + }, + "identityType": { + "type": "string", + "defaultValue": "SystemAssigned", + "allowedValues": [ "SystemAssigned", "SystemAssigned, UserAssigned" ], + "metadata": { "description": "Use 'SystemAssigned, UserAssigned' if the VM already has user-assigned identities to avoid overwriting them." } + }, + "createNewAmw": { + "type": "bool", + "defaultValue": false, + "metadata": { "description": "Set to true to create a new Azure Monitor Workspace. Set to false to use an existing one via 'existingAmwResourceId'." } + }, + "amwName": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Name for the new Azure Monitor Workspace. Required when createNewAmw=true." } + }, + "amwResourceGroup": { + "type": "string", + "defaultValue": "[parameters('vmResourceGroup')]", + "metadata": { "description": "Resource group for the new AMW. Defaults to VM resource group." } + }, + "existingAmwResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Full resource ID of an existing Azure Monitor Workspace. Required when createNewAmw=false." } + }, + "createNewLogAnalyticsWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { "description": "Set to true to create a new Log Analytics workspace. Only used when enablePerProcessMetrics=true." } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Name for the new Log Analytics workspace. Required when createNewLogAnalyticsWorkspace=true." } + }, + "logAnalyticsResourceGroup": { + "type": "string", + "defaultValue": "[parameters('vmResourceGroup')]", + "metadata": { "description": "Resource group for the new Log Analytics workspace. Defaults to VM resource group." } + }, + "existingLogAnalyticsWorkspaceId": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Full resource ID of an existing Log Analytics workspace. Required when enablePerProcessMetrics=true and createNewLogAnalyticsWorkspace=false." } + }, + "createNewDcr": { + "type": "bool", + "defaultValue": true, + "metadata": { "description": "Set to true to create a new Data Collection Rule. Set to false to use an existing one via 'existingDcrId'." } + }, + "dcrName": { + "type": "string", + "defaultValue": "[concat('msvmi-', parameters('location'), '-', parameters('vmName'))]", + "metadata": { "description": "Name for the new DCR. Defaults to msvmi-{location}-{vmName}." } + }, + "dcrResourceGroup": { + "type": "string", + "defaultValue": "[parameters('vmResourceGroup')]", + "metadata": { "description": "Resource group for the new DCR. Defaults to VM resource group." } + }, + "existingDcrId": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Full resource ID of an existing DCR. Required when createNewDcr=false." } + }, + "enablePerProcessMetrics": { + "type": "bool", + "defaultValue": false, + "metadata": { "description": "Enable per-process metrics (paid tier). Adds process.* OTel counters and InsightsMetrics/DetailedMetrics via Log Analytics. Requires a Log Analytics workspace." } + }, + "enableAlerts": { + "type": "bool", + "defaultValue": false, + "metadata": { "description": "Create recommended VM Insights alert rules (VM Availability + guest OS alerts for CPU, memory, disk, network)." } + }, + "uamiResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { "description": "Full resource ID of a User-Assigned Managed Identity for guest OS PromQL-based alerts. Required when enableAlerts=true." } + } + }, + "variables": { + "amaExtensionType": "[if(equals(parameters('osType'), 'Windows'), 'AzureMonitorWindowsAgent', 'AzureMonitorLinuxAgent')]", + "vmResourceId": "[concat('/subscriptions/', parameters('vmSubscriptionId'), '/resourceGroups/', parameters('vmResourceGroup'), '/providers/Microsoft.Compute/virtualMachines/', parameters('vmName'))]", + "amwResourceId": "[if(parameters('createNewAmw'), concat('/subscriptions/', parameters('vmSubscriptionId'), '/resourceGroups/', parameters('amwResourceGroup'), '/providers/microsoft.monitor/accounts/', parameters('amwName')), parameters('existingAmwResourceId'))]", + "logAnalyticsWorkspaceId": "[if(parameters('createNewLogAnalyticsWorkspace'), concat('/subscriptions/', parameters('vmSubscriptionId'), '/resourceGroups/', parameters('logAnalyticsResourceGroup'), '/providers/microsoft.operationalinsights/workspaces/', parameters('logAnalyticsWorkspaceName')), parameters('existingLogAnalyticsWorkspaceId'))]", + "dcrResourceId": "[if(parameters('createNewDcr'), concat('/subscriptions/', parameters('vmSubscriptionId'), '/resourceGroups/', parameters('dcrResourceGroup'), '/providers/Microsoft.Insights/dataCollectionRules/', parameters('dcrName')), parameters('existingDcrId'))]", + "dcraResourceId": "[concat(variables('vmResourceId'), '/providers/Microsoft.Insights/dataCollectionRuleAssociations/VirtualMachineInsightsExtension')]" + }, + "resources": [ + { + "comments": "--- Enable system-assigned managed identity on the VM (required by AMA) ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "EnableVMSystemIdentity", + "condition": "[parameters('enableSystemAssignedIdentity')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Compute/virtualMachines", + "apiVersion": "2022-11-01", + "name": "[parameters('vmName')]", + "location": "[parameters('location')]", + "identity": { + "type": "[parameters('identityType')]" + } + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('vmResourceGroup')]" + }, + { + "comments": "--- Create a new Azure Monitor Workspace ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "CreateAMW", + "condition": "[parameters('createNewAmw')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "microsoft.monitor/accounts", + "apiVersion": "2023-04-03", + "name": "[parameters('amwName')]", + "location": "[parameters('location')]", + "properties": {} + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('amwResourceGroup')]" + }, + { + "comments": "--- Create a new Log Analytics workspace (for per-process metrics) ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "CreateLogAnalyticsWorkspace", + "condition": "[and(parameters('createNewLogAnalyticsWorkspace'), parameters('enablePerProcessMetrics'))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]", + "location": "[parameters('location')]", + "properties": { + "sku": { "name": "PerGB2018" }, + "retentionInDays": 30 + } + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('logAnalyticsResourceGroup')]" + }, + { + "comments": "--- DCR: Standard OTel metrics only (free tier) ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "CreateStandardDCR", + "condition": "[and(parameters('createNewDcr'), not(parameters('enablePerProcessMetrics')))]", + "dependsOn": [ + "microsoft.resources/deployments/CreateAMW" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dcrName')]", + "location": "[parameters('location')]", + "properties": { + "dataSources": { + "performanceCountersOTel": [ + { + "name": "OtelDataSource", + "streams": [ "Microsoft-OtelPerfMetrics" ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "system.filesystem.usage", + "system.disk.io", + "system.disk.operation_time", + "system.disk.operations", + "system.memory.usage", + "system.network.io", + "system.cpu.time", + "system.network.dropped", + "system.network.errors", + "system.uptime" + ] + } + ] + }, + "destinations": { + "monitoringAccounts": [ + { + "accountResourceId": "[variables('amwResourceId')]", + "name": "MonitoringAccountDestination" + } + ] + }, + "dataFlows": [ + { + "streams": [ "Microsoft-OtelPerfMetrics" ], + "destinations": [ "MonitoringAccountDestination" ] + } + ] + } + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('dcrResourceGroup')]" + }, + { + "comments": "--- DCR: Per-process metrics (paid tier), OTel + InsightsMetrics/DetailedMetrics ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "CreatePerProcessDCR", + "condition": "[and(parameters('createNewDcr'), parameters('enablePerProcessMetrics'))]", + "dependsOn": [ + "microsoft.resources/deployments/CreateAMW", + "microsoft.resources/deployments/CreateLogAnalyticsWorkspace" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionRules", + "apiVersion": "2024-03-11", + "name": "[parameters('dcrName')]", + "location": "[parameters('location')]", + "properties": { + "dataSources": { + "performanceCounters": [ + { + "name": "Microsoft-InsightsMetrics", + "streams": [ "Microsoft-InsightsMetrics" ], + "scheduledTransferPeriod": "PT1M", + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "\\VmInsights\\DetailedMetrics" + ] + } + ], + "performanceCountersOTel": [ + { + "name": "OtelDataSource", + "streams": [ "Microsoft-OtelPerfMetrics" ], + "samplingFrequencyInSeconds": 60, + "counterSpecifiers": [ + "system.filesystem.usage", + "system.disk.io", + "system.disk.operation_time", + "system.disk.operations", + "system.memory.usage", + "system.network.io", + "system.cpu.time", + "system.network.dropped", + "system.network.errors", + "system.uptime", + "process.uptime", + "process.cpu.time", + "process.cpu.utilization", + "process.memory.usage", + "process.memory.virtual", + "process.memory.utilization", + "process.disk.io", + "process.disk.operations", + "process.paging.faults", + "process.open_file_descriptors", + "process.threads", + "process.handles", + "process.context_switches", + "process.signals_pending", + "system.processes.count", + "system.processes.created" + ] + } + ] + }, + "destinations": { + "logAnalytics": [ + { + "workspaceResourceId": "[variables('logAnalyticsWorkspaceId')]", + "name": "vmInsightworkspace" + } + ], + "monitoringAccounts": [ + { + "accountResourceId": "[variables('amwResourceId')]", + "name": "MonitoringAccountDestination" + } + ] + }, + "dataFlows": [ + { + "streams": [ "Microsoft-InsightsMetrics" ], + "destinations": [ "vmInsightworkspace" ] + }, + { + "streams": [ "Microsoft-OtelPerfMetrics" ], + "destinations": [ "MonitoringAccountDestination" ] + } + ] + } + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('dcrResourceGroup')]" + }, + { + "comments": "--- Associate DCR with VM ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "CreateDCRA", + "dependsOn": [ + "microsoft.resources/deployments/CreateStandardDCR", + "microsoft.resources/deployments/CreatePerProcessDCR" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Insights/dataCollectionRuleAssociations", + "apiVersion": "2022-06-01", + "name": "VirtualMachineInsightsExtension", + "id": "[variables('dcraResourceId')]", + "properties": { + "description": "Association of data collection rule. Deleting this association will break the data collection for this virtual machine.", + "dataCollectionRuleId": "[variables('dcrResourceId')]" + }, + "scope": "[variables('vmResourceId')]" + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('vmResourceGroup')]" + }, + { + "comments": "--- Install Azure Monitor Agent extension ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "InstallAMAExtension", + "dependsOn": [ + "microsoft.resources/deployments/CreateDCRA", + "microsoft.resources/deployments/EnableVMSystemIdentity" + ], + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "microsoft.compute/virtualmachines/extensions", + "apiVersion": "2022-11-01", + "name": "[concat(parameters('vmName'), '/', variables('amaExtensionType'))]", + "location": "[parameters('location')]", + "properties": { + "publisher": "Microsoft.Azure.Monitor", + "type": "[variables('amaExtensionType')]", + "typeHandlerVersion": "1.0", + "autoUpgradeMinorVersion": true, + "enableAutomaticUpgrade": true + } + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('vmResourceGroup')]" + }, + { + "comments": "--- Host alert: VM Availability (platform metric, no UAMI required) ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "CreateHostAlertRules", + "condition": "[parameters('enableAlerts')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2018-03-01", + "name": "[concat('VM Availability - ', parameters('vmName'))]", + "location": "global", + "properties": { + "description": "VM is unavailable or not responding", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT5M", + "windowSize": "PT5M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.SingleResourceMultipleMetricCriteria", + "allOf": [ + { + "name": "Metric1", + "metricName": "VmAvailabilityMetric", + "metricNamespace": "Microsoft.Compute/virtualMachines", + "operator": "LessThan", + "threshold": 1, + "timeAggregation": "Average", + "criterionType": "StaticThresholdCriterion" + } + ] + }, + "actions": [] + } + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('vmResourceGroup')]" + }, + { + "comments": "--- Guest OS alerts: CPU, Memory, Disk, Network (PromQL-based, requires UAMI) ---", + "type": "microsoft.resources/deployments", + "apiVersion": "2021-04-01", + "name": "CreateGuestAlertRules", + "condition": "[parameters('enableAlerts')]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2024-03-01-preview", + "name": "[concat('Guest OS CPU Usage - ', parameters('vmName'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[parameters('uamiResourceId')]": {} + } + }, + "properties": { + "description": "CPU usage has exceeded 80% threshold over the last 5 minutes", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT1M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.PromQLCriteria", + "allOf": [ + { + "name": "Metric1", + "query": "avg_over_time(((sum (irate({\"system.cpu.time\",\"state\" !~ \"idle|iowait|steal\"}[2m]))) / (sum (irate({\"system.cpu.time\"}[2m]))))[5m:]) * 100 > 80", + "criterionType": "StaticThresholdCriterion" + } + ], + "failingPeriods": { "for": "PT2M" } + }, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT2M" + }, + "actions": [] + } + }, + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2024-03-01-preview", + "name": "[concat('Guest OS Memory Usage - ', parameters('vmName'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[parameters('uamiResourceId')]": {} + } + }, + "properties": { + "description": "Available memory has dropped below 1 GB over the last 5 minutes", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT1M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.PromQLCriteria", + "allOf": [ + { + "name": "Metric1", + "query": "min_over_time((sum ({\"system.memory.usage\", state=~\"free|cached|buffered|slab_reclaimable\"}))[5m:]) < (1 * 1024 * 1024 * 1024)", + "criterionType": "StaticThresholdCriterion" + } + ], + "failingPeriods": { "for": "PT2M" } + }, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT2M" + }, + "actions": [] + } + }, + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2024-03-01-preview", + "name": "[concat('Guest OS Disk IOPS - ', parameters('vmName'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[parameters('uamiResourceId')]": {} + } + }, + "properties": { + "description": "Disk IOPS has exceeded 5000 operations per second over the last 5 minutes", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT1M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.PromQLCriteria", + "allOf": [ + { + "name": "Metric1", + "query": "max_over_time((sum (irate({\"system.disk.operations\"}[2m])))[5m:]) > 5000", + "criterionType": "StaticThresholdCriterion" + } + ], + "failingPeriods": { "for": "PT2M" } + }, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT2M" + }, + "actions": [] + } + }, + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2024-03-01-preview", + "name": "[concat('Guest OS Network In - ', parameters('vmName'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[parameters('uamiResourceId')]": {} + } + }, + "properties": { + "description": "Total network inbound traffic has exceeded 100 GB over the last day", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT1M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.PromQLCriteria", + "allOf": [ + { + "name": "Metric1", + "query": "sum_over_time((sum (irate({\"system.network.io\", direction=\"receive\"}[2m])))[1d:]) > (100 * 1024 * 1024 * 1024)", + "criterionType": "StaticThresholdCriterion" + } + ], + "failingPeriods": { "for": "PT2M" } + }, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT2M" + }, + "actions": [] + } + }, + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2024-03-01-preview", + "name": "[concat('Guest OS Network Out - ', parameters('vmName'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[parameters('uamiResourceId')]": {} + } + }, + "properties": { + "description": "Total network outbound traffic has exceeded 50 GB over the last day", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT1M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.PromQLCriteria", + "allOf": [ + { + "name": "Metric1", + "query": "sum_over_time((sum (irate({\"system.network.io\", direction=\"transmit\"}[2m])))[1d:]) > (50 * 1024 * 1024 * 1024)", + "criterionType": "StaticThresholdCriterion" + } + ], + "failingPeriods": { "for": "PT2M" } + }, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT2M" + }, + "actions": [] + } + }, + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2024-03-01-preview", + "name": "[concat('Guest OS Network Errors - ', parameters('vmName'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[parameters('uamiResourceId')]": {} + } + }, + "properties": { + "description": "Network errors have exceeded 10 total errors over the last 5 minutes", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT1M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.PromQLCriteria", + "allOf": [ + { + "name": "Metric1", + "query": "sum_over_time((sum (irate({\"system.network.errors\"}[2m])))[5m:]) > 10", + "criterionType": "StaticThresholdCriterion" + } + ], + "failingPeriods": { "for": "PT2M" } + }, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT2M" + }, + "actions": [] + } + }, + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2024-03-01-preview", + "name": "[concat('Guest OS Disk Operation Time - ', parameters('vmName'))]", + "location": "[parameters('location')]", + "identity": { + "type": "UserAssigned", + "userAssignedIdentities": { + "[parameters('uamiResourceId')]": {} + } + }, + "properties": { + "description": "Average disk operation time has exceeded 100ms over the last 5 minutes", + "severity": 3, + "enabled": true, + "scopes": [ "[variables('vmResourceId')]" ], + "evaluationFrequency": "PT1M", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.PromQLCriteria", + "allOf": [ + { + "name": "Metric1", + "query": "avg_over_time(((sum (irate({\"system.disk.operation_time\"}[2m]))) / (sum (irate({\"system.disk.operations\"}[2m]))))[5m:]) * 1000 > 100", + "criterionType": "StaticThresholdCriterion" + } + ], + "failingPeriods": { "for": "PT2M" } + }, + "resolveConfiguration": { + "autoResolved": true, + "timeToResolve": "PT2M" + }, + "actions": [] + } + } + ] + } + }, + "subscriptionId": "[parameters('vmSubscriptionId')]", + "resourceGroup": "[parameters('vmResourceGroup')]" + } + ] +}