From ef150e930a223581589f90e1283d3fef8bee30e8 Mon Sep 17 00:00:00 2001 From: Kris Baranek Date: Fri, 15 Dec 2023 22:42:43 +0100 Subject: [PATCH] feat: New Module `avm/res/insights/webtest` (#728) ## Description New Module `avm/res/insights/webtest`, migrated from CARML. ## Adding a new module - [x] A proposal has been submitted and approved. - [ ] I have included "Closes #{module_proposal_issue_number}" in the PR description. - [ ] I have run `brm validate` locally to verify the module files. - [x] I have run deployment tests locally to ensure the module is deployable. ## Pipeline references | Pipeline | | - | | [![avm.res.insights.webtest](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml/badge.svg?branch=users%2Fkrbar%2FwebtestModule)](https://github.com/krbar/bicep-registry-modules/actions/workflows/avm.res.insights.webtest.yml) | --- .github/CODEOWNERS | 2 +- .../workflows/avm.res.insights.webtest.yml | 83 +++ avm/res/insights/webtest/ORPHANED.md | 4 + avm/res/insights/webtest/README.md | 661 ++++++++++++++++++ avm/res/insights/webtest/main.bicep | 201 ++++++ avm/res/insights/webtest/main.json | 379 ++++++++++ .../tests/e2e/defaults/dependencies.bicep | 26 + .../tests/e2e/defaults/main.test.bicep | 62 ++ .../webtest/tests/e2e/max/dependencies.bicep | 37 + .../webtest/tests/e2e/max/main.test.bicep | 95 +++ .../tests/e2e/waf-aligned/dependencies.bicep | 26 + .../tests/e2e/waf-aligned/main.test.bicep | 71 ++ avm/res/insights/webtest/version.json | 7 + 13 files changed, 1653 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/avm.res.insights.webtest.yml create mode 100644 avm/res/insights/webtest/ORPHANED.md create mode 100644 avm/res/insights/webtest/README.md create mode 100644 avm/res/insights/webtest/main.bicep create mode 100644 avm/res/insights/webtest/main.json create mode 100644 avm/res/insights/webtest/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/res/insights/webtest/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/insights/webtest/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/insights/webtest/tests/e2e/max/main.test.bicep create mode 100644 avm/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/insights/webtest/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 465b399117..8b095bf930 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -63,7 +63,7 @@ /avm/res/insights/metric-alert/ @Azure/avm-res-insights-metricalert-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/insights/private-link-scope/ @Azure/avm-res-insights-privatelinkscope-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/insights/scheduled-query-rule/ @Azure/avm-res-insights-scheduledqueryrule-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/insights/webtest/ @Azure/avm-res-insights-webtest-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/insights/webtest/ @Azure/avm-res-insights-webtest-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/key-vault/vault/ @Azure/avm-res-keyvault-vault-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/kubernetes-configuration/extension/ @Azure/avm-res-kubernetesconfiguration-extension-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/kubernetes-configuration/flux-configuration/ @Azure/avm-res-kubernetesconfiguration-fluxconfiguration-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/workflows/avm.res.insights.webtest.yml b/.github/workflows/avm.res.insights.webtest.yml new file mode 100644 index 0000000000..5fb825b8fd --- /dev/null +++ b/.github/workflows/avm.res.insights.webtest.yml @@ -0,0 +1,83 @@ +name: "avm.res.insights.webtest" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.insights.webtest.yml" + - "avm/res/insights/webtest/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/insights/webtest" + workflowPath: ".github/workflows/avm.res.insights.webtest.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-20.04 + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Module" + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/insights/webtest/ORPHANED.md b/avm/res/insights/webtest/ORPHANED.md new file mode 100644 index 0000000000..ef8fa911d2 --- /dev/null +++ b/avm/res/insights/webtest/ORPHANED.md @@ -0,0 +1,4 @@ +⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ + +- Only security and bug fixes are being handled by the AVM core team at present. +- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/insights/webtest/README.md b/avm/res/insights/webtest/README.md new file mode 100644 index 0000000000..01f43138a3 --- /dev/null +++ b/avm/res/insights/webtest/README.md @@ -0,0 +1,661 @@ +# Web Tests `[Microsoft.Insights/webtests]` + +> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ +> +> - Only security and bug fixes are being handled by the AVM core team at present. +> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! + +This module deploys a Web Test. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/webtests` | [2022-06-15](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2022-06-15/webtests) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/insights/webtest:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +
+ +via Bicep module + +```bicep +module webtest 'br/public:avm/res/insights/webtest:' = { + name: '${uniqueString(deployment().name, location)}-test-iwtmin' + params: { + // Required parameters + appInsightResourceId: '' + name: 'iwtmin001' + request: { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' + } + webTestName: 'wt$iwtmin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "appInsightResourceId": { + "value": "" + }, + "name": { + "value": "iwtmin001" + }, + "request": { + "value": { + "HttpVerb": "GET", + "RequestUrl": "https://learn.microsoft.com/en-us/" + } + }, + "webTestName": { + "value": "wt$iwtmin001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module webtest 'br/public:avm/res/insights/webtest:' = { + name: '${uniqueString(deployment().name, location)}-test-iwtmax' + params: { + // Required parameters + appInsightResourceId: '' + name: 'iwtmax001' + request: { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' + } + webTestName: 'wt$iwtmax001' + // Non-required parameters + location: '' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + syntheticMonitorId: 'iwtmax001' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "appInsightResourceId": { + "value": "" + }, + "name": { + "value": "iwtmax001" + }, + "request": { + "value": { + "HttpVerb": "GET", + "RequestUrl": "https://learn.microsoft.com/en-us/" + } + }, + "webTestName": { + "value": "wt$iwtmax001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "locations": { + "value": [ + { + "Id": "emea-nl-ams-azr" + } + ] + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "syntheticMonitorId": { + "value": "iwtmax001" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module webtest 'br/public:avm/res/insights/webtest:' = { + name: '${uniqueString(deployment().name, location)}-test-iwtwaf' + params: { + // Required parameters + appInsightResourceId: '' + name: 'iwtwaf001' + request: { + HttpVerb: 'GET' + RequestUrl: 'https://learn.microsoft.com/en-us/' + } + webTestName: 'wt$iwtwaf001' + // Non-required parameters + location: '' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + syntheticMonitorId: 'iwtwaf001' + tags: { + 'hidden-title': 'This is visible in the resource name' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "appInsightResourceId": { + "value": "" + }, + "name": { + "value": "iwtwaf001" + }, + "request": { + "value": { + "HttpVerb": "GET", + "RequestUrl": "https://learn.microsoft.com/en-us/" + } + }, + "webTestName": { + "value": "wt$iwtwaf001" + }, + // Non-required parameters + "location": { + "value": "" + }, + "locations": { + "value": [ + { + "Id": "emea-nl-ams-azr" + } + ] + }, + "syntheticMonitorId": { + "value": "iwtwaf001" + }, + "tags": { + "value": { + "hidden-title": "This is visible in the resource name" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appInsightResourceId`](#parameter-appinsightresourceid) | string | Resource ID of the App Insights resource to link with this webtest. | +| [`name`](#parameter-name) | string | Name of the webtest. | +| [`request`](#parameter-request) | object | The collection of request properties. | +| [`webTestName`](#parameter-webtestname) | string | User defined name if this WebTest. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`configuration`](#parameter-configuration) | object | An XML configuration specification for a WebTest. | +| [`description`](#parameter-description) | string | User defined description for this WebTest. | +| [`enabled`](#parameter-enabled) | bool | Is the test actively being monitored. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`frequency`](#parameter-frequency) | int | Interval in seconds between test runs for this WebTest. | +| [`kind`](#parameter-kind) | string | The kind of WebTest that this web test watches. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`locations`](#parameter-locations) | array | List of where to physically run the tests from to give global coverage for accessibility of your application. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`retryEnabled`](#parameter-retryenabled) | bool | Allow for retries should this WebTest fail. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | +| [`syntheticMonitorId`](#parameter-syntheticmonitorid) | string | Unique ID of this WebTest. | +| [`tags`](#parameter-tags) | object | Resource tags. Note: a mandatory tag 'hidden-link' based on the 'appInsightResourceId' parameter will be automatically added to the tags defined here. | +| [`timeout`](#parameter-timeout) | int | Seconds until this WebTest will timeout and fail. | +| [`validationRules`](#parameter-validationrules) | object | The collection of validation rule properties. | + +### Parameter: `appInsightResourceId` + +Resource ID of the App Insights resource to link with this webtest. + +- Required: Yes +- Type: string + +### Parameter: `name` + +Name of the webtest. + +- Required: Yes +- Type: string + +### Parameter: `request` + +The collection of request properties. + +- Required: Yes +- Type: object + +### Parameter: `webTestName` + +User defined name if this WebTest. + +- Required: Yes +- Type: string + +### Parameter: `configuration` + +An XML configuration specification for a WebTest. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `description` + +User defined description for this WebTest. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enabled` + +Is the test actively being monitored. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `frequency` + +Interval in seconds between test runs for this WebTest. + +- Required: No +- Type: int +- Default: `300` + +### Parameter: `kind` + +The kind of WebTest that this web test watches. + +- Required: No +- Type: string +- Default: `'standard'` +- Allowed: + ```Bicep + [ + 'multistep' + 'ping' + 'standard' + ] + ``` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `locations` + +List of where to physically run the tests from to give global coverage for accessibility of your application. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + { + Id: 'us-il-ch1-azr' + } + { + Id: 'us-fl-mia-edge' + } + { + Id: 'latam-br-gru-edge' + } + { + Id: 'apac-sg-sin-azr' + } + { + Id: 'emea-nl-ams-azr' + } + ] + ``` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `retryEnabled` + +Allow for retries should this WebTest fail. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `roleAssignments` + +Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The name of the role to assign. If it cannot be found you can specify the role definition ID instead. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container" | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The name of the role to assign. If it cannot be found you can specify the role definition ID instead. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container" + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `syntheticMonitorId` + +Unique ID of this WebTest. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `tags` + +Resource tags. Note: a mandatory tag 'hidden-link' based on the 'appInsightResourceId' parameter will be automatically added to the tags defined here. + +- Required: No +- Type: object + +### Parameter: `timeout` + +Seconds until this WebTest will timeout and fail. + +- Required: No +- Type: int +- Default: `30` + +### Parameter: `validationRules` + +The collection of validation rule properties. + +- Required: No +- Type: object +- Default: `{}` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the webtest. | +| `resourceGroupName` | string | The resource group the resource was deployed into. | +| `resourceId` | string | The resource ID of the webtest. | + +## Cross-referenced modules + +_None_ diff --git a/avm/res/insights/webtest/main.bicep b/avm/res/insights/webtest/main.bicep new file mode 100644 index 0000000000..f2cb81e56a --- /dev/null +++ b/avm/res/insights/webtest/main.bicep @@ -0,0 +1,201 @@ +metadata name = 'Web Tests' +metadata description = 'This module deploys a Web Test.' +metadata owner = 'Azure/module-maintainers' + +@sys.description('Required. Name of the webtest.') +param name string + +@sys.description('Required. Resource ID of the App Insights resource to link with this webtest.') +param appInsightResourceId string + +@sys.description('Required. User defined name if this WebTest.') +param webTestName string + +@sys.description('Optional. Resource tags. Note: a mandatory tag \'hidden-link\' based on the \'appInsightResourceId\' parameter will be automatically added to the tags defined here.') +param tags object? + +@sys.description('Required. The collection of request properties.') +param request object + +@sys.description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@sys.description('Optional. User defined description for this WebTest.') +param description string = '' + +@sys.description('Optional. Unique ID of this WebTest.') +param syntheticMonitorId string = name + +@sys.description('Optional. The kind of WebTest that this web test watches.') +@allowed([ + 'multistep' + 'ping' + 'standard' +]) +param kind string = 'standard' + +@sys.description('Optional. List of where to physically run the tests from to give global coverage for accessibility of your application.') +param locations array = [ + { + Id: 'us-il-ch1-azr' + } + { + Id: 'us-fl-mia-edge' + } + { + Id: 'latam-br-gru-edge' + } + { + Id: 'apac-sg-sin-azr' + } + { + Id: 'emea-nl-ams-azr' + } +] + +@sys.description('Optional. Is the test actively being monitored.') +param enabled bool = true + +@sys.description('Optional. Interval in seconds between test runs for this WebTest.') +param frequency int = 300 + +@sys.description('Optional. Seconds until this WebTest will timeout and fail.') +param timeout int = 30 + +@sys.description('Optional. Allow for retries should this WebTest fail.') +param retryEnabled bool = true + +@sys.description('Optional. The collection of validation rule properties.') +param validationRules object = {} + +@sys.description('Optional. An XML configuration specification for a WebTest.') +param configuration object = {} + +@sys.description('Optional. The lock settings of the service.') +param lock lockType + +@sys.description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') +param roleAssignments roleAssignmentType + +@sys.description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var hiddenLinkTag = { + 'hidden-link:${appInsightResourceId}': 'Resource' +} + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168') + 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') +} + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) { + name: '46d3xbcp.res.insights-webtest.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource webtest 'Microsoft.Insights/webtests@2022-06-15' = { + name: name + location: location + tags: union(tags ?? {}, hiddenLinkTag) + properties: { + Kind: kind + Locations: locations + Name: webTestName + Description: description + SyntheticMonitorId: syntheticMonitorId + Enabled: enabled + Frequency: frequency + Timeout: timeout + RetryEnabled: retryEnabled + Request: request + ValidationRules: validationRules + Configuration: configuration + } +} + +resource webtest_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.' + } + scope: webtest +} + +resource webtest_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(webtest.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: webtest +}] + +@sys.description('The name of the webtest.') +output name string = webtest.name + +@sys.description('The resource ID of the webtest.') +output resourceId string = webtest.id + +@sys.description('The resource group the resource was deployed into.') +output resourceGroupName string = resourceGroup().name + +@sys.description('The location the resource was deployed into.') +output location string = webtest.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @sys.description('Optional. Specify the name of lock.') + name: string? + + @sys.description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @sys.description('Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead.') + roleDefinitionIdOrName: string + + @sys.description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @sys.description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @sys.description('Optional. The description of the role assignment.') + description: string? + + @sys.description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container"') + condition: string? + + @sys.description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @sys.description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/insights/webtest/main.json b/avm/res/insights/webtest/main.json new file mode 100644 index 0000000000..65c5bb59b6 --- /dev/null +++ b/avm/res/insights/webtest/main.json @@ -0,0 +1,379 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "15597399930177304296" + }, + "name": "Web Tests", + "description": "This module deploys a Web Test.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The name of the role to assign. If it cannot be found you can specify the role definition ID instead." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"" + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the webtest." + } + }, + "appInsightResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the App Insights resource to link with this webtest." + } + }, + "webTestName": { + "type": "string", + "metadata": { + "description": "Required. User defined name if this WebTest." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags. Note: a mandatory tag 'hidden-link' based on the 'appInsightResourceId' parameter will be automatically added to the tags defined here." + } + }, + "request": { + "type": "object", + "metadata": { + "description": "Required. The collection of request properties." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "description": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. User defined description for this WebTest." + } + }, + "syntheticMonitorId": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Unique ID of this WebTest." + } + }, + "kind": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "multistep", + "ping", + "standard" + ], + "metadata": { + "description": "Optional. The kind of WebTest that this web test watches." + } + }, + "locations": { + "type": "array", + "defaultValue": [ + { + "Id": "us-il-ch1-azr" + }, + { + "Id": "us-fl-mia-edge" + }, + { + "Id": "latam-br-gru-edge" + }, + { + "Id": "apac-sg-sin-azr" + }, + { + "Id": "emea-nl-ams-azr" + } + ], + "metadata": { + "description": "Optional. List of where to physically run the tests from to give global coverage for accessibility of your application." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Is the test actively being monitored." + } + }, + "frequency": { + "type": "int", + "defaultValue": 300, + "metadata": { + "description": "Optional. Interval in seconds between test runs for this WebTest." + } + }, + "timeout": { + "type": "int", + "defaultValue": 30, + "metadata": { + "description": "Optional. Seconds until this WebTest will timeout and fail." + } + }, + "retryEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Allow for retries should this WebTest fail." + } + }, + "validationRules": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. The collection of validation rule properties." + } + }, + "configuration": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. An XML configuration specification for a WebTest." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "hiddenLinkTag": { + "[format('hidden-link:{0}', parameters('appInsightResourceId'))]": "Resource" + }, + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.insights-webtest.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "webtest": { + "type": "Microsoft.Insights/webtests", + "apiVersion": "2022-06-15", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[union(coalesce(parameters('tags'), createObject()), variables('hiddenLinkTag'))]", + "properties": { + "Kind": "[parameters('kind')]", + "Locations": "[parameters('locations')]", + "Name": "[parameters('webTestName')]", + "Description": "[parameters('description')]", + "SyntheticMonitorId": "[parameters('syntheticMonitorId')]", + "Enabled": "[parameters('enabled')]", + "Frequency": "[parameters('frequency')]", + "Timeout": "[parameters('timeout')]", + "RetryEnabled": "[parameters('retryEnabled')]", + "Request": "[parameters('request')]", + "ValidationRules": "[parameters('validationRules')]", + "Configuration": "[parameters('configuration')]" + } + }, + "webtest_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Insights/webtests/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "webtest" + ] + }, + "webtest_roleAssignments": { + "copy": { + "name": "webtest_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/webtests/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Insights/webtests', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "webtest" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the webtest." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webtest." + }, + "value": "[resourceId('Microsoft.Insights/webtests', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the resource was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webtest', '2022-06-15', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/insights/webtest/tests/e2e/defaults/dependencies.bicep b/avm/res/insights/webtest/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..79e003515d --- /dev/null +++ b/avm/res/insights/webtest/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,26 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param appInsightName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +resource appInsight 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output appInsightResourceId string = appInsight.id diff --git a/avm/res/insights/webtest/tests/e2e/defaults/main.test.bicep b/avm/res/insights/webtest/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..15351e1d6d --- /dev/null +++ b/avm/res/insights/webtest/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,62 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.webtests-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param location string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iwtmin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + appInsightName: 'dep-${namePrefix}-appi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + appInsightResourceId: nestedDependencies.outputs.appInsightResourceId + webTestName: 'wt${namePrefix}$${serviceShort}001' + request: { + RequestUrl: 'https://learn.microsoft.com/en-us/' + HttpVerb: 'GET' + } + } +}] diff --git a/avm/res/insights/webtest/tests/e2e/max/dependencies.bicep b/avm/res/insights/webtest/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..51098662db --- /dev/null +++ b/avm/res/insights/webtest/tests/e2e/max/dependencies.bicep @@ -0,0 +1,37 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param appInsightName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource appInsight 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output appInsightResourceId string = appInsight.id + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/insights/webtest/tests/e2e/max/main.test.bicep b/avm/res/insights/webtest/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..798c1e42ea --- /dev/null +++ b/avm/res/insights/webtest/tests/e2e/max/main.test.bicep @@ -0,0 +1,95 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.webtests-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param location string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iwtmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + appInsightName: 'dep-${namePrefix}-appi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + appInsightResourceId: nestedDependencies.outputs.appInsightResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + webTestName: 'wt${namePrefix}$${serviceShort}001' + syntheticMonitorId: '${namePrefix}${serviceShort}001' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + request: { + RequestUrl: 'https://learn.microsoft.com/en-us/' + HttpVerb: 'GET' + } + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + } +}] diff --git a/avm/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..79e003515d --- /dev/null +++ b/avm/res/insights/webtest/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,26 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Log Analytics Workspace to create.') +param appInsightName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2021-06-01' = { + name: logAnalyticsWorkspaceName + location: location +} + +resource appInsight 'Microsoft.Insights/components@2020-02-02' = { + name: appInsightName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspace.id + } +} + +@description('The resource ID of the created Log Analytics Workspace.') +output appInsightResourceId string = appInsight.id diff --git a/avm/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep b/avm/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..7514fdacdf --- /dev/null +++ b/avm/res/insights/webtest/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,71 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-insights.webtests-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param location string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'iwtwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: location +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-nestedDependencies' + params: { + appInsightName: 'dep-${namePrefix}-appi-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + location: location + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: location + appInsightResourceId: nestedDependencies.outputs.appInsightResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + } + webTestName: 'wt${namePrefix}$${serviceShort}001' + syntheticMonitorId: '${namePrefix}${serviceShort}001' + locations: [ + { + Id: 'emea-nl-ams-azr' + } + ] + request: { + RequestUrl: 'https://learn.microsoft.com/en-us/' + HttpVerb: 'GET' + } + } +}] diff --git a/avm/res/insights/webtest/version.json b/avm/res/insights/webtest/version.json new file mode 100644 index 0000000000..83083db694 --- /dev/null +++ b/avm/res/insights/webtest/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} \ No newline at end of file