From 05b1cb414fcc87826b98f24f49dc8e010449966d Mon Sep 17 00:00:00 2001 From: Joseph Barnes Date: Tue, 9 Jul 2024 20:53:46 -0500 Subject: [PATCH] Added github workflow to generate arm and bicep templates --- .github/workflows/generate-templates.yml | 83 ++++++ .github/workflows/hugo-build-pr-check.yml | 5 + .github/workflows/hugo-site-build.yml | 7 +- .../partials/templates/template-tabs.html | 11 +- .../generate-templates/generate-templates.py | 125 +++++---- .../arm/activity-administrative.json | 95 +++++++ .../arm/activity-resourcehealth.json | 95 +++++++ .../templates/arm/activity-servicehealth.json | 91 +++++++ .../generate-templates/templates/arm/log.json | 256 ++++++++++++++++++ .../templates/arm/metric-dynamic.json | 219 +++++++++++++++ .../templates/arm/metric-static.json | 199 ++++++++++++++ .../bicep/activity-administrative.bicep | 68 +++++ .../bicep/activity-resourcehealth.bicep | 66 +++++ .../bicep/activity-servicehealth.bicep | 64 +++++ .../templates/bicep/log.bicep | 168 ++++++++++++ .../templates/bicep/metric-dynamic.bicep | 147 ++++++++++ .../templates/bicep/metric-static.bicep | 135 +++++++++ 17 files changed, 1769 insertions(+), 65 deletions(-) create mode 100644 .github/workflows/generate-templates.yml create mode 100644 tooling/generate-templates/templates/arm/activity-administrative.json create mode 100644 tooling/generate-templates/templates/arm/activity-resourcehealth.json create mode 100644 tooling/generate-templates/templates/arm/activity-servicehealth.json create mode 100644 tooling/generate-templates/templates/arm/log.json create mode 100644 tooling/generate-templates/templates/arm/metric-dynamic.json create mode 100644 tooling/generate-templates/templates/arm/metric-static.json create mode 100644 tooling/generate-templates/templates/bicep/activity-administrative.bicep create mode 100644 tooling/generate-templates/templates/bicep/activity-resourcehealth.bicep create mode 100644 tooling/generate-templates/templates/bicep/activity-servicehealth.bicep create mode 100644 tooling/generate-templates/templates/bicep/log.bicep create mode 100644 tooling/generate-templates/templates/bicep/metric-dynamic.bicep create mode 100644 tooling/generate-templates/templates/bicep/metric-static.bicep diff --git a/.github/workflows/generate-templates.yml b/.github/workflows/generate-templates.yml new file mode 100644 index 000000000..3b4c836bb --- /dev/null +++ b/.github/workflows/generate-templates.yml @@ -0,0 +1,83 @@ +# Workflow for generating (arm/bicep/etc) templates for each alert +name: Generate Templates + +on: + # Runs on pushes targeting the default branch + push: + branches: + - main + paths: + - 'services/**/alerts.yaml' + - 'tooling/generate-templates/**' + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: {} + +jobs: + generate-templates: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: main + submodules: recursive + fetch-depth: 0 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' # install the python version needed + + - name: Install Python Packages and Requirements + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + working-directory: tooling/generate-templates + + - name: Generate Templates + id: generate + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + + git checkout -b github-action-generate-templates + + # Generate templates for alerts + echo "Generating templates for alerts..." + python tooling/generate-templates/generate-templates.py --path services --output services --template_path tooling/generate-templates/templates + + # Check if there are any changes in the services directory + git add services + + # Check if there are any changes to commit + if [[ `git status --porcelain` ]]; then + git commit -m "[GitHub Action - Generate Templates] Generate templates for alerts" + + # Push changes to the current branch + git push --set-upstream origin github-action-generate-templates --force + + prs=$(gh pr list \ + --repo "$GITHUB_REPOSITORY" \ + --head 'github-action-generate-templates' \ + --base 'main' \ + --json title \ + --jq 'length') + + if ((prs > 0)); then + echo "skippr=true" >> "$GITHUB_OUTPUT" + fi + else + echo "skippr=true" >> "$GITHUB_OUTPUT" + fi + - name: Create pull request + if: '!steps.generate.outputs.skippr' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # Create a pull request + echo "Creating a pull request..." + gh pr --repo ${{ github.repository }} create --title "[GitHub Action - Generate Templates] Generate templates for alerts" --body "This PR was automatically generated by the workflow." --base main --head github-action-generate-templates + diff --git a/.github/workflows/hugo-build-pr-check.yml b/.github/workflows/hugo-build-pr-check.yml index 847761cfd..4c659dc4a 100644 --- a/.github/workflows/hugo-build-pr-check.yml +++ b/.github/workflows/hugo-build-pr-check.yml @@ -7,6 +7,11 @@ on: - main paths: - 'docs/**' + - 'services/**/alerts.yaml' + - 'services/**/*.md' + - 'services/**/templates/**' + - 'tooling/export-alerts/**' + - 'tooling/generate-templates/**' - '.github/workflows/hugo-build-pr-check.yml' workflow_dispatch: {} diff --git a/.github/workflows/hugo-site-build.yml b/.github/workflows/hugo-site-build.yml index a46eb5120..40335b5b3 100644 --- a/.github/workflows/hugo-site-build.yml +++ b/.github/workflows/hugo-site-build.yml @@ -10,6 +10,7 @@ on: - 'docs/**' - 'services/**/alerts.yaml' - 'services/**/*.md' + - 'services/**/templates/**' - 'tooling/export-alerts/**' - 'tooling/generate-templates/**' @@ -69,12 +70,6 @@ jobs: python export-alerts.py --path ../../services --template ./alerts-template.xlsx --output-xls ../../services/amba-alerts.xlsx --output-json ../../services/amba-alerts.json --output-yaml ../../services/amba-alerts.yaml working-directory: tooling/export-alerts - - name: Generate Templates - run: | - pip install -r requirements.txt - python generate-templates.py --path ../../services --output ../../artifacts/templates - working-directory: tooling/generate-templates - - name: Setup Pages id: pages uses: actions/configure-pages@v5 diff --git a/docs/layouts/partials/templates/template-tabs.html b/docs/layouts/partials/templates/template-tabs.html index 61b59b461..33acd7d25 100644 --- a/docs/layouts/partials/templates/template-tabs.html +++ b/docs/layouts/partials/templates/template-tabs.html @@ -1,8 +1,9 @@ {{ $category := .category }} {{ $type := .type }} -{{ $filename := printf "%s.json" .alert.guid | printf "%s"}} -{{ $version := readFile "artifacts/templates/latest_version.txt" }} -{{ $file := path.Join "artifacts/templates" $version $category $type $filename }} +{{ $alert_name := .alert.name | replaceRE `[^a-zA-Z0-9-]` "" }} +{{ $alert_name := printf "%s_%s" $alert_name .alert.guid }} +{{ $filename := printf "%s.json" $alert_name | printf "%s"}} +{{ $file := path.Join "services" $category $type "templates/arm" $filename }}
- {{ $filename := printf "%s.bicep" .alert.guid | printf "%s"}} - {{ $file := path.Join "artifacts/templates" $version $category $type $filename }} + {{ $filename := printf "%s.bicep" $alert_name | printf "%s"}} + {{ $file := path.Join "services" $category $type "templates/bicep" $filename }} {{ $data := readFile $file }} {{ highlight $data "bicep" }}
diff --git a/tooling/generate-templates/generate-templates.py b/tooling/generate-templates/generate-templates.py index d6c64b66c..3f2572d50 100644 --- a/tooling/generate-templates/generate-templates.py +++ b/tooling/generate-templates/generate-templates.py @@ -2,13 +2,13 @@ import yaml import json import argparse -import datetime # Parse command line arguments def parseArguments(): parser = argparse.ArgumentParser(description='This script will generate ARM and Bicep templates for each alert.') parser.add_argument('-p', '--path', type=str, required=False, metavar='path', help='Path to services directory', default='../../services') - parser.add_argument('-o', '--output', type=str, required=False, metavar='output', help='Path to output directory', default='../../artifacts/templates') + parser.add_argument('-o', '--output', type=str, required=False, metavar='output', help='Path to output directory', default='../../services') + parser.add_argument('-s', '--template_path', type=str, required=False, metavar='template_path', help='Path to templates directory', default='templates') parser.add_argument('-t', '--telemetry_pid', type=str, required=False, metavar='telemetry_pid', help='Telemetry PID', default='pid-8bb7cf8a-bcf7-4264-abcb-703ace2fc84d') args = parser.parse_args() @@ -18,8 +18,7 @@ def readYamlData(dir, export_hidden): # Walk the directory tree and load all the alerts.yaml files # into a list of dictionaries using the folder path as the structure - # for the dictionary. This will allow us to easily export the data - # to a CSV or XLS file. + # for the dictionary. data = {} for root, dirs, files in os.walk(dir): for file in files: @@ -45,12 +44,12 @@ def readYamlData(dir, export_hidden): return data -def readTemplates(): +def readTemplates(template_path): arm = {} bicep = {} # Read ARM templates from arm directory into a string - for root, dirs, files in os.walk(os.path.join('.', 'arm')): + for root, dirs, files in os.walk(os.path.join(template_path, 'arm')): for file in files: if file.endswith('.json'): # read the file into a string @@ -58,7 +57,7 @@ def readTemplates(): arm[file.replace('.json','')] = f.read() # Read Bicep templates from arm directory into a string - for root, dirs, files in os.walk(os.path.join('.', 'bicep')): + for root, dirs, files in os.walk(os.path.join(template_path, 'bicep')): for file in files: if file.endswith('.bicep'): # read the file into a string @@ -73,30 +72,35 @@ def main(): data = readYamlData(args.path, False) - arm, bicep = readTemplates() + arm, bicep = readTemplates(args.template_path) import datetime + import re - # Get the current timestamp - timestamp = datetime.datetime.now() + for category in data: + for resourceType in data[category]: - # Format it as a string - formatted_timestamp = timestamp.strftime("%Y%m%d%H%M%S") + print(f"Generating templates for {len(data[category][resourceType])} alerts in {category}/{resourceType}...") - # Create the output directory if it doesn't exist - os.makedirs(args.output, exist_ok=True) + # create directories based on template types if it doesn't exist + os.makedirs(os.path.join(args.output, category, resourceType, "templates", "arm"), exist_ok=True) + os.makedirs(os.path.join(args.output, category, resourceType, "templates", "bicep"), exist_ok=True) - # Write timestamp to a file - with open(os.path.join(args.output, 'latest_version.txt'), 'w') as f: - f.write(formatted_timestamp) + # Remove all files in arm and bicep directories + for root, dirs, files in os.walk(os.path.join(args.output, category, resourceType, "templates", "arm")): + for file in files: + os.remove(os.path.join(root, file)) - for category in data: - for resourceType in data[category]: - # create directory based on resourceType if it doesn't exist - os.makedirs(os.path.join(args.output, formatted_timestamp, category, resourceType), exist_ok=True) + for root, dirs, files in os.walk(os.path.join(args.output, category, resourceType, "templates", "bicep")): + for file in files: + os.remove(os.path.join(root, file)) + + alert_file_names = [] for alert in data[category][resourceType]: arm_template_type = "" + alert_file_name = re.sub(r'[^a-zA-Z0-9-]', '', alert['name']) + '_' + alert['guid'] + if alert["type"] == "Metric": if 'criterionType' in alert["properties"]: if alert["properties"]["criterionType"] == "StaticThresholdCriterion": @@ -114,6 +118,8 @@ def main(): template_type = "activity-resourcehealth" elif alert["properties"]["category"] == "ServiceHealth": template_type = "activity-servicehealth" + else: + continue if template_type == "": print(f"Template not found for alert {alert['guid']}") @@ -125,21 +131,21 @@ def main(): arm_template = arm_template.replace("##TELEMETRY_PID##", args.telemetry_pid) bicep_template = bicep_template.replace("##TELEMETRY_PID##", args.telemetry_pid) - if 'description' in alert and alert["description"]: + if 'description' in alert and alert["description"] is not None: arm_template = arm_template.replace("##DESCRIPTION##", alert["description"]) bicep_template = bicep_template.replace("##DESCRIPTION##", alert["description"]) else: arm_template = arm_template.replace("##DESCRIPTION##", "") bicep_template = bicep_template.replace("##DESCRIPTION##", "") - if 'severity' in alert["properties"] and alert["properties"]["severity"]: + if 'severity' in alert["properties"] and alert["properties"]["severity"] is not None: arm_template = arm_template.replace("##SEVERITY##", str(int(alert["properties"]["severity"]))) bicep_template = bicep_template.replace("##SEVERITY##", str(int(alert["properties"]["severity"]))) else: arm_template = arm_template.replace("##SEVERITY##", "") bicep_template = bicep_template.replace("##SEVERITY##", "") - if 'autoMitigate' in alert["properties"] and alert["properties"]["autoMitigate"]: + if 'autoMitigate' in alert["properties"] and alert["properties"]["autoMitigate"] is not None: if alert["properties"]["autoMitigate"] == True: arm_template = arm_template.replace("##AUTO_MITIGATE##", "true") bicep_template = bicep_template.replace("##AUTO_MITIGATE##", "true") @@ -150,7 +156,7 @@ def main(): arm_template = arm_template.replace("##AUTO_MITIGATE##", "") bicep_template = bicep_template.replace("##AUTO_MITIGATE##", "") - if 'query' in alert["properties"] and alert["properties"]["query"]: + if 'query' in alert["properties"] and alert["properties"]["query"] is not None: arm_template = arm_template.replace("##QUERY##", json.dumps(alert["properties"]["query"].replace("\n", " "))) query = alert["properties"]["query"].replace("\n", " ").replace("'", "\\'") bicep_template = bicep_template.replace("##QUERY##", query) @@ -158,77 +164,83 @@ def main(): arm_template = arm_template.replace("##QUERY##", "") bicep_template = bicep_template.replace("##QUERY##", "") - if 'metricMeasureColumn' in alert["properties"] and alert["properties"]["metricMeasureColumn"]: + if 'metricName' in alert["properties"] and alert["properties"]["metricName"] is not None: + arm_template = arm_template.replace("##METRIC_NAME##", alert["properties"]["metricName"]) + bicep_template = bicep_template.replace("##METRIC_NAME##", alert["properties"]["metricName"]) + else: + arm_template = arm_template.replace("##METRIC_NAME##", "") + bicep_template = bicep_template.replace("##METRIC_NAME##", "") + + if 'metricMeasureColumn' in alert["properties"] and alert["properties"]["metricMeasureColumn"] is not None: arm_template = arm_template.replace("##METRIC_MEASURE_COLUMN##", alert["properties"]["metricMeasureColumn"]) bicep_template = bicep_template.replace("##METRIC_MEASURE_COLUMN##", alert["properties"]["metricMeasureColumn"]) else: arm_template = arm_template.replace("##METRIC_MEASURE_COLUMN##", "") bicep_template = bicep_template.replace("##METRIC_MEASURE_COLUMN##", "") - if 'resouceIdColumn' in alert["properties"] and alert["properties"]["resouceIdColumn"]: + if 'resouceIdColumn' in alert["properties"] and alert["properties"]["resouceIdColumn"] is not None: arm_template = arm_template.replace("##RESOURCE_ID_COLUMN##", alert["properties"]["resouceIdColumn"]) bicep_template = bicep_template.replace("##RESOURCE_ID_COLUMN##", alert["properties"]["resouceIdColumn"]) else: arm_template = arm_template.replace("##RESOURCE_ID_COLUMN##", "") bicep_template = bicep_template.replace("##RESOURCE_ID_COLUMN##", "") - if 'operator' in alert["properties"] and alert["properties"]["operator"]: + if 'operator' in alert["properties"] and alert["properties"]["operator"] is not None: arm_template = arm_template.replace("##OPERATOR##", alert["properties"]["operator"]) bicep_template = bicep_template.replace("##OPERATOR##", alert["properties"]["operator"]) else: arm_template = arm_template.replace("##OPERATOR##", "") bicep_template = bicep_template.replace("##OPERATOR##", "") - if 'failingPeriods' in alert["properties"] and alert["properties"]["failingPeriods"]["numberOfEvaluationPeriods"]: + if 'failingPeriods' in alert["properties"] and alert["properties"]["failingPeriods"]["numberOfEvaluationPeriods"] is not None: arm_template = arm_template.replace("##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS##", str(int(alert["properties"]["failingPeriods"]["numberOfEvaluationPeriods"]))) bicep_template = bicep_template.replace("##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS##", str(int(alert["properties"]["failingPeriods"]["numberOfEvaluationPeriods"]))) else: arm_template = arm_template.replace("##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS##", "") bicep_template = bicep_template.replace("##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS##", "") - if 'failingPeriods' in alert["properties"] and alert["properties"]["failingPeriods"]["numberOfEvaluationPeriods"]: + if 'failingPeriods' in alert["properties"] and alert["properties"]["failingPeriods"]["numberOfEvaluationPeriods"] is not None: arm_template = arm_template.replace("##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT##", str(int(alert["properties"]["failingPeriods"]["minFailingPeriodsToAlert"]))) bicep_template = bicep_template.replace("##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT##", str(int(alert["properties"]["failingPeriods"]["minFailingPeriodsToAlert"]))) else: arm_template = arm_template.replace("##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT##", "") bicep_template = bicep_template.replace("##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT##", "") - if 'threshold' in alert["properties"] and alert["properties"]["threshold"]: - arm_template = arm_template.replace("##THRESHOLD##", str(int(alert["properties"]["threshold"]))) - bicep_template = bicep_template.replace("##THRESHOLD##", str(int(alert["properties"]["threshold"]))) + if 'threshold' in alert["properties"] and alert["properties"]["threshold"] is not None: + # Convert the threshold to a float + threshold = float(alert["properties"]["threshold"]) + threshold = str(round(threshold)) + if threshold == "": + raise Exception(f"Threshold is empty for alert {alert['guid']}") + + arm_template = arm_template.replace("##THRESHOLD##", threshold) + bicep_template = bicep_template.replace("##THRESHOLD##", threshold) else: arm_template = arm_template.replace("##THRESHOLD##", "") bicep_template = bicep_template.replace("##THRESHOLD##", "") - if 'timeAggregation' in alert["properties"] and alert["properties"]["timeAggregation"]: + if 'timeAggregation' in alert["properties"] and alert["properties"]["timeAggregation"] is not None: arm_template = arm_template.replace("##TIME_AGGREGATION##", alert["properties"]["timeAggregation"]) bicep_template = bicep_template.replace("##TIME_AGGREGATION##", alert["properties"]["timeAggregation"]) else: arm_template = arm_template.replace("##TIME_AGGREGATION##", "") bicep_template = bicep_template.replace("##TIME_AGGREGATION##", "") - if 'windowSize' in alert["properties"] and alert["properties"]["windowSize"]: + if 'windowSize' in alert["properties"] and alert["properties"]["windowSize"] is not None: arm_template = arm_template.replace("##WINDOW_SIZE##", alert["properties"]["windowSize"]) bicep_template = bicep_template.replace("##WINDOW_SIZE##", alert["properties"]["windowSize"]) else: arm_template = arm_template.replace("##WINDOW_SIZE##", "") bicep_template = bicep_template.replace("##WINDOW_SIZE##", "") - if 'evaluationFrequency' in alert["properties"] and alert["properties"]["evaluationFrequency"]: + if 'evaluationFrequency' in alert["properties"] and alert["properties"]["evaluationFrequency"] is not None: arm_template = arm_template.replace("##EVALUATION_FREQUENCY##", alert["properties"]["evaluationFrequency"]) bicep_template = bicep_template.replace("##EVALUATION_FREQUENCY##", alert["properties"]["evaluationFrequency"]) else: arm_template = arm_template.replace("##EVALUATION_FREQUENCY##", "") bicep_template = bicep_template.replace("##EVALUATION_FREQUENCY##", "") - if 'metricName' in alert["properties"] and alert["properties"]["metricName"]: - arm_template = arm_template.replace("##METRIC_NAME##", alert["properties"]["metricName"]) - bicep_template = bicep_template.replace("##METRIC_NAME##", alert["properties"]["metricName"]) - else: - arm_template = arm_template.replace("##METRIC_NAME##", "") - bicep_template = bicep_template.replace("##METRIC_NAME##", "") - - if 'dimensions' in alert["properties"] and "dimensions" in alert["properties"]: + if 'dimensions' in alert["properties"] and alert["properties"]["dimensions"] is not None: arm_template = arm_template.replace("##DIMENSIONS##", json.dumps(alert["properties"]["dimensions"])) dimensions = [] @@ -246,17 +258,17 @@ def main(): bicep_template = bicep_template.replace("##DIMENSIONS##", "".join(dimensions)) else: - arm_template = arm_template.replace("##DIMENSIONS##", "") - bicep_template = bicep_template.replace("##DIMENSIONS##", "") + arm_template = arm_template.replace("##DIMENSIONS##", "[]") + bicep_template = bicep_template.replace("##DIMENSIONS##", "[]") - if 'operationName' in alert["properties"] and alert["properties"]["operationName"]: + if 'operationName' in alert["properties"] and alert["properties"]["operationName"] is not None: arm_template = arm_template.replace("##OPERATION_NAME##", alert["properties"]["operationName"]) bicep_template = bicep_template.replace("##OPERATION_NAME##", alert["properties"]["operationName"]) else: arm_template = arm_template.replace("##OPERATION_NAME##", "") bicep_template = bicep_template.replace("##OPERATION_NAME##", "") - if 'status' in alert["properties"] and alert["properties"]["status"]: + if 'status' in alert["properties"] and alert["properties"]["status"] is not None: arm_template = arm_template.replace("##STATUS##", json.dumps(alert["properties"]["status"])) statuses = [] @@ -268,7 +280,7 @@ def main(): arm_template = arm_template.replace("##STATUS##", "") bicep_template = bicep_template.replace("##STATUS##", "") - if 'causes' in alert["properties"] and alert["properties"]["causes"]: + if 'causes' in alert["properties"] and alert["properties"]["causes"] is not None: causes = [] for cause in alert["properties"]["causes"]: @@ -293,7 +305,7 @@ def main(): arm_template = arm_template.replace("##CAUSES##", "") bicep_template = bicep_template.replace("##CAUSES##", "") - if 'currentHealthStatus' in alert["properties"] and alert["properties"]["currentHealthStatus"]: + if 'currentHealthStatus' in alert["properties"] and alert["properties"]["currentHealthStatus"] is not None: currentHealthStatuses = [] for currentHealthStatus in alert["properties"]["currentHealthStatus"]: currentHealthStatuses.append(f""" @@ -317,19 +329,24 @@ def main(): arm_template = arm_template.replace("##CURRENT_HEALTH_STATUS##", "") bicep_template = bicep_template.replace("##CURRENT_HEALTH_STATUS##", "") - if 'incidentType' in alert["properties"] and alert["properties"]["incidentType"]: + if 'incidentType' in alert["properties"] and alert["properties"]["incidentType"] is not None: arm_template = arm_template.replace("##INCIDENT_TYPE##", alert["properties"]["incidentType"]) bicep_template = bicep_template.replace("##INCIDENT_TYPE##", alert["properties"]["incidentType"]) else: arm_template = arm_template.replace("##INCIDENT_TYPE##", "") bicep_template = bicep_template.replace("##INCIDENT_TYPE##", "") - # Save the ARM template - with open(os.path.join(args.output, formatted_timestamp, category, resourceType, alert['guid'] + '.json'), 'w') as f: + # Check if alert name already exists + if alert_file_name in alert_file_names: + raise Exception(f"Alert name {alert_file_name} already exists in the list of alerts for {category}/{resourceType}") + else: + alert_file_names.append(alert_file_name) + + with open(os.path.join(args.output, category, resourceType, "templates", "arm", alert_file_name + '.json'), 'w') as f: f.write(arm_template) # Save the Bicep template - with open(os.path.join(args.output, formatted_timestamp, category, resourceType, alert['guid'] + '.bicep'), 'w') as f: + with open(os.path.join(args.output, category, resourceType, "templates", "bicep", alert_file_name + '.bicep'), 'w') as f: f.write(bicep_template) if __name__ == '__main__': diff --git a/tooling/generate-templates/templates/arm/activity-administrative.json b/tooling/generate-templates/templates/arm/activity-administrative.json new file mode 100644 index 000000000..a48293408 --- /dev/null +++ b/tooling/generate-templates/templates/arm/activity-administrative.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "alertName": { + "type": "string", + "metadata": { + "description": "Unique name (within the Resource Group) for the Activity log alert." + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "##DESCRIPTION##", + "metadata": { + "description": "Description of alert" + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Indicates whether or not the alert is enabled." + } + }, + "currentDateTimeUtcNow": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "The current date and time using the utcNow function. Used for deployment name uniqueness" + } + }, + "telemetryOptOut": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ], + "metadata": { + "description": "The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry." + } + } + }, + "variables": { + "pidDeploymentName": "[take(concat('##TELEMETRY_PID##-', uniqueString(resourceGroup().id, parameters('alertName'), parameters('currentDateTimeUtcNow'))), 64)]" + }, + "resources": [ + { + "type": "Microsoft.Insights/activityLogAlerts", + "apiVersion": "2017-04-01", + "name": "[parameters('alertName')]", + "location": "Global", + "tags": { + "_deployed_by_amba": true + }, + "properties": { + "description": "[parameters('alertDescription')]", + "scopes": [ + "[subscription().id]" + ], + "enabled": "[parameters('isEnabled')]", + "condition": { + "allOf": [ + { + "field": "category", + "equals": "Administrative" + }, + { + "field": "operationName", + "equals": "##OPERATION_NAME##" + }, + { + "field": "status", + "containsAny": ##STATUS## + } + ] + } + } + }, + { + "condition": "[equals(parameters('telemetryOptOut'), 'No')]", + "apiVersion": "2020-06-01", + "name": "[variables('pidDeploymentName')]", + "type": "Microsoft.Resources/deployments", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + } + ] +} diff --git a/tooling/generate-templates/templates/arm/activity-resourcehealth.json b/tooling/generate-templates/templates/arm/activity-resourcehealth.json new file mode 100644 index 000000000..a25574c0f --- /dev/null +++ b/tooling/generate-templates/templates/arm/activity-resourcehealth.json @@ -0,0 +1,95 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "alertName": { + "type": "string", + "metadata": { + "description": "Unique name (within the Resource Group) for the Activity log alert." + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "##DESCRIPTION##", + "metadata": { + "description": "Description of alert" + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Indicates whether or not the alert is enabled." + } + }, + "currentDateTimeUtcNow": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "The current date and time using the utcNow function. Used for deployment name uniqueness" + } + }, + "telemetryOptOut": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ], + "metadata": { + "description": "The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry." + } + } + }, + "variables": { + "pidDeploymentName": "[take(concat('##TELEMETRY_PID##-', uniqueString(resourceGroup().id, parameters('alertName'), parameters('currentDateTimeUtcNow'))), 64)]" + }, + "resources": [ + { + "type": "Microsoft.Insights/activityLogAlerts", + "apiVersion": "2017-04-01", + "name": "[parameters('alertName')]", + "location": "Global", + "tags": { + "_deployed_by_amba": true + }, + "properties": { + "description": "[parameters('alertDescription')]", + "scopes": [ + "[subscription().id]" + ], + "enabled": "[parameters('isEnabled')]", + "condition": { + "allOf": [ + { + "field": "category", + "equals": "ResourceHealth" + }, + { + "anyOf": [##CAUSES## + ] + }, + { + "anyOf": [##CURRENT_HEALTH_STATUS## + ] + } + ] + } + } + }, + { + "condition": "[equals(parameters('telemetryOptOut'), 'No')]", + "apiVersion": "2020-06-01", + "name": "[variables('pidDeploymentName')]", + "type": "Microsoft.Resources/deployments", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + } + ] +} diff --git a/tooling/generate-templates/templates/arm/activity-servicehealth.json b/tooling/generate-templates/templates/arm/activity-servicehealth.json new file mode 100644 index 000000000..796bd3784 --- /dev/null +++ b/tooling/generate-templates/templates/arm/activity-servicehealth.json @@ -0,0 +1,91 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "alertName": { + "type": "string", + "metadata": { + "description": "Unique name (within the Resource Group) for the Activity log alert." + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "##DESCRIPTION##", + "metadata": { + "description": "Description of alert" + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Indicates whether or not the alert is enabled." + } + }, + "currentDateTimeUtcNow": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "The current date and time using the utcNow function. Used for deployment name uniqueness" + } + }, + "telemetryOptOut": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ], + "metadata": { + "description": "The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry." + } + } + }, + "variables": { + "pidDeploymentName": "[take(concat('##TELEMETRY_PID-', uniqueString(resourceGroup().id, parameters('alertName'), parameters('currentDateTimeUtcNow'))), 64)]" + }, + "resources": [ + { + "type": "Microsoft.Insights/activityLogAlerts", + "apiVersion": "2017-04-01", + "name": "[parameters('alertName')]", + "location": "Global", + "tags": { + "_deployed_by_amba": true + }, + "properties": { + "description": "[parameters('alertDescription')]", + "scopes": [ + "[subscription().id]" + ], + "enabled": "[parameters('isEnabled')]", + "condition": { + "allOf": [ + { + "field": "category", + "equals": "ServiceHealth" + }, + { + "field": "properties.incidentType", + "equals": "##INCIDENT_TYPE##" + } + ] + } + } + }, + { + "condition": "[equals(parameters('telemetryOptOut'), 'No')]", + "apiVersion": "2020-06-01", + "name": "[variables('pidDeploymentName')]", + "type": "Microsoft.Resources/deployments", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + } + ] +} diff --git a/tooling/generate-templates/templates/arm/log.json b/tooling/generate-templates/templates/arm/log.json new file mode 100644 index 000000000..c2a583ca8 --- /dev/null +++ b/tooling/generate-templates/templates/arm/log.json @@ -0,0 +1,256 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "alertName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Name of the alert" + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "##DESCRIPTION##", + "metadata": { + "description": "Description of alert" + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Specifies whether the alert is enabled" + } + }, + "checkWorkspaceAlertsStorageConfigured": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Specifies whether to check linked storage and fail creation if the storage was not found" + } + }, + "resourceId": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Full Resource ID of the resource emitting the metric that will be used for the comparison. For example /subscriptions/00000000-0000-0000-0000-0000-00000000/resourceGroups/ResourceGroupName/providers/Microsoft.compute/virtualMachines/VM_xyz" + } + }, + "muteActionsDuration": { + "type": "string", + "allowedValues": [ + "PT1M", + "PT5M", + "PT15M", + "PT30M", + "PT1H", + "PT6H", + "PT12H", + "PT24H" + ], + "metadata": { + "description": "Mute actions for the chosen period of time (in ISO 8601 duration format) after the alert is fired." + } + }, + "alertSeverity": { + "type": "int", + "defaultValue": ##SEVERITY##, + "allowedValues": [ + 0, + 1, + 2, + 3, + 4 + ], + "metadata": { + "description": "Severity of alert {0,1,2,3,4}" + } + }, + "autoMitigate": { + "type": "bool", + "defaultValue": ##AUTO_MITIGATE##, + "metadata": { + "description": "Specifies whether the alert will automatically resolve" + } + }, + "query": { + "type": "string", + "minLength": 1, + "defaultValue": ##QUERY##, + "metadata": { + "description": "Name of the metric used in the comparison to activate the alert." + } + }, + "metricMeasureColumn": { + "type": "string", + "defaultValue": "##METRIC_MEASURE_COLUMN##", + "metadata": { + "description": "Name of the measure column used in the alert evaluation." + } + }, + "resourceIdColumn": { + "type": "string", + "defaultValue": "##RESOURCE_ID_COLUMN##", + "metadata": { + "description": "Name of the resource ID column used in the alert targeting the alerts." + } + }, + "operator": { + "type": "string", + "defaultValue": "##OPERATOR##", + "allowedValues": [ + "Equals", + "GreaterThan", + "GreaterThanOrEqual", + "LessThan", + "LessThanOrEqual" + ], + "metadata": { + "description": "Operator comparing the current value with the threshold value." + } + }, + "threshold": { + "type": "string", + "defaultValue": "##THRESHOLD##", + "metadata": { + "description": "The threshold value at which the alert is activated." + } + }, + "numberOfEvaluationPeriods": { + "type": "int", + "defaultValue": ##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS##, + "metadata": { + "description": "The number of periods to check in the alert evaluation." + } + }, + "minFailingPeriodsToAlert": { + "type": "int", + "defaultValue": ##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT##, + "metadata": { + "description": "The number of unhealthy periods to alert on (must be lower or equal to numberOfEvaluationPeriods)." + } + }, + "timeAggregation": { + "type": "string", + "defaultValue": "##TIME_AGGREGATION##", + "allowedValues": [ + "Average", + "Minimum", + "Maximum", + "Total", + "Count" + ], + "metadata": { + "description": "How the data that is collected should be combined over time." + } + }, + "windowSize": { + "type": "string", + "defaultValue": "##WINDOW_SIZE##", + "allowedValues": [ + "PT1M", + "PT5M", + "PT15M", + "PT30M", + "PT1H", + "PT6H", + "PT12H", + "PT24H", + "PT1D" + ], + "metadata": { + "description": "Period of time used to monitor alert activity based on the threshold. Must be between one minute and one day. ISO 8601 duration format." + } + }, + "evaluationFrequency": { + "type": "string", + "defaultValue": "##EVALUATION_FREQUENCY##", + "allowedValues": [ + "PT5M", + "PT15M", + "PT30M", + "PT1H" + ], + "metadata": { + "description": "how often the metric alert is evaluated represented in ISO 8601 duration format" + } + }, + "currentDateTimeUtcNow": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "The current date and time using the utcNow function. Used for deployment name uniqueness" + } + }, + "telemetryOptOut": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ], + "metadata": { + "description": "The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry." + } + } + }, + "variables": { + "pidDeploymentName": "[take(concat('##TELEMETRY_PID##-', uniqueString(resourceGroup().id, parameters('alertName'), parameters('currentDateTimeUtcNow'))), 64)]" + }, + "resources": [ + { + "type": "Microsoft.Insights/scheduledQueryRules", + "apiVersion": "2021-08-01", + "name": "[parameters('alertName')]", + "location": "[resourceGroup().location]", + "tags": { + "_deployed_by_amba": true + }, + "properties": { + "description": "[parameters('alertDescription')]", + "severity": "[parameters('alertSeverity')]", + "enabled": "[parameters('isEnabled')]", + "scopes": [ + "[parameters('resourceId')]" + ], + "evaluationFrequency": "[parameters('evaluationFrequency')]", + "windowSize": "[parameters('windowSize')]", + "criteria": { + "allOf": [ + { + "query": "[parameters('query')]", + "metricMeasureColumn": "[parameters('metricMeasureColumn')]", + "resourceIdColumn": "[parameters('resourceIdColumn')]", + "dimensions": ##DIMENSIONS##, + "operator": "[parameters('operator')]", + "threshold": "[parameters('threshold')]", + "timeAggregation": "[parameters('timeAggregation')]", + "failingPeriods": { + "numberOfEvaluationPeriods": "[parameters('numberOfEvaluationPeriods')]", + "minFailingPeriodsToAlert": "[parameters('minFailingPeriodsToAlert')]" + } + } + ] + }, + "muteActionsDuration": "[parameters('muteActionsDuration')]", + "autoMitigate": "[parameters('autoMitigate')]", + "checkWorkspaceAlertsStorageConfigured": "[parameters('checkWorkspaceAlertsStorageConfigured')]" + } + }, + { + "condition": "[equals(parameters('telemetryOptOut'), 'No')]", + "apiVersion": "2020-06-01", + "name": "[variables('pidDeploymentName')]", + "type": "Microsoft.Resources/deployments", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + } + ] +} diff --git a/tooling/generate-templates/templates/arm/metric-dynamic.json b/tooling/generate-templates/templates/arm/metric-dynamic.json new file mode 100644 index 000000000..f7184178f --- /dev/null +++ b/tooling/generate-templates/templates/arm/metric-dynamic.json @@ -0,0 +1,219 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "alertName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Name of the alert" + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "##DESCRIPTION##", + "metadata": { + "description": "Description of alert" + } + }, + "targetResourceId": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "List of Azure resource Ids seperated by a comma. For example - /subscriptions/00000000-0000-0000-0000-0000-00000000/resourceGroup/resource-group-name/Microsoft.compute/virtualMachines/vm-name" + } + }, + "targetResourceRegion": { + "type": "string", + "metadata": { + "description": "Azure region in which target resources to be monitored are in (without spaces). For example: EastUS" + } + }, + "targetResourceType": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Resource type of target resources to be monitored." + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Specifies whether the alert is enabled" + } + }, + "alertSeverity": { + "type": "int", + "defaultValue": ##SEVERITY##, + "allowedValues": [ + 0, + 1, + 2, + 3, + 4 + ], + "metadata": { + "description": "Severity of alert {0,1,2,3,4}" + } + }, + "operator": { + "type": "string", + "defaultValue": "##OPERATOR##", + "allowedValues": [ + "GreaterThan", + "LessThan", + "GreaterOrLessThan" + ], + "metadata": { + "description": "Operator comparing the current value with the threshold value." + } + }, + "alertSensitivity": { + "type": "string", + "defaultValue": "##ALERT_SENSITIVITY##", + "allowedValues": [ + "High", + "Medium", + "Low" + ], + "metadata": { + "description": "Tunes how 'noisy' the Dynamic Thresholds alerts will be: 'High' will result in more alerts while 'Low' will result in fewer alerts." + } + }, + "numberOfEvaluationPeriods": { + "type": "int", + "defaultValue": ##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS##, + "metadata": { + "description": "The number of periods to check in the alert evaluation." + } + }, + "minFailingPeriodsToAlert": { + "type": "int", + "defaultValue": ##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT##, + "metadata": { + "description": "The number of unhealthy periods to alert on (must be lower or equal to numberOfEvaluationPeriods)." + } + }, + "timeAggregation": { + "type": "string", + "defaultValue": "##TIME_AGGREGATION##", + "allowedValues": [ + "Average", + "Minimum", + "Maximum", + "Total", + "Count" + ], + "metadata": { + "description": "How the data that is collected should be combined over time." + } + }, + "windowSize": { + "type": "string", + "defaultValue": "##WINDOW_SIZE##", + "allowedValues": [ + "PT1M", + "PT5M", + "PT15M", + "PT30M", + "PT1H", + "PT6H", + "PT12H", + "PT24H", + "PT1D" + ], + "metadata": { + "description": "Period of time used to monitor alert activity based on the threshold. Must be between five minutes and one hour. ISO 8601 duration format." + } + }, + "evaluationFrequency": { + "type": "string", + "defaultValue": "##EVALUATION_FREQUENCY##", + "allowedValues": [ + "PT5M", + "PT15M", + "PT30M", + "PT1H" + ], + "metadata": { + "description": "how often the metric alert is evaluated represented in ISO 8601 duration format" + } + }, + "currentDateTimeUtcNow": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "The current date and time using the utcNow function. Used for deployment name uniqueness" + } + }, + "telemetryOptOut": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ], + "metadata": { + "description": "The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry." + } + } + }, + "variables": { + "pidDeploymentName": "[take(concat('##TELEMETRY_PID##-', uniqueString(resourceGroup().id, parameters('alertName'), parameters('currentDateTimeUtcNow'))), 64)]", + "varTargetResourceId": "[split(parameters('targetResourceId'), ',')]" + }, + "resources": [ + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2018-03-01", + "name": "[parameters('alertName')]", + "location": "global", + "tags": { + "_deployed_by_amba": true + }, + "properties": { + "description": "[parameters('alertDescription')]", + "scopes": "[variables('varTargetResourceId')]", + "targetResourceType": "[parameters('targetResourceType')]", + "targetResourceRegion": "[parameters('targetResourceRegion')]", + "severity": "[parameters('alertSeverity')]", + "enabled": "[parameters('isEnabled')]", + "evaluationFrequency": "[parameters('evaluationFrequency')]", + "windowSize": "[parameters('windowSize')]", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria", + "allOf": [ + { + "criterionType": "DynamicThresholdCriterion", + "name": "1st criterion", + "metricName": "##METRIC_NAME##", + "dimensions": ##DIMENSIONS##, + "operator": "[parameters('operator')]", + "alertSensitivity": "[parameters('alertSensitivity')]", + "failingPeriods": { + "numberOfEvaluationPeriods": "[parameters('numberOfEvaluationPeriods')]", + "minFailingPeriodsToAlert": "[parameters('minFailingPeriodsToAlert')]" + }, + "timeAggregation": "[parameters('timeAggregation')]" + } + ] + } + } + }, + { + "condition": "[equals(parameters('telemetryOptOut'), 'No')]", + "apiVersion": "2020-06-01", + "name": "[variables('pidDeploymentName')]", + "type": "Microsoft.Resources/deployments", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + } + ] +} diff --git a/tooling/generate-templates/templates/arm/metric-static.json b/tooling/generate-templates/templates/arm/metric-static.json new file mode 100644 index 000000000..01d14e539 --- /dev/null +++ b/tooling/generate-templates/templates/arm/metric-static.json @@ -0,0 +1,199 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "alertName": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Name of the alert" + } + }, + "alertDescription": { + "type": "string", + "defaultValue": "##DESCRIPTION##", + "metadata": { + "description": "Description of alert" + } + }, + "targetResourceId": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "List of Azure resource Ids seperated by a comma. For example - /subscriptions/00000000-0000-0000-0000-0000-00000000/resourceGroup/resource-group-name/Microsoft.compute/virtualMachines/vm-name" + } + }, + "targetResourceRegion": { + "type": "string", + "metadata": { + "description": "Azure region in which target resources to be monitored are in (without spaces). For example: EastUS" + } + }, + "targetResourceType": { + "type": "string", + "minLength": 1, + "metadata": { + "description": "Resource type of target resources to be monitored." + } + }, + "isEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Specifies whether the alert is enabled" + } + }, + "alertSeverity": { + "type": "int", + "defaultValue": ##SEVERITY##, + "allowedValues": [ + 0, + 1, + 2, + 3, + 4 + ], + "metadata": { + "description": "Severity of alert {0,1,2,3,4}" + } + }, + "operator": { + "type": "string", + "defaultValue": "##OPERATOR##", + "allowedValues": [ + "Equals", + "GreaterThan", + "GreaterThanOrEqual", + "LessThan", + "LessThanOrEqual" + ], + "metadata": { + "description": "Operator comparing the current value with the threshold value." + } + }, + "threshold": { + "type": "string", + "defaultValue": "##THRESHOLD##", + "metadata": { + "description": "The threshold value at which the alert is activated." + } + }, + "timeAggregation": { + "type": "string", + "defaultValue": "##TIME_AGGREGATION##", + "allowedValues": [ + "Average", + "Minimum", + "Maximum", + "Total", + "Count" + ], + "metadata": { + "description": "How the data that is collected should be combined over time." + } + }, + "windowSize": { + "type": "string", + "defaultValue": "##WINDOW_SIZE##", + "allowedValues": [ + "PT1M", + "PT5M", + "PT15M", + "PT30M", + "PT1H", + "PT6H", + "PT12H", + "PT24H", + "PT1D" + ], + "metadata": { + "description": "Period of time used to monitor alert activity based on the threshold. Must be between one minute and one day. ISO 8601 duration format." + } + }, + "evaluationFrequency": { + "type": "string", + "defaultValue": "##EVALUATION_FREQUENCY##", + "allowedValues": [ + "PT1M", + "PT5M", + "PT15M", + "PT30M", + "PT1H" + ], + "metadata": { + "description": "how often the metric alert is evaluated represented in ISO 8601 duration format" + } + }, + "currentDateTimeUtcNow": { + "type": "string", + "defaultValue": "[utcNow()]", + "metadata": { + "description": "The current date and time using the utcNow function. Used for deployment name uniqueness" + } + }, + "telemetryOptOut": { + "type": "string", + "defaultValue": "No", + "allowedValues": [ + "Yes", + "No" + ], + "metadata": { + "description": "The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry." + } + } + }, + "variables": { + "pidDeploymentName": "[take(concat('##TELEMETRY_PID##-', uniqueString(resourceGroup().id, parameters('alertName'), parameters('currentDateTimeUtcNow'))), 64)]", + "varTargetResourceId": "[split(parameters('targetResourceId'), ',')]" + }, + "resources": [ + { + "type": "Microsoft.Insights/metricAlerts", + "apiVersion": "2018-03-01", + "name": "[parameters('alertName')]", + "location": "global", + "tags": { + "_deployed_by_amba": true + }, + "properties": { + "description": "[parameters('alertDescription')]", + "scopes": "[variables('varTargetResourceId')]", + "targetResourceType": "[parameters('targetResourceType')]", + "targetResourceRegion": "[parameters('targetResourceRegion')]", + "severity": "[parameters('alertSeverity')]", + "enabled": "[parameters('isEnabled')]", + "evaluationFrequency": "[parameters('evaluationFrequency')]", + "windowSize": "[parameters('windowSize')]", + "criteria": { + "odata.type": "Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria", + "allOf": [ + { + "name": "1st criterion", + "metricName": "##METRIC_NAME##", + "dimensions": ##DIMENSIONS##, + "operator": "[parameters('operator')]", + "threshold": "[parameters('threshold')]", + "timeAggregation": "[parameters('timeAggregation')]", + "criterionType": "StaticThresholdCriterion" + } + ] + } + } + }, + { + "condition": "[equals(parameters('telemetryOptOut'), 'No')]", + "apiVersion": "2020-06-01", + "name": "[variables('pidDeploymentName')]", + "type": "Microsoft.Resources/deployments", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] + } + } + } + ] +} diff --git a/tooling/generate-templates/templates/bicep/activity-administrative.bicep b/tooling/generate-templates/templates/bicep/activity-administrative.bicep new file mode 100644 index 000000000..53c404616 --- /dev/null +++ b/tooling/generate-templates/templates/bicep/activity-administrative.bicep @@ -0,0 +1,68 @@ +@description('Unique name (within the Resource Group) for the Activity log alert.') +@minLength(1) +param alertName string + +@description('Description of alert') +param alertDescription string = '##DESCRIPTION##' + +@description('Indicates whether or not the alert is enabled.') +param isEnabled bool = true + +@description('"The current date and time using the utcNow function. Used for deployment name uniqueness') +param currentDateTimeUtcNow string = utcNow() + +@description('The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry.') +@allowed([ + 'Yes' + 'No' +]) +param telemetryOptOut string = 'No' + +resource symbolicname 'Microsoft.Insights/activityLogAlerts@2023-01-01-preview' = { + name: alertName + location: 'Global' + tags: { + _deployed_by_amba: 'true' + } + properties: { + description: alertDescription + scopes: [ + subscription().id + ] + enabled: isEnabled + condition: { + allOf: [ + { + { + field: 'category' + equals: 'Administrative' + } + { + field: 'operationName' + equals: '##OPERATION_NAME##' + } + { + field: 'status' + containsAny: ##STATUS## + } + } + ] + } + } +} + +var ambaTelemetryPidName = '##TELEMETRY_PID##-${uniqueString(resourceGroup().id, alertName, currentDateTimeUtcNow)}' +resource ambaTelemetryPid 'Microsoft.Resources/deployments@2020-06-01' = if (telemetryOptOut == 'No') { + name: ambaTelemetryPidName + tags: { + _deployed_by_amba: 'true' + } + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} diff --git a/tooling/generate-templates/templates/bicep/activity-resourcehealth.bicep b/tooling/generate-templates/templates/bicep/activity-resourcehealth.bicep new file mode 100644 index 000000000..e993691b9 --- /dev/null +++ b/tooling/generate-templates/templates/bicep/activity-resourcehealth.bicep @@ -0,0 +1,66 @@ +@description('Unique name (within the Resource Group) for the Activity log alert.') +@minLength(1) +param alertName string + +@description('Description of alert') +param alertDescription string = '##DESCRIPTION##' + +@description('Indicates whether or not the alert is enabled.') +param isEnabled bool = true + +@description('"The current date and time using the utcNow function. Used for deployment name uniqueness') +param currentDateTimeUtcNow string = utcNow() + +@description('The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry.') +@allowed([ + 'Yes' + 'No' +]) +param telemetryOptOut string = 'No' + +resource symbolicname 'Microsoft.Insights/activityLogAlerts@2023-01-01-preview' = { + name: alertName + location: 'Global' + tags: { + _deployed_by_amba: 'true' + } + properties: { + description: alertDescription + scopes: [ + subscription().id + ] + enabled: isEnabled + condition: { + allOf: [ + { + field: 'category' + equals: 'ResourceHealth' + } + { + anyOf: [##CAUSES## + ] + } + { + anyOf: [##CURRENT_HEALTH_STATUS## + ] + } + ] + } + } +} + +var ambaTelemetryPidName = '##TELEMETRY_PID##-${uniqueString(resourceGroup().id, alertName, currentDateTimeUtcNow)}' +resource ambaTelemetryPid 'Microsoft.Resources/deployments@2020-06-01' = if (telemetryOptOut == 'No') { + name: ambaTelemetryPidName + tags: { + _deployed_by_amba: 'true' + } + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} diff --git a/tooling/generate-templates/templates/bicep/activity-servicehealth.bicep b/tooling/generate-templates/templates/bicep/activity-servicehealth.bicep new file mode 100644 index 000000000..36e9470f7 --- /dev/null +++ b/tooling/generate-templates/templates/bicep/activity-servicehealth.bicep @@ -0,0 +1,64 @@ +@description('Unique name (within the Resource Group) for the Activity log alert.') +@minLength(1) +param alertName string + +@description('Description of alert') +param alertDescription string = '##DESCRIPTION##' + +@description('Indicates whether or not the alert is enabled.') +param isEnabled bool = true + +@description('"The current date and time using the utcNow function. Used for deployment name uniqueness') +param currentDateTimeUtcNow string = utcNow() + +@description('The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry.') +@allowed([ + 'Yes' + 'No' +]) +param telemetryOptOut string = 'No' + +resource symbolicname 'Microsoft.Insights/activityLogAlerts@2023-01-01-preview' = { + name: alertName + location: 'Global' + tags: { + _deployed_by_amba: 'true' + } + properties: { + description: alertDescription + scopes: [ + subscription().id + ] + enabled: isEnabled + condition: { + allOf: [ + { + { + field: 'category' + equals: 'ServiceHealth' + } + { + field: 'properties.incidentType' + equals: '##INCIDENT_TYPE##' + } + } + ] + } + } +} + +var ambaTelemetryPidName = '##TELEMETRY_PID##-${uniqueString(resourceGroup().id, alertName, currentDateTimeUtcNow)}' +resource ambaTelemetryPid 'Microsoft.Resources/deployments@2020-06-01' = if (telemetryOptOut == 'No') { + name: ambaTelemetryPidName + tags: { + _deployed_by_amba: 'true' + } + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} diff --git a/tooling/generate-templates/templates/bicep/log.bicep b/tooling/generate-templates/templates/bicep/log.bicep new file mode 100644 index 000000000..7387bc999 --- /dev/null +++ b/tooling/generate-templates/templates/bicep/log.bicep @@ -0,0 +1,168 @@ +@description('Name of the alert') +@minLength(1) +param alertName string + +@description('Description of alert') +param alertDescription string = '##DESCRIPTION##' + +@description('Specifies whether the alert is enabled') +param isEnabled bool = true + +@description('Specifies whether to check linked storage and fail creation if the storage was not found') +param checkWorkspaceAlertsStorageConfigured bool = false + +@description('Full Resource ID of the resource emitting the metric that will be used for the comparison. For example /subscriptions/00000000-0000-0000-0000-0000-00000000/resourceGroups/ResourceGroupName/providers/Microsoft.compute/virtualMachines/VM_xyz') +@minLength(1) +param resourceId string + +@description('Mute actions for the chosen period of time (in ISO 8601 duration format) after the alert is fired.') +@allowed([ + 'PT1M' + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' + 'PT6H' + 'PT12H' + 'PT24H' +]) +param muteActionsDuration string + +@description('Severity of alert {0,1,2,3,4}') +@allowed([ + 0 + 1 + 2 + 3 + 4 +]) +param alertSeverity int = ##SEVERITY## + +@description('Specifies whether the alert will automatically resolve') +param autoMitigate bool = ##AUTO_MITIGATE## + +@description('Name of the metric used in the comparison to activate the alert.') +@minLength(1) +param query string = '##QUERY##' + +@description('Name of the measure column used in the alert evaluation.') +param metricMeasureColumn string = '##METRIC_MEASURE_COLUMN##' + +@description('Name of the resource ID column used in the alert targeting the alerts.') +param resourceIdColumn string = '##RESOURCE_ID_COLUMN##' + +@description('Operator comparing the current value with the threshold value.') +@allowed([ + 'Equals' + 'GreaterThan' + 'GreaterThanOrEqual' + 'LessThan' + 'LessThanOrEqual' +]) +param operator string = '##OPERATOR##' + +@description('The threshold value at which the alert is activated.') +param threshold int = ##THRESHOLD## + +@description('The number of periods to check in the alert evaluation.') +param numberOfEvaluationPeriods int = ##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS## + +@description('The number of unhealthy periods to alert on (must be lower or equal to numberOfEvaluationPeriods).') +param minFailingPeriodsToAlert int = ##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT## + +@description('How the data that is collected should be combined over time.') +@allowed([ + 'Average' + 'Minimum' + 'Maximum' + 'Total' + 'Count' +]) +param timeAggregation string = '##TIME_AGGREGATION##' + +@description('Period of time used to monitor alert activity based on the threshold. Must be between one minute and one day. ISO 8601 duration format.') +@allowed([ + 'PT1M' + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' + 'PT6H' + 'PT12H' + 'PT24H' + 'P1D' +]) +param windowSize string = '##WINDOW_SIZE##' + +@description('how often the metric alert is evaluated represented in ISO 8601 duration format') +@allowed([ + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' +]) +param evaluationFrequency string = '##EVALUATION_FREQUENCY##' + +@description('"The current date and time using the utcNow function. Used for deployment name uniqueness') +param currentDateTimeUtcNow string = utcNow() + +@description('The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry.') +@allowed([ + 'Yes' + 'No' +]) +param telemetryOptOut string = 'No' + +resource alert 'Microsoft.Insights/scheduledQueryRules@2021-08-01' = { + name: alertName + location: resourceGroup().location + tags: { + _deployed_by_amba: 'true' + } + properties: { + description: alertDescription + severity: alertSeverity + enabled: isEnabled + scopes: [ + resourceId + ] + evaluationFrequency: evaluationFrequency + windowSize: windowSize + criteria: { + allOf: [ + { + query: query + metricMeasureColumn: metricMeasureColumn + resourceIdColumn: resourceIdColumn + dimensions: [##DIMENSIONS##] + operator: operator + threshold: threshold + timeAggregation: timeAggregation + failingPeriods: { + numberOfEvaluationPeriods: numberOfEvaluationPeriods + minFailingPeriodsToAlert: minFailingPeriodsToAlert + } + } + ] + } + muteActionsDuration: muteActionsDuration + autoMitigate: autoMitigate + checkWorkspaceAlertsStorageConfigured: checkWorkspaceAlertsStorageConfigured + } +} + +var ambaTelemetryPidName = '##TELEMETRY_PID##-${uniqueString(resourceGroup().id, alertName, currentDateTimeUtcNow)}' +resource ambaTelemetryPid 'Microsoft.Resources/deployments@2020-06-01' = if (telemetryOptOut == 'No') { + name: ambaTelemetryPidName + tags: { + _deployed_by_amba: 'true' + } + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} diff --git a/tooling/generate-templates/templates/bicep/metric-dynamic.bicep b/tooling/generate-templates/templates/bicep/metric-dynamic.bicep new file mode 100644 index 000000000..77a4a28da --- /dev/null +++ b/tooling/generate-templates/templates/bicep/metric-dynamic.bicep @@ -0,0 +1,147 @@ +@description('Name of the alert') +@minLength(1) +param alertName string + +@description('Description of alert') +param alertDescription string = '##DESCRIPTION##' + +@description('array of Azure resource Ids. For example - /subscriptions/00000000-0000-0000-0000-0000-00000000/resourceGroup/resource-group-name/Microsoft.compute/virtualMachines/vm-name') +@minLength(1) +param targetResourceId array + +@description('Azure region in which target resources to be monitored are in (without spaces). For example: EastUS') +param targetResourceRegion string + +@description('Resource type of target resources to be monitored.') +@minLength(1) +param targetResourceType string + +@description('Specifies whether the alert is enabled') +param isEnabled bool = true + +@description('Severity of alert {0,1,2,3,4}') +@allowed([ + 0 + 1 + 2 + 3 + 4 +]) +param alertSeverity int = ##SEVERITY## + +@description('Operator comparing the current value with the threshold value.') +@allowed([ + 'GreaterThan' + 'LessThan' + 'GreaterOrLessThan' +]) +param operator string = '##OPERATOR##' + +@description('Tunes how \'noisy\' the Dynamic Thresholds alerts will be: \'High\' will result in more alerts while \'Low\' will result in fewer alerts.') +@allowed([ + 'High' + 'Medium' + 'Low' +]) +param alertSensitivity string = '##ALERT_SENSITIVITY##' + +@description('The number of periods to check in the alert evaluation.') +param numberOfEvaluationPeriods int = ##FAILING_PERIODS_NUMBER_OF_EVALUATION_PERIODS## + +@description('The number of unhealthy periods to alert on (must be lower or equal to numberOfEvaluationPeriods).') +param minFailingPeriodsToAlert int = ##FAILING_PERIODS_MIN_FAILING_PERIODS_TO_ALERT## + +@description('How the data that is collected should be combined over time.') +@allowed([ + 'Average' + 'Minimum' + 'Maximum' + 'Total' + 'Count' +]) +param timeAggregation string = '##TIME_AGGREGATION##' + +@description('Period of time used to monitor alert activity based on the threshold. Must be between five minutes and one hour. ISO 8601 duration format.') +@allowed([ + 'PT1M' + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' + 'PT6H' + 'PT12H' + 'PT24H' + 'P1D' +]) +param windowSize string = '##WINDOW_SIZE##' + +@description('how often the metric alert is evaluated represented in ISO 8601 duration format') +@allowed([ + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' +]) +param evaluationFrequency string = '##EVALUATION_FREQUENCY##' + +@description('"The current date and time using the utcNow function. Used for deployment name uniqueness') +param currentDateTimeUtcNow string = utcNow() + +@description('The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry.') +@allowed([ + 'Yes' + 'No' +]) +param telemetryOptOut string = 'No' + +resource metricAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = { + name: alertName + location: 'global' + tags: { + _deployed_by_amba: 'true' + } + properties: { + description: alertDescription + scopes: targetResourceId + targetResourceType: targetResourceType + targetResourceRegion: targetResourceRegion + severity: alertSeverity + enabled: isEnabled + evaluationFrequency: evaluationFrequency + windowSize: windowSize + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria' + allOf: [ + { + criterionType: 'DynamicThresholdCriterion' + name: '1st criterion' + metricName: '##METRIC_NAME##' + dimensions: [##DIMENSIONS##] + operator: operator + alertSensitivity: alertSensitivity + failingPeriods: { + numberOfEvaluationPeriods: numberOfEvaluationPeriods + minFailingPeriodsToAlert: minFailingPeriodsToAlert + } + timeAggregation: timeAggregation + } + ] + } + } +} + +var ambaTelemetryPidName = '##TELEMETRY_PID##-${uniqueString(resourceGroup().id, alertName, currentDateTimeUtcNow)}' +resource ambaTelemetryPid 'Microsoft.Resources/deployments@2020-06-01' = if (telemetryOptOut == 'No') { + name: ambaTelemetryPidName + tags: { + _deployed_by_amba: 'true' + } + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +} diff --git a/tooling/generate-templates/templates/bicep/metric-static.bicep b/tooling/generate-templates/templates/bicep/metric-static.bicep new file mode 100644 index 000000000..b4511d07d --- /dev/null +++ b/tooling/generate-templates/templates/bicep/metric-static.bicep @@ -0,0 +1,135 @@ +@description('Name of the alert') +@minLength(1) +param alertName string + +@description('Description of alert') +param alertDescription string = '##DESCRIPTION##' + +@description('Array of Azure resource Ids. For example - /subscriptions/00000000-0000-0000-0000-0000-00000000/resourceGroup/resource-group-name/Microsoft.compute/virtualMachines/vm-name') +@minLength(1) +param targetResourceId array + +@description('Azure region in which target resources to be monitored are in (without spaces). For example: EastUS') +param targetResourceRegion string + +@description('Resource type of target resources to be monitored.') +@minLength(1) +param targetResourceType string + +@description('Specifies whether the alert is enabled') +param isEnabled bool = true + +@description('Severity of alert {0,1,2,3,4}') +@allowed([ + 0 + 1 + 2 + 3 + 4 +]) +param alertSeverity int = ##SEVERITY## + +@description('Operator comparing the current value with the threshold value.') +@allowed([ + 'Equals' + 'GreaterThan' + 'GreaterThanOrEqual' + 'LessThan' + 'LessThanOrEqual' +]) +param operator string = '##OPERATOR##' + +@description('The threshold value at which the alert is activated.') +param threshold int = ##THRESHOLD## + +@description('How the data that is collected should be combined over time.') +@allowed([ + 'Average' + 'Minimum' + 'Maximum' + 'Total' + 'Count' +]) +param timeAggregation string = '##TIME_AGGREGATION##' + +@description('Period of time used to monitor alert activity based on the threshold. Must be between one minute and one day. ISO 8601 duration format.') +@allowed([ + 'PT1M' + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' + 'PT6H' + 'PT12H' + 'PT24H' + 'P1D' +]) +param windowSize string = '##WINDOW_SIZE##' + +@description('how often the metric alert is evaluated represented in ISO 8601 duration format') +@allowed([ + 'PT1M' + 'PT5M' + 'PT15M' + 'PT30M' + 'PT1H' +]) +param evaluationFrequency string = '##EVALUATION_FREQUENCY##' + +@description('"The current date and time using the utcNow function. Used for deployment name uniqueness') +param currentDateTimeUtcNow string = utcNow() + +@description('The customer usage identifier used for telemetry purposes. The default value of False enables telemetry. The value of True disables telemetry.') +@allowed([ + 'Yes' + 'No' +]) +param telemetryOptOut string = 'No' + +resource metricAlert 'Microsoft.Insights/metricAlerts@2018-03-01' = { + name: alertName + location: 'global' + tags: { + _deployed_by_amba: 'true' + } + properties: { + description: alertDescription + scopes: targetResourceId + targetResourceType: targetResourceType + targetResourceRegion: targetResourceRegion + severity: alertSeverity + enabled: isEnabled + evaluationFrequency: evaluationFrequency + windowSize: windowSize + criteria: { + 'odata.type': 'Microsoft.Azure.Monitor.MultipleResourceMultipleMetricCriteria' + allOf: [ + { + name: '1st criterion' + metricName: '##METRIC_NAME##' + dimensions: [##DIMENSIONS##] + operator: operator + threshold: threshold + timeAggregation: timeAggregation + criterionType: 'StaticThresholdCriterion' + } + ] + } + } +} + +var ambaTelemetryPidName = '##TELEMETRY_PID##-${uniqueString(resourceGroup().id, alertName, currentDateTimeUtcNow)}' +resource ambaTelemetryPid 'Microsoft.Resources/deployments@2020-06-01' = if (telemetryOptOut == 'No') { + name: ambaTelemetryPidName + tags: { + _deployed_by_amba: 'true' + } + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + } + } +}