From fbe86926c78b1df30d77fedbacdb36f88c77b939 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Fri, 12 Jan 2024 15:39:40 +1000 Subject: [PATCH 01/18] feat: `avm/res/databricks/workspace` --- .../avm.res.databricks.workspace.yml | 83 + avm/res/databricks/workspace/ORPHANED.md | 4 + avm/res/databricks/workspace/README.md | 1473 ++++++++++++++++ avm/res/databricks/workspace/main.bicep | 505 ++++++ avm/res/databricks/workspace/main.json | 1514 +++++++++++++++++ .../tests/e2e/defaults/main.test.bicep | 46 + .../tests/e2e/max/dependencies.bicep | 368 ++++ .../workspace/tests/e2e/max/main.test.bicep | 164 ++ .../tests/e2e/waf-aligned/dependencies.bicep | 368 ++++ .../tests/e2e/waf-aligned/main.test.bicep | 147 ++ avm/res/databricks/workspace/version.json | 7 + 11 files changed, 4679 insertions(+) create mode 100644 .github/workflows/avm.res.databricks.workspace.yml create mode 100644 avm/res/databricks/workspace/ORPHANED.md create mode 100644 avm/res/databricks/workspace/README.md create mode 100644 avm/res/databricks/workspace/main.bicep create mode 100644 avm/res/databricks/workspace/main.json create mode 100644 avm/res/databricks/workspace/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/databricks/workspace/tests/e2e/max/main.test.bicep create mode 100644 avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/databricks/workspace/version.json diff --git a/.github/workflows/avm.res.databricks.workspace.yml b/.github/workflows/avm.res.databricks.workspace.yml new file mode 100644 index 0000000000..d9d477def4 --- /dev/null +++ b/.github/workflows/avm.res.databricks.workspace.yml @@ -0,0 +1,83 @@ +name: "avm.res.databricks.workspace" + +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.databricks.workspace.yml" + - "avm/res/databricks/workspace/**" + - "avm/utilities/pipelines/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/databricks/workspace" + workflowPath: ".github/workflows/avm.res.databricks.workspace.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: "Run" + 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/databricks/workspace/ORPHANED.md b/avm/res/databricks/workspace/ORPHANED.md new file mode 100644 index 0000000000..ef8fa911d2 --- /dev/null +++ b/avm/res/databricks/workspace/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/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md new file mode 100644 index 0000000000..a64a729c2c --- /dev/null +++ b/avm/res/databricks/workspace/README.md @@ -0,0 +1,1473 @@ +# Azure Databricks Workspaces `[Microsoft.Databricks/workspaces]` + +> ⚠️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 an Azure Databricks Workspace. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Notes](#Notes) +- [Data Collection](#Data-Collection) + +## 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.Databricks/workspaces` | [2023-02-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Databricks/2023-02-01/workspaces) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | + +## 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/databricks/workspace:`. + +- [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 workspace 'br/public:avm/res/databricks/workspace:' = { + name: '${uniqueString(deployment().name, location)}-test-dwmin' + params: { + // Required parameters + name: 'dwmin001' + // 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 + "name": { + "value": "dwmin001" + }, + // 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 workspace 'br/public:avm/res/databricks/workspace:' = { + name: '${uniqueString(deployment().name, location)}-test-dwmax' + params: { + // Required parameters + name: 'dwmax001' + // Non-required parameters + amlWorkspaceResourceId: '' + customerManagedKey: { + keyName: '' + keyVaultResourceId: '' + } + customerManagedKeyManagedDisk: { + keyName: '' + keyVaultResourceId: '' + rotationToLatestKeyVersionEnabled: true + } + customPrivateSubnetName: '' + customPublicSubnetName: '' + customVirtualNetworkResourceId: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disablePublicIp: true + loadBalancerBackendPoolName: '' + loadBalancerResourceId: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedResourceGroupResourceId: '' + natGatewayName: 'nat-gateway' + prepareEncryption: true + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + publicIpName: 'nat-gw-public-ip' + publicNetworkAccess: 'Disabled' + requiredNsgRules: 'NoAzureDatabricksRules' + requireInfrastructureEncryption: true + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuName: 'premium' + storageAccountName: 'sadwmax001' + storageAccountSkuName: 'Standard_ZRS' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetAddressPrefix: '10.100' + } +} +``` + +
+

+ +

+ +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 + "name": { + "value": "dwmax001" + }, + // Non-required parameters + "amlWorkspaceResourceId": { + "value": "" + }, + "customerManagedKey": { + "value": { + "keyName": "", + "keyVaultResourceId": "" + } + }, + "customerManagedKeyManagedDisk": { + "value": { + "keyName": "", + "keyVaultResourceId": "", + "rotationToLatestKeyVersionEnabled": true + } + }, + "customPrivateSubnetName": { + "value": "" + }, + "customPublicSubnetName": { + "value": "" + }, + "customVirtualNetworkResourceId": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "category": "jobs" + }, + { + "category": "notebook" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disablePublicIp": { + "value": true + }, + "loadBalancerBackendPoolName": { + "value": "" + }, + "loadBalancerResourceId": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedResourceGroupResourceId": { + "value": "" + }, + "natGatewayName": { + "value": "nat-gateway" + }, + "prepareEncryption": { + "value": true + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + } + ] + }, + "publicIpName": { + "value": "nat-gw-public-ip" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "requiredNsgRules": { + "value": "NoAzureDatabricksRules" + }, + "requireInfrastructureEncryption": { + "value": true + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuName": { + "value": "premium" + }, + "storageAccountName": { + "value": "sadwmax001" + }, + "storageAccountSkuName": { + "value": "Standard_ZRS" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "vnetAddressPrefix": { + "value": "10.100" + } + } +} +``` + +
+

+ +### 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 workspace 'br/public:avm/res/databricks/workspace:' = { + name: '${uniqueString(deployment().name, location)}-test-dwwaf' + params: { + // Required parameters + name: 'dwwaf001' + // Non-required parameters + amlWorkspaceResourceId: '' + customerManagedKey: { + keyName: '' + keyVaultResourceId: '' + } + customerManagedKeyManagedDisk: { + keyName: '' + keyVaultResourceId: '' + rotationToLatestKeyVersionEnabled: true + } + customPrivateSubnetName: '' + customPublicSubnetName: '' + customVirtualNetworkResourceId: '' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + } + ] + name: 'customSetting' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + disablePublicIp: true + loadBalancerBackendPoolName: '' + loadBalancerResourceId: '' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + managedResourceGroupResourceId: '' + natGatewayName: 'nat-gateway' + prepareEncryption: true + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + '' + ] + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + publicIpName: 'nat-gw-public-ip' + publicNetworkAccess: 'Disabled' + requiredNsgRules: 'NoAzureDatabricksRules' + requireInfrastructureEncryption: true + skuName: 'premium' + storageAccountName: 'sadwwaf001' + storageAccountSkuName: 'Standard_ZRS' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + vnetAddressPrefix: '10.100' + } +} +``` + +
+

+ +

+ +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 + "name": { + "value": "dwwaf001" + }, + // Non-required parameters + "amlWorkspaceResourceId": { + "value": "" + }, + "customerManagedKey": { + "value": { + "keyName": "", + "keyVaultResourceId": "" + } + }, + "customerManagedKeyManagedDisk": { + "value": { + "keyName": "", + "keyVaultResourceId": "", + "rotationToLatestKeyVersionEnabled": true + } + }, + "customPrivateSubnetName": { + "value": "" + }, + "customPublicSubnetName": { + "value": "" + }, + "customVirtualNetworkResourceId": { + "value": "" + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "category": "jobs" + }, + { + "category": "notebook" + } + ], + "name": "customSetting", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "disablePublicIp": { + "value": true + }, + "loadBalancerBackendPoolName": { + "value": "" + }, + "loadBalancerResourceId": { + "value": "" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "managedResourceGroupResourceId": { + "value": "" + }, + "natGatewayName": { + "value": "nat-gateway" + }, + "prepareEncryption": { + "value": true + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneResourceIds": [ + "" + ], + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "Role": "DeploymentValidation" + } + } + ] + }, + "publicIpName": { + "value": "nat-gw-public-ip" + }, + "publicNetworkAccess": { + "value": "Disabled" + }, + "requiredNsgRules": { + "value": "NoAzureDatabricksRules" + }, + "requireInfrastructureEncryption": { + "value": true + }, + "skuName": { + "value": "premium" + }, + "storageAccountName": { + "value": "sadwwaf001" + }, + "storageAccountSkuName": { + "value": "Standard_ZRS" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "vnetAddressPrefix": { + "value": "10.100" + } + } +} +``` + +
+

+ + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the Azure Databricks workspace to create. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`amlWorkspaceResourceId`](#parameter-amlworkspaceresourceid) | string | The resource ID of a Azure Machine Learning workspace to link with Databricks workspace. | +| [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition to use for the managed service. | +| [`customerManagedKeyManagedDisk`](#parameter-customermanagedkeymanageddisk) | object | The customer managed key definition to use for the managed disk. | +| [`customPrivateSubnetName`](#parameter-customprivatesubnetname) | string | The name of the Private Subnet within the Virtual Network. | +| [`customPublicSubnetName`](#parameter-custompublicsubnetname) | string | The name of a Public Subnet within the Virtual Network. | +| [`customVirtualNetworkResourceId`](#parameter-customvirtualnetworkresourceid) | string | The resource ID of a Virtual Network where this Databricks Cluster should be created. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`disablePublicIp`](#parameter-disablepublicip) | bool | Disable Public IP. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | +| [`loadBalancerBackendPoolName`](#parameter-loadbalancerbackendpoolname) | string | Name of the outbound Load Balancer Backend Pool for Secure Cluster Connectivity (No Public IP). | +| [`loadBalancerResourceId`](#parameter-loadbalancerresourceid) | string | Resource URI of Outbound Load balancer for Secure Cluster Connectivity (No Public IP) workspace. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`managedResourceGroupResourceId`](#parameter-managedresourcegroupresourceid) | string | The managed resource group ID. It is created by the module as per the to-be resource ID you provide. | +| [`natGatewayName`](#parameter-natgatewayname) | string | Name of the NAT gateway for Secure Cluster Connectivity (No Public IP) workspace subnets. | +| [`prepareEncryption`](#parameter-prepareencryption) | bool | Prepare the workspace for encryption. Enables the Managed Identity for managed storage account. | +| [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | +| [`publicIpName`](#parameter-publicipname) | string | Name of the Public IP for No Public IP workspace with managed vNet. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | The network access type for accessing workspace. Set value to disabled to access workspace only via private link. | +| [`requiredNsgRules`](#parameter-requirednsgrules) | string | Gets or sets a value indicating whether data plane (clusters) to control plane communication happen over private endpoint. | +| [`requireInfrastructureEncryption`](#parameter-requireinfrastructureencryption) | bool | A boolean indicating whether or not the DBFS root file system will be enabled with secondary layer of encryption with platform managed keys for data at rest. | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`skuName`](#parameter-skuname) | string | The pricing tier of workspace. | +| [`storageAccountName`](#parameter-storageaccountname) | string | Default DBFS storage account name. | +| [`storageAccountSkuName`](#parameter-storageaccountskuname) | string | Storage account SKU name. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`vnetAddressPrefix`](#parameter-vnetaddressprefix) | string | Address prefix for Managed virtual network. | + +### Parameter: `name` + +The name of the Azure Databricks workspace to create. + +- Required: Yes +- Type: string + +### Parameter: `amlWorkspaceResourceId` + +The resource ID of a Azure Machine Learning workspace to link with Databricks workspace. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `customerManagedKey` + +The customer managed key definition to use for the managed service. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyName`](#parameter-customermanagedkeykeyname) | string | The name of the customer managed key to use for encryption. | +| [`keyVaultResourceId`](#parameter-customermanagedkeykeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVersion`](#parameter-customermanagedkeykeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, using 'latest'. | +| [`userAssignedIdentityResourceId`](#parameter-customermanagedkeyuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. | + +### Parameter: `customerManagedKey.keyName` + +The name of the customer managed key to use for encryption. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVaultResourceId` + +The resource ID of a key vault to reference a customer managed key for encryption from. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVersion` + +The version of the customer managed key to reference for encryption. If not provided, using 'latest'. + +- Required: No +- Type: string + +### Parameter: `customerManagedKey.userAssignedIdentityResourceId` + +User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. + +- Required: No +- Type: string + +### Parameter: `customerManagedKeyManagedDisk` + +The customer managed key definition to use for the managed disk. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyName`](#parameter-customermanagedkeymanageddiskkeyname) | string | The name of the customer managed key to use for encryption. | +| [`keyVaultResourceId`](#parameter-customermanagedkeymanageddiskkeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVersion`](#parameter-customermanagedkeymanageddiskkeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, using 'latest'. | +| [`rotationToLatestKeyVersionEnabled`](#parameter-customermanagedkeymanageddiskrotationtolatestkeyversionenabled) | bool | Indicate whether the latest key version should be automatically used for Managed Disk Encryption. Enabled by default. | +| [`userAssignedIdentityResourceId`](#parameter-customermanagedkeymanageddiskuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. | + +### Parameter: `customerManagedKeyManagedDisk.keyName` + +The name of the customer managed key to use for encryption. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKeyManagedDisk.keyVaultResourceId` + +The resource ID of a key vault to reference a customer managed key for encryption from. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKeyManagedDisk.keyVersion` + +The version of the customer managed key to reference for encryption. If not provided, using 'latest'. + +- Required: No +- Type: string + +### Parameter: `customerManagedKeyManagedDisk.rotationToLatestKeyVersionEnabled` + +Indicate whether the latest key version should be automatically used for Managed Disk Encryption. Enabled by default. + +- Required: No +- Type: bool + +### Parameter: `customerManagedKeyManagedDisk.userAssignedIdentityResourceId` + +User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. + +- Required: No +- Type: string + +### Parameter: `customPrivateSubnetName` + +The name of the Private Subnet within the Virtual Network. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `customPublicSubnetName` + +The name of a Public Subnet within the Virtual Network. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `customVirtualNetworkResourceId` + +The resource ID of a Virtual Network where this Databricks Cluster should be created. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `diagnosticSettings` + +The diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-diagnosticsettingseventhubauthorizationruleresourceid) | string | Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. | +| [`eventHubName`](#parameter-diagnosticsettingseventhubname) | string | Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | +| [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of logs that will be streamed. "allMetrics" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | +| [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | + +### Parameter: `diagnosticSettings.eventHubAuthorizationRuleResourceId` + +Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.eventHubName` + +Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.logAnalyticsDestinationType` + +A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AzureDiagnostics' + 'Dedicated' + ] + ``` + +### Parameter: `diagnosticSettings.logCategoriesAndGroups` + +The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +### Parameter: `diagnosticSettings.marketplacePartnerResourceId` + +The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.metricCategories` + +The name of logs that will be streamed. "allMetrics" includes all possible logs for the resource. Set to '' to disable log collection. + +- Required: No +- Type: array + +### Parameter: `diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.storageAccountResourceId` + +Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `diagnosticSettings.workspaceResourceId` + +Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. + +- Required: No +- Type: string + +### Parameter: `disablePublicIp` + +Disable Public IP. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable telemetry via a Globally Unique Identifier (GUID). + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `loadBalancerBackendPoolName` + +Name of the outbound Load Balancer Backend Pool for Secure Cluster Connectivity (No Public IP). + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `loadBalancerResourceId` + +Resource URI of Outbound Load balancer for Secure Cluster Connectivity (No Public IP) workspace. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### 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: `managedResourceGroupResourceId` + +The managed resource group ID. It is created by the module as per the to-be resource ID you provide. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `natGatewayName` + +Name of the NAT gateway for Secure Cluster Connectivity (No Public IP) workspace subnets. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `prepareEncryption` + +Prepare the workspace for encryption. Enables the Managed Identity for managed storage account. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `privateEndpoints` + +Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`subnetResourceId`](#parameter-privateendpointssubnetresourceid) | string | Resource ID of the subnet where the endpoint needs to be created. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationSecurityGroupResourceIds`](#parameter-privateendpointsapplicationsecuritygroupresourceids) | array | Application security groups in which the private endpoint IP configuration is included. | +| [`customDnsConfigs`](#parameter-privateendpointscustomdnsconfigs) | array | Custom DNS configurations. | +| [`customNetworkInterfaceName`](#parameter-privateendpointscustomnetworkinterfacename) | string | The custom name of the network interface attached to the private endpoint. | +| [`enableTelemetry`](#parameter-privateendpointsenabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`ipConfigurations`](#parameter-privateendpointsipconfigurations) | array | A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. | +| [`location`](#parameter-privateendpointslocation) | string | The location to deploy the private endpoint to. | +| [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | +| [`manualPrivateLinkServiceConnections`](#parameter-privateendpointsmanualprivatelinkserviceconnections) | array | Manual PrivateLink Service Connections. | +| [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | +| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | +| [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | +| [`service`](#parameter-privateendpointsservice) | string | The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". | +| [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | + +### Parameter: `privateEndpoints.subnetResourceId` + +Resource ID of the subnet where the endpoint needs to be created. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.applicationSecurityGroupResourceIds` + +Application security groups in which the private endpoint IP configuration is included. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs` + +Custom DNS configurations. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.customNetworkInterfaceName` + +The custom name of the network interface attached to the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool + +### Parameter: `privateEndpoints.ipConfigurations` + +A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.location` + +The location to deploy the private endpoint to. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.lock` + +Specify the type of lock. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-privateendpointslockkind) | string | Specify the type of lock. | +| [`name`](#parameter-privateendpointslockname) | string | Specify the name of lock. | + +### Parameter: `privateEndpoints.lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `privateEndpoints.lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.manualPrivateLinkServiceConnections` + +Manual PrivateLink Service Connections. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.name` + +The name of the private endpoint. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroupName` + +The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneResourceIds` + +The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. + +- Required: No +- Type: array + +### Parameter: `privateEndpoints.roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-privateendpointsroleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-privateendpointsroleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-privateendpointsroleassignmentscondition) | 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-privateendpointsroleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-privateendpointsroleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-privateendpointsroleassignmentsdescription) | string | The description of the role assignment. | +| [`principalType`](#parameter-privateendpointsroleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `privateEndpoints.roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `privateEndpoints.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: `privateEndpoints.roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `privateEndpoints.roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `privateEndpoints.service` + +The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob". + +- Required: No +- Type: string + +### Parameter: `privateEndpoints.tags` + +Tags to be applied on all resources/resource groups in this deployment. + +- Required: No +- Type: object + +### Parameter: `publicIpName` + +Name of the Public IP for No Public IP workspace with managed vNet. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `publicNetworkAccess` + + The network access type for accessing workspace. Set value to disabled to access workspace only via private link. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `requiredNsgRules` + +Gets or sets a value indicating whether data plane (clusters) to control plane communication happen over private endpoint. + +- Required: No +- Type: string +- Default: `'AllRules'` +- Allowed: + ```Bicep + [ + 'AllRules' + 'NoAzureDatabricksRules' + ] + ``` + +### Parameter: `requireInfrastructureEncryption` + +A boolean indicating whether or not the DBFS root file system will be enabled with secondary layer of encryption with platform managed keys for data at rest. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- 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 role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**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 role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- 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: `skuName` + +The pricing tier of workspace. + +- Required: No +- Type: string +- Default: `'premium'` +- Allowed: + ```Bicep + [ + 'premium' + 'standard' + 'trial' + ] + ``` + +### Parameter: `storageAccountName` + +Default DBFS storage account name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `storageAccountSkuName` + +Storage account SKU name. + +- Required: No +- Type: string +- Default: `'Standard_GRS'` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `vnetAddressPrefix` + +Address prefix for Managed virtual network. + +- Required: No +- Type: string +- Default: `'10.139'` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed databricks workspace. | +| `resourceGroupName` | string | The resource group of the deployed databricks workspace. | +| `resourceId` | string | The resource ID of the deployed databricks workspace. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other CARML modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/network/private-endpoint:0.3.1` | Remote reference | + +## Notes + +### Parameter Usage: `customPublicSubnetName` and `customPrivateSubnetName` + +- Require Network Security Groups attached to the subnets (Note: Rule don't have to be set, they are set through the deployment) + +- The two subnets also need the delegation to service `Microsoft.Databricks/workspaces` + +### Parameter Usage: `parameters` + +- Include only those elements (e.g. amlWorkspaceId) as object if specified, otherwise remove it. + +

+ +Parameter JSON format + +```json +"parameters": { + "value": { + "amlWorkspaceId": { + "value": "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.MachineLearningServices/workspaces/xxx" + }, + "customVirtualNetworkId": { + "value": "/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Network/virtualNetworks/xxx" + }, + "customPublicSubnetName": { + "value": "xxx" + }, + "customPrivateSubnetName": { + "value": "xxx" + }, + "enableNoPublicIp": { + "value": true + } + } +} +``` + +
+ +
+ +Bicep format + +```bicep +parameters: { + amlWorkspaceId: { + value: '/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.MachineLearningServices/workspaces/xxx' + } + customVirtualNetworkId: { + value: '/subscriptions/xxx/resourceGroups/xxx/providers/Microsoft.Network/virtualNetworks/xxx' + } + customPublicSubnetName: { + value: 'xxx' + } + customPrivateSubnetName: { + value: 'xxx' + } + enableNoPublicIp: { + value: true + } +} +``` + +
+

+ +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/databricks/workspace/main.bicep b/avm/res/databricks/workspace/main.bicep new file mode 100644 index 0000000000..433b5a950f --- /dev/null +++ b/avm/res/databricks/workspace/main.bicep @@ -0,0 +1,505 @@ +metadata name = 'Azure Databricks Workspaces' +metadata description = 'This module deploys an Azure Databricks Workspace.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the Azure Databricks workspace to create.') +param name string + +@description('Optional. The managed resource group ID. It is created by the module as per the to-be resource ID you provide.') +param managedResourceGroupResourceId string = '' + +@description('Optional. The pricing tier of workspace.') +@allowed([ + 'trial' + 'standard' + 'premium' +]) +param skuName string = 'premium' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. The diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingType + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +param enableTelemetry bool = true + +@description('Optional. The resource ID of a Virtual Network where this Databricks Cluster should be created.') +param customVirtualNetworkResourceId string = '' + +@description('Optional. The resource ID of a Azure Machine Learning workspace to link with Databricks workspace.') +param amlWorkspaceResourceId string = '' + +@description('Optional. The name of the Private Subnet within the Virtual Network.') +param customPrivateSubnetName string = '' + +@description('Optional. The name of a Public Subnet within the Virtual Network.') +param customPublicSubnetName string = '' + +@description('Optional. Disable Public IP.') +param disablePublicIp bool = false + +@description('Optional. The customer managed key definition to use for the managed service.') +param customerManagedKey customerManagedKeyType + +@description('Optional. The customer managed key definition to use for the managed disk.') +param customerManagedKeyManagedDisk customerManagedKeyManagedDiskType + +@description('Optional. Name of the outbound Load Balancer Backend Pool for Secure Cluster Connectivity (No Public IP).') +param loadBalancerBackendPoolName string = '' + +@description('Optional. Resource URI of Outbound Load balancer for Secure Cluster Connectivity (No Public IP) workspace.') +param loadBalancerResourceId string = '' + +@description('Optional. Name of the NAT gateway for Secure Cluster Connectivity (No Public IP) workspace subnets.') +param natGatewayName string = '' + +@description('Optional. Prepare the workspace for encryption. Enables the Managed Identity for managed storage account.') +param prepareEncryption bool = false + +@description('Optional. Name of the Public IP for No Public IP workspace with managed vNet.') +param publicIpName string = '' + +@description('Optional. A boolean indicating whether or not the DBFS root file system will be enabled with secondary layer of encryption with platform managed keys for data at rest.') +param requireInfrastructureEncryption bool = false + +@description('Optional. Default DBFS storage account name.') +param storageAccountName string = '' + +@description('Optional. Storage account SKU name.') +param storageAccountSkuName string = 'Standard_GRS' + +@description('Optional. Address prefix for Managed virtual network.') +param vnetAddressPrefix string = '10.139' + +@description('Optional. The network access type for accessing workspace. Set value to disabled to access workspace only via private link.') +@allowed([ + 'Disabled' + 'Enabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Gets or sets a value indicating whether data plane (clusters) to control plane communication happen over private endpoint.') +@allowed([ + 'AllRules' + 'NoAzureDatabricksRules' +]) +param requiredNsgRules string = 'AllRules' + +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointType + +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.databricks-workspace.${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 cMKKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split((customerManagedKey.?keyVaultResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup(split((customerManagedKey.?keyVaultResourceId ?? '//'), '/')[2], split((customerManagedKey.?keyVaultResourceId ?? '////'), '/')[4]) + + resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName ?? 'dummyKey' + } +} + +resource cMKManagedDiskKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (!empty(customerManagedKeyManagedDisk.?keyVaultResourceId)) { + name: last(split((customerManagedKeyManagedDisk.?keyVaultResourceId ?? 'dummyVault'), '/')) + scope: resourceGroup(split((customerManagedKeyManagedDisk.?keyVaultResourceId ?? '//'), '/')[2], split((customerManagedKeyManagedDisk.?keyVaultResourceId ?? '////'), '/')[4]) + + resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKeyManagedDisk.?keyVaultResourceId) && !empty(customerManagedKeyManagedDisk.?keyName)) { + name: customerManagedKeyManagedDisk.?keyName ?? 'dummyKey' + } +} + +resource workspace 'Microsoft.Databricks/workspaces@2023-02-01' = { + name: name + location: location + tags: tags + sku: { + name: skuName + } + properties: { + managedResourceGroupId: !empty(managedResourceGroupResourceId) ? managedResourceGroupResourceId : '${subscription().id}/resourceGroups/${name}-rg' + parameters: union( + // Always added parameters + { + enableNoPublicIp: { + value: disablePublicIp + } + prepareEncryption: { + value: prepareEncryption + } + vnetAddressPrefix: { + value: vnetAddressPrefix + } + requireInfrastructureEncryption: { + value: requireInfrastructureEncryption + } + }, + // Parameters only added if not empty + !empty(customVirtualNetworkResourceId) ? { + customVirtualNetworkId: { + value: customVirtualNetworkResourceId + } + } : {}, + !empty(amlWorkspaceResourceId) ? { + amlWorkspaceId: { + value: amlWorkspaceResourceId + } + } : {}, + !empty(customPrivateSubnetName) ? { + customPrivateSubnetName: { + value: customPrivateSubnetName + } + } : {}, + !empty(customPublicSubnetName) ? { + customPublicSubnetName: { + value: customPublicSubnetName + } + } : {}, + !empty(loadBalancerBackendPoolName) ? { + loadBalancerBackendPoolName: { + value: loadBalancerBackendPoolName + } + } : {}, + !empty(loadBalancerResourceId) ? { + loadBalancerId: { + value: loadBalancerResourceId + } + } : {}, + !empty(natGatewayName) ? { + natGatewayName: { + value: natGatewayName + } + } : {}, + !empty(publicIpName) ? { + publicIpName: { + value: publicIpName + } + } : {}, + !empty(storageAccountName) ? { + storageAccountName: { + value: storageAccountName + } + } : {}, + !empty(storageAccountSkuName) ? { + storageAccountSkuName: { + value: storageAccountSkuName + } + } : {}) + publicNetworkAccess: publicNetworkAccess + requiredNsgRules: requiredNsgRules + encryption: !empty(customerManagedKey) || !empty(customerManagedKeyManagedDisk) ? { + entities: { + managedServices: !empty(customerManagedKey) ? { + keySource: 'Microsoft.Keyvault' + keyVaultProperties: { + keyVaultUri: cMKKeyVault.properties.vaultUri + keyName: customerManagedKey!.keyName + keyVersion: !empty(customerManagedKey.?keyVersion ?? '') ? customerManagedKey!.keyVersion : last(split(cMKKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + } + } : null + managedDisk: !empty(customerManagedKeyManagedDisk) ? { + keySource: 'Microsoft.Keyvault' + keyVaultProperties: { + keyVaultUri: cMKManagedDiskKeyVault.properties.vaultUri + keyName: customerManagedKeyManagedDisk!.keyName + keyVersion: !empty(customerManagedKeyManagedDisk.?keyVersion ?? '') ? customerManagedKeyManagedDisk!.keyVersion : last(split(cMKManagedDiskKeyVault::cMKKey.properties.keyUriWithVersion, '/')) + } + rotationToLatestKeyVersionEnabled: customerManagedKeyManagedDisk.?rotationToLatestKeyVersionEnabled ?? true + } : null + } + } : null + } +} + +resource workspace_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: workspace +} + +// Note: Diagnostic Settings are only supported by the premium tier +resource workspace_diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = [for (diagnosticSetting, index) in (diagnosticSettings ?? []): { + name: diagnosticSetting.?name ?? '${name}-diagnosticSettings' + properties: { + storageAccountId: diagnosticSetting.?storageAccountResourceId + workspaceId: diagnosticSetting.?workspaceResourceId + eventHubAuthorizationRuleId: diagnosticSetting.?eventHubAuthorizationRuleResourceId + eventHubName: diagnosticSetting.?eventHubName + logs: diagnosticSetting.?logCategoriesAndGroups ?? [ + { + categoryGroup: 'AllLogs' + enabled: true + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: workspace +}] + +resource workspace_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(workspace.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: workspace +}] + +module workspace_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.3.1' = [for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-KeyVault-PrivateEndpoint-${index}' + params: { + privateLinkServiceConnections: [ + { + name: name + properties: { + privateLinkServiceId: workspace.id + groupIds: [ + privateEndpoint.?service ?? 'databricks_ui_api' + ] + } + } + ] + name: privateEndpoint.?name ?? 'pep-${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'databricks_ui_api'}-${index}' + subnetResourceId: privateEndpoint.subnetResourceId + enableTelemetry: enableTelemetry + location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location + lock: privateEndpoint.?lock ?? lock + privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName + privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds + roleAssignments: privateEndpoint.?roleAssignments + tags: privateEndpoint.?tags ?? tags + manualPrivateLinkServiceConnections: privateEndpoint.?manualPrivateLinkServiceConnections + customDnsConfigs: privateEndpoint.?customDnsConfigs + ipConfigurations: privateEndpoint.?ipConfigurations + applicationSecurityGroupResourceIds: privateEndpoint.?applicationSecurityGroupResourceIds + customNetworkInterfaceName: privateEndpoint.?customNetworkInterfaceName + } +}] + +@description('The name of the deployed databricks workspace.') +output name string = workspace.name + +@description('The resource ID of the deployed databricks workspace.') +output resourceId string = workspace.id + +@description('The resource group of the deployed databricks workspace.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = workspace.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type privateEndpointType = { + + @description('Optional. The name of the private endpoint.') + name: string? + + @description('Optional. The location to deploy the private endpoint to.') + location: string? + + @description('Optional. The service (sub-) type to deploy the private endpoint for. For example "vault" or "blob".') + service: string? + + @description('Required. Resource ID of the subnet where the endpoint needs to be created.') + subnetResourceId: string + + @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') + privateDnsZoneGroupName: string? + + @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneResourceIds: string[]? + + @description('Optional. Custom DNS configurations.') + customDnsConfigs: { + @description('Required. Fqdn that resolves to private endpoint IP address.') + fqdn: string? + + @description('Required. A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[]? + + @description('Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints.') + ipConfigurations: { + @description('Required. The name of the resource that is unique within a resource group.') + name: string + + @description('Required. Properties of private endpoint IP configurations.') + properties: { + @description('Required. The ID of a group obtained from the remote resource that this private endpoint should connect to.') + groupId: string + + @description('Required. The member name of a group obtained from the remote resource that this private endpoint should connect to.') + memberName: string + + @description('Required. A private IP address obtained from the private endpoint\'s subnet.') + privateIPAddress: string + } + }[]? + + @description('Optional. Application security groups in which the private endpoint IP configuration is included.') + applicationSecurityGroupResourceIds: string[]? + + @description('Optional. The custom name of the network interface attached to the private endpoint.') + customNetworkInterfaceName: string? + + @description('Optional. Specify the type of lock.') + lock: lockType + + @description('Optional. Array of role assignments to create.') + roleAssignments: roleAssignmentType + + @description('Optional. Tags to be applied on all resources/resource groups in this deployment.') + tags: object? + + @description('Optional. Manual PrivateLink Service Connections.') + manualPrivateLinkServiceConnections: array? + + @description('Optional. Enable/Disable usage telemetry for module.') + enableTelemetry: bool? +}[]? + +type customerManagedKeyType = { + @description('Required. The resource ID of a key vault to reference a customer managed key for encryption from.') + keyVaultResourceId: string + + @description('Required. The name of the customer managed key to use for encryption.') + keyName: string + + @description('Optional. The version of the customer managed key to reference for encryption. If not provided, using \'latest\'.') + keyVersion: string? + + @description('Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use.') + userAssignedIdentityResourceId: string? +}? + +type customerManagedKeyManagedDiskType = { + @description('Required. The resource ID of a key vault to reference a customer managed key for encryption from.') + keyVaultResourceId: string + + @description('Required. The name of the customer managed key to use for encryption.') + keyName: string + + @description('Optional. The version of the customer managed key to reference for encryption. If not provided, using \'latest\'.') + keyVersion: string? + + @description('Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use.') + userAssignedIdentityResourceId: string? + + @description('Optional. Indicate whether the latest key version should be automatically used for Managed Disk Encryption. Enabled by default.') + rotationToLatestKeyVersionEnabled: bool? +}? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @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? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? + +type diagnosticSettingType = { + @description('Optional. The name of diagnostic setting.') + name: string? + + @description('Optional. The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to \'\' to disable log collection.') + logCategoriesAndGroups: { + @description('Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here.') + category: string? + + @description('Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs.') + categoryGroup: string? + }[]? + + @description('Optional. The name of logs that will be streamed. "allMetrics" includes all possible logs for the resource. Set to \'\' to disable log collection.') + metricCategories: { + @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') + category: string + }[]? + + @description('Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type.') + logAnalyticsDestinationType: ('Dedicated' | 'AzureDiagnostics')? + + @description('Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + workspaceResourceId: string? + + @description('Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + storageAccountResourceId: string? + + @description('Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to.') + eventHubAuthorizationRuleResourceId: string? + + @description('Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub.') + eventHubName: string? + + @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') + marketplacePartnerResourceId: string? +}[]? diff --git a/avm/res/databricks/workspace/main.json b/avm/res/databricks/workspace/main.json new file mode 100644 index 0000000000..932eb4c80a --- /dev/null +++ b/avm/res/databricks/workspace/main.json @@ -0,0 +1,1514 @@ +{ + "$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.24.24.22086", + "templateHash": "8058701732527405193" + }, + "name": "Azure Databricks Workspaces", + "description": "This module deploys an Azure Databricks Workspace.", + "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 + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The service (sub-) type to deploy the private endpoint for. For example \"vault\" or \"blob\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Manual PrivateLink Service Connections." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "customerManagedKeyManagedDiskType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + }, + "rotationToLatestKeyVersionEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicate whether the latest key version should be automatically used for Managed Disk Encryption. Enabled by default." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "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 + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allMetrics\" includes all possible logs for the resource. Set to '' to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Azure Databricks workspace to create." + } + }, + "managedResourceGroupResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The managed resource group ID. It is created by the module as per the to-be resource ID you provide." + } + }, + "skuName": { + "type": "string", + "defaultValue": "premium", + "allowedValues": [ + "trial", + "standard", + "premium" + ], + "metadata": { + "description": "Optional. The pricing tier of workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." + } + }, + "customVirtualNetworkResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of a Virtual Network where this Databricks Cluster should be created." + } + }, + "amlWorkspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of a Azure Machine Learning workspace to link with Databricks workspace." + } + }, + "customPrivateSubnetName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the Private Subnet within the Virtual Network." + } + }, + "customPublicSubnetName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of a Public Subnet within the Virtual Network." + } + }, + "disablePublicIp": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Public IP." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition to use for the managed service." + } + }, + "customerManagedKeyManagedDisk": { + "$ref": "#/definitions/customerManagedKeyManagedDiskType", + "metadata": { + "description": "Optional. The customer managed key definition to use for the managed disk." + } + }, + "loadBalancerBackendPoolName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the outbound Load Balancer Backend Pool for Secure Cluster Connectivity (No Public IP)." + } + }, + "loadBalancerResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource URI of Outbound Load balancer for Secure Cluster Connectivity (No Public IP) workspace." + } + }, + "natGatewayName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the NAT gateway for Secure Cluster Connectivity (No Public IP) workspace subnets." + } + }, + "prepareEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Prepare the workspace for encryption. Enables the Managed Identity for managed storage account." + } + }, + "publicIpName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the Public IP for No Public IP workspace with managed vNet." + } + }, + "requireInfrastructureEncryption": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. A boolean indicating whether or not the DBFS root file system will be enabled with secondary layer of encryption with platform managed keys for data at rest." + } + }, + "storageAccountName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Default DBFS storage account name." + } + }, + "storageAccountSkuName": { + "type": "string", + "defaultValue": "Standard_GRS", + "metadata": { + "description": "Optional. Storage account SKU name." + } + }, + "vnetAddressPrefix": { + "type": "string", + "defaultValue": "10.139", + "metadata": { + "description": "Optional. Address prefix for Managed virtual network." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. \tThe network access type for accessing workspace. Set value to disabled to access workspace only via private link." + } + }, + "requiredNsgRules": { + "type": "string", + "defaultValue": "AllRules", + "allowedValues": [ + "AllRules", + "NoAzureDatabricksRules" + ], + "metadata": { + "description": "Optional. Gets or sets a value indicating whether data plane (clusters) to control plane communication happen over private endpoint." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + } + }, + "variables": { + "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": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "cMKManagedDiskKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKManagedDiskKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.databricks-workspace.{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" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKManagedDiskKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "workspace": { + "type": "Microsoft.Databricks/workspaces", + "apiVersion": "2023-02-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('skuName')]" + }, + "properties": { + "managedResourceGroupId": "[if(not(empty(parameters('managedResourceGroupResourceId'))), parameters('managedResourceGroupResourceId'), format('{0}/resourceGroups/{1}-rg', subscription().id, parameters('name')))]", + "parameters": "[union(createObject('enableNoPublicIp', createObject('value', parameters('disablePublicIp')), 'prepareEncryption', createObject('value', parameters('prepareEncryption')), 'vnetAddressPrefix', createObject('value', parameters('vnetAddressPrefix')), 'requireInfrastructureEncryption', createObject('value', parameters('requireInfrastructureEncryption'))), if(not(empty(parameters('customVirtualNetworkResourceId'))), createObject('customVirtualNetworkId', createObject('value', parameters('customVirtualNetworkResourceId'))), createObject()), if(not(empty(parameters('amlWorkspaceResourceId'))), createObject('amlWorkspaceId', createObject('value', parameters('amlWorkspaceResourceId'))), createObject()), if(not(empty(parameters('customPrivateSubnetName'))), createObject('customPrivateSubnetName', createObject('value', parameters('customPrivateSubnetName'))), createObject()), if(not(empty(parameters('customPublicSubnetName'))), createObject('customPublicSubnetName', createObject('value', parameters('customPublicSubnetName'))), createObject()), if(not(empty(parameters('loadBalancerBackendPoolName'))), createObject('loadBalancerBackendPoolName', createObject('value', parameters('loadBalancerBackendPoolName'))), createObject()), if(not(empty(parameters('loadBalancerResourceId'))), createObject('loadBalancerId', createObject('value', parameters('loadBalancerResourceId'))), createObject()), if(not(empty(parameters('natGatewayName'))), createObject('natGatewayName', createObject('value', parameters('natGatewayName'))), createObject()), if(not(empty(parameters('publicIpName'))), createObject('publicIpName', createObject('value', parameters('publicIpName'))), createObject()), if(not(empty(parameters('storageAccountName'))), createObject('storageAccountName', createObject('value', parameters('storageAccountName'))), createObject()), if(not(empty(parameters('storageAccountSkuName'))), createObject('storageAccountSkuName', createObject('value', parameters('storageAccountSkuName'))), createObject()))]", + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "requiredNsgRules": "[parameters('requiredNsgRules')]", + "encryption": "[if(or(not(empty(parameters('customerManagedKey'))), not(empty(parameters('customerManagedKeyManagedDisk')))), createObject('entities', createObject('managedServices', if(not(empty(parameters('customerManagedKey'))), createObject('keySource', 'Microsoft.Keyvault', 'keyVaultProperties', createObject('keyVaultUri', reference('cMKKeyVault').vaultUri, 'keyName', parameters('customerManagedKey').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), parameters('customerManagedKey').keyVersion, last(split(reference('cMKKeyVault::cMKKey').keyUriWithVersion, '/'))))), null()), 'managedDisk', if(not(empty(parameters('customerManagedKeyManagedDisk'))), createObject('keySource', 'Microsoft.Keyvault', 'keyVaultProperties', createObject('keyVaultUri', reference('cMKManagedDiskKeyVault').vaultUri, 'keyName', parameters('customerManagedKeyManagedDisk').keyName, 'keyVersion', if(not(empty(coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'keyVersion'), ''))), parameters('customerManagedKeyManagedDisk').keyVersion, last(split(reference('cMKManagedDiskKeyVault::cMKKey').keyUriWithVersion, '/')))), 'rotationToLatestKeyVersionEnabled', coalesce(tryGet(parameters('customerManagedKeyManagedDisk'), 'rotationToLatestKeyVersionEnabled'), true())), null()))), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKManagedDiskKeyVault" + ] + }, + "workspace_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.Databricks/workspaces/{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": [ + "workspace" + ] + }, + "workspace_diagnosticSettings": { + "copy": { + "name": "workspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Databricks/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "logs": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'AllLogs', 'enabled', true())))]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_roleAssignments": { + "copy": { + "name": "workspace_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Databricks/workspaces/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Databricks/workspaces', 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": [ + "workspace" + ] + }, + "workspace_privateEndpoints": { + "copy": { + "name": "workspace_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "privateLinkServiceConnections": { + "value": [ + { + "name": "[parameters('name')]", + "properties": { + "privateLinkServiceId": "[resourceId('Microsoft.Databricks/workspaces', parameters('name'))]", + "groupIds": [ + "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'databricks_ui_api')]" + ] + } + } + ] + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.Databricks/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'databricks_ui_api'), copyIndex()))]" + }, + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "manualPrivateLinkServiceConnections": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualPrivateLinkServiceConnections')]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$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": "2821141217598568122" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "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 + }, + "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 + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private ip address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint ip address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private ip addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "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')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.3.1', '.', '-'), 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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_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.Network/privateEndpoints/{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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', 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": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "18168683629401652671" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed databricks workspace." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed databricks workspace." + }, + "value": "[resourceId('Microsoft.Databricks/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed databricks workspace." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('workspace', '2023-02-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/databricks/workspace/tests/e2e/defaults/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..23f5959852 --- /dev/null +++ b/avm/res/databricks/workspace/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,46 @@ +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}-databricks.workspaces-${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 = 'dwmin' + +@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 +} + +// ============== // +// 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 + } +}] diff --git a/avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep b/avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..a45e4247ea --- /dev/null +++ b/avm/res/databricks/workspace/tests/e2e/max/dependencies.bicep @@ -0,0 +1,368 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Key Vault for Disk Encryption to create.') +param keyVaultDiskName string + +@description('Required. The name of the Azure Machine Learning Workspace to create.') +param amlWorkspaceName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Application Insights Instanec to create.') +param applicationInsightsName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required by batch account + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyVaultDisk 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultDiskName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required by batch account + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKeyDisk' + properties: { + kty: 'RSA' + } + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Key-Vault-Crypto-User-RoleAssignment') + scope: keyVault::key + properties: { + principalId: '09ef9f59-e7b6-422e-84e4-508cfc8d64e7' // AzureDatabricks Enterprise Application Object Id + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424') // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource amlPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-Key-Vault-Contributor') + scope: keyVault + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') // Contributor + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_ZRS' + } + kind: 'StorageV2' + properties: {} +} + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { + name: applicationInsightsName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + } +} + +resource machineLearningWorkspace 'Microsoft.MachineLearningServices/workspaces@2023-04-01' = { + name: amlWorkspaceName + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + storageAccount: storageAccount.id + keyVault: keyVault.id + applicationInsights: applicationInsights.id + primaryUserAssignedIdentity: managedIdentity.id + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + properties: { + backendAddressPools: [ + { + name: 'default' + } + ] + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-inbound' + properties: { + description: 'Required for worker nodes communication within a cluster.' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + access: 'Allow' + priority: 100 + direction: 'Inbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-databricks-webapp' + properties: { + description: 'Required for workers communication with Databricks Webapp.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'AzureDatabricks' + access: 'Allow' + priority: 100 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-sql' + properties: { + description: 'Required for workers communication with Azure SQL services.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '3306' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Sql' + access: 'Allow' + priority: 101 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-storage' + properties: { + description: 'Required for workers communication with Azure Storage services.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Storage' + access: 'Allow' + priority: 102 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-outbound' + properties: { + description: 'Required for worker nodes communication within a cluster.' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + access: 'Allow' + priority: 103 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-eventhub' + properties: { + description: 'Required for worker communication with Azure Eventhub services.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '9093' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'EventHub' + access: 'Allow' + priority: 104 + direction: 'Outbound' + } + } + ] + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + } + } + { + name: 'custom-public-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + networkSecurityGroup: { + id: networkSecurityGroup.id + } + delegations: [ + { + name: 'databricksDelegation' + properties: { + serviceName: 'Microsoft.Databricks/workspaces' + } + } + ] + } + } + { + name: 'custom-private-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 2) + networkSecurityGroup: { + id: networkSecurityGroup.id + } + delegations: [ + { + name: 'databricksDelegation' + properties: { + serviceName: 'Microsoft.Databricks/workspaces' + } + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.azuredatabricks.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Default Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The name of the created Virtual Network Public Subnet.') +output customPublicSubnetName string = virtualNetwork.properties.subnets[1].name + +@description('The name of the created Virtual Network Private Subnet.') +output customPrivateSubnetName string = virtualNetwork.properties.subnets[2].name + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Azure Machine Learning Workspace.') +output machineLearningWorkspaceResourceId string = machineLearningWorkspace.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The resource ID of the created Disk Key Vault.') +output keyVaultDiskResourceId string = keyVaultDisk.id + +@description('The resource ID of the created Load Balancer.') +output loadBalancerResourceId string = loadBalancer.id + +@description('The name of the created Load Balancer Backend Pool.') +output loadBalancerBackendPoolName string = loadBalancer.properties.backendAddressPools[0].name + +@description('The name of the created Key Vault encryption key.') +output keyVaultKeyName string = keyVault::key.name + +@description('The name of the created Key Vault Disk encryption key.') +output keyVaultDiskKeyName string = keyVaultDisk::key.name + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..471d2b9f00 --- /dev/null +++ b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep @@ -0,0 +1,164 @@ +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}-databricks.workspaces-${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 = 'dwmax' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@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: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + amlWorkspaceName: 'dep-${namePrefix}-aml-${serviceShort}' + applicationInsightsName: 'dep-${namePrefix}-appi-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + networkSecurityGroupName: 'dep-${namePrefix}-nsg-${serviceShort}' + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + keyVaultDiskName: 'dep-${namePrefix}-kve-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${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 + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + + } + ] + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + 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' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + customerManagedKey: { + keyName: nestedDependencies.outputs.keyVaultKeyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + } + customerManagedKeyManagedDisk: { + keyName: nestedDependencies.outputs.keyVaultDiskKeyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId + rotationToLatestKeyVersionEnabled: true + } + storageAccountName: 'sa${namePrefix}${serviceShort}001' + storageAccountSkuName: 'Standard_ZRS' + publicIpName: 'nat-gw-public-ip' + natGatewayName: 'nat-gateway' + prepareEncryption: true + requiredNsgRules: 'NoAzureDatabricksRules' + skuName: 'premium' + amlWorkspaceResourceId: nestedDependencies.outputs.machineLearningWorkspaceResourceId + customPrivateSubnetName: nestedDependencies.outputs.customPrivateSubnetName + customPublicSubnetName: nestedDependencies.outputs.customPublicSubnetName + publicNetworkAccess: 'Disabled' + disablePublicIp: true + loadBalancerResourceId: nestedDependencies.outputs.loadBalancerResourceId + loadBalancerBackendPoolName: nestedDependencies.outputs.loadBalancerBackendPoolName + customVirtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.defaultSubnetResourceId + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + managedResourceGroupResourceId: '${subscription().id}/resourceGroups/rg-${resourceGroupName}-managed' + requireInfrastructureEncryption: true + vnetAddressPrefix: '10.100' + } +}] diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..a45e4247ea --- /dev/null +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,368 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +@description('Required. The name of the Key Vault for Disk Encryption to create.') +param keyVaultDiskName string + +@description('Required. The name of the Azure Machine Learning Workspace to create.') +param amlWorkspaceName string + +@description('Required. The name of the Load Balancer to create.') +param loadBalancerName string + +@description('Required. The name of the Network Security Group to create.') +param networkSecurityGroupName string + +@description('Required. The name of the Storage Account to create.') +param storageAccountName string + +@description('Required. The name of the Application Insights Instanec to create.') +param applicationInsightsName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required by batch account + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyVaultDisk 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultDiskName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required by batch account + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKeyDisk' + properties: { + kty: 'RSA' + } + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Key-Vault-Crypto-User-RoleAssignment') + scope: keyVault::key + properties: { + principalId: '09ef9f59-e7b6-422e-84e4-508cfc8d64e7' // AzureDatabricks Enterprise Application Object Id + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424') // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} + +resource amlPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault.id}-${location}-${managedIdentity.id}-Key-Vault-Contributor') + scope: keyVault + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') // Contributor + principalType: 'ServicePrincipal' + } +} + +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_ZRS' + } + kind: 'StorageV2' + properties: {} +} + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { + name: applicationInsightsName + location: location + kind: 'web' + properties: { + Application_Type: 'web' + } +} + +resource machineLearningWorkspace 'Microsoft.MachineLearningServices/workspaces@2023-04-01' = { + name: amlWorkspaceName + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${managedIdentity.id}': {} + } + } + properties: { + storageAccount: storageAccount.id + keyVault: keyVault.id + applicationInsights: applicationInsights.id + primaryUserAssignedIdentity: managedIdentity.id + } +} + +resource loadBalancer 'Microsoft.Network/loadBalancers@2023-04-01' = { + name: loadBalancerName + location: location + properties: { + backendAddressPools: [ + { + name: 'default' + } + ] + frontendIPConfigurations: [ + { + name: 'privateIPConfig1' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +resource networkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: networkSecurityGroupName + location: location + properties: { + securityRules: [ + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-inbound' + properties: { + description: 'Required for worker nodes communication within a cluster.' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + access: 'Allow' + priority: 100 + direction: 'Inbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-databricks-webapp' + properties: { + description: 'Required for workers communication with Databricks Webapp.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'AzureDatabricks' + access: 'Allow' + priority: 100 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-sql' + properties: { + description: 'Required for workers communication with Azure SQL services.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '3306' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Sql' + access: 'Allow' + priority: 101 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-storage' + properties: { + description: 'Required for workers communication with Azure Storage services.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '443' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'Storage' + access: 'Allow' + priority: 102 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-worker-outbound' + properties: { + description: 'Required for worker nodes communication within a cluster.' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'VirtualNetwork' + access: 'Allow' + priority: 103 + direction: 'Outbound' + } + } + { + name: 'Microsoft.Databricks-workspaces_UseOnly_databricks-worker-to-eventhub' + properties: { + description: 'Required for worker communication with Azure Eventhub services.' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '9093' + sourceAddressPrefix: 'VirtualNetwork' + destinationAddressPrefix: 'EventHub' + access: 'Allow' + priority: 104 + direction: 'Outbound' + } + } + ] + } +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2022-01-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 0) + } + } + { + name: 'custom-public-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 1) + networkSecurityGroup: { + id: networkSecurityGroup.id + } + delegations: [ + { + name: 'databricksDelegation' + properties: { + serviceName: 'Microsoft.Databricks/workspaces' + } + } + ] + } + } + { + name: 'custom-private-subnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 20, 2) + networkSecurityGroup: { + id: networkSecurityGroup.id + } + delegations: [ + { + name: 'databricksDelegation' + properties: { + serviceName: 'Microsoft.Databricks/workspaces' + } + } + ] + } + } + ] + } +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.azuredatabricks.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Default Subnet.') +output defaultSubnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The name of the created Virtual Network Public Subnet.') +output customPublicSubnetName string = virtualNetwork.properties.subnets[1].name + +@description('The name of the created Virtual Network Private Subnet.') +output customPrivateSubnetName string = virtualNetwork.properties.subnets[2].name + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id + +@description('The resource ID of the created Azure Machine Learning Workspace.') +output machineLearningWorkspaceResourceId string = machineLearningWorkspace.id + +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The resource ID of the created Disk Key Vault.') +output keyVaultDiskResourceId string = keyVaultDisk.id + +@description('The resource ID of the created Load Balancer.') +output loadBalancerResourceId string = loadBalancer.id + +@description('The name of the created Load Balancer Backend Pool.') +output loadBalancerBackendPoolName string = loadBalancer.properties.backendAddressPools[0].name + +@description('The name of the created Key Vault encryption key.') +output keyVaultKeyName string = keyVault::key.name + +@description('The name of the created Key Vault Disk encryption key.') +output keyVaultDiskKeyName string = keyVaultDisk::key.name + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..8060b63d58 --- /dev/null +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,147 @@ +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}-databricks.workspaces-${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 = 'dwwaf' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@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: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + location: location + amlWorkspaceName: 'dep-${namePrefix}-aml-${serviceShort}' + applicationInsightsName: 'dep-${namePrefix}-appi-${serviceShort}' + loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' + storageAccountName: 'dep${namePrefix}sa${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + networkSecurityGroupName: 'dep-${namePrefix}-nsg-${serviceShort}' + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + keyVaultDiskName: 'dep-${namePrefix}-kve-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${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' + diagnosticSettings: [ + { + name: 'customSetting' + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + logCategoriesAndGroups: [ + { + category: 'jobs' + } + { + category: 'notebook' + + } + ] + } + ] + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + customerManagedKey: { + keyName: nestedDependencies.outputs.keyVaultKeyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + } + customerManagedKeyManagedDisk: { + keyName: nestedDependencies.outputs.keyVaultDiskKeyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId + rotationToLatestKeyVersionEnabled: true + } + storageAccountName: 'sa${namePrefix}${serviceShort}001' + storageAccountSkuName: 'Standard_ZRS' + publicIpName: 'nat-gw-public-ip' + natGatewayName: 'nat-gateway' + prepareEncryption: true + requiredNsgRules: 'NoAzureDatabricksRules' + skuName: 'premium' + amlWorkspaceResourceId: nestedDependencies.outputs.machineLearningWorkspaceResourceId + customPrivateSubnetName: nestedDependencies.outputs.customPrivateSubnetName + customPublicSubnetName: nestedDependencies.outputs.customPublicSubnetName + publicNetworkAccess: 'Disabled' + disablePublicIp: true + loadBalancerResourceId: nestedDependencies.outputs.loadBalancerResourceId + loadBalancerBackendPoolName: nestedDependencies.outputs.loadBalancerBackendPoolName + customVirtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + privateEndpoints: [ + { + privateDnsZoneResourceIds: [ + nestedDependencies.outputs.privateDNSZoneResourceId + ] + subnetResourceId: nestedDependencies.outputs.defaultSubnetResourceId + tags: { + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + managedResourceGroupResourceId: '${subscription().id}/resourceGroups/rg-${resourceGroupName}-managed' + requireInfrastructureEncryption: true + vnetAddressPrefix: '10.100' + location: resourceGroup.location + } +}] diff --git a/avm/res/databricks/workspace/version.json b/avm/res/databricks/workspace/version.json new file mode 100644 index 0000000000..7fa401bdf7 --- /dev/null +++ b/avm/res/databricks/workspace/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 8722f65fda1254eb341908f8533a1260d6ec57a3 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Fri, 12 Jan 2024 20:41:11 +1000 Subject: [PATCH 02/18] codeowners --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index baf9bd2b2c..a8e6d990d7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -35,7 +35,7 @@ #/avm/res/container-registry/registry/ @Azure/avm-res-containerregistry-registry-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/container-service/managed-cluster/ @Azure/avm-res-containerservice-managedcluster-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/databricks/access-connector/ @Azure/avm-res-databricks-accessconnector-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/databricks/workspace/ @Azure/avm-res-databricks-workspace-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/databricks/workspace/ @Azure/avm-res-databricks-workspace-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/data-factory/factory/ @Azure/avm-res-datafactory-factory-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/data-protection/backup-vault/ @Azure/avm-res-dataprotection-backupvault-module-owners-bicep @Azure/avm-core-team-technical-bicep #/avm/res/db-for-my-sql/flexible-server/ @Azure/avm-res-dbformysql-flexibleserver-module-owners-bicep @Azure/avm-core-team-technical-bicep From 2815fb0bde273b1294836eaa1eee1b589748a482 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Sun, 14 Jan 2024 10:22:39 +1000 Subject: [PATCH 03/18] Update avm/res/databricks/workspace/main.bicep Co-authored-by: Alexander Sehr --- avm/res/databricks/workspace/main.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/databricks/workspace/main.bicep b/avm/res/databricks/workspace/main.bicep index 433b5a950f..2fc8b4f251 100644 --- a/avm/res/databricks/workspace/main.bicep +++ b/avm/res/databricks/workspace/main.bicep @@ -31,7 +31,7 @@ param lock lockType @description('Optional. Tags of the resource.') param tags object? -@description('Optional. Enable telemetry via a Globally Unique Identifier (GUID).') +@description('Optional. Enable/Disable usage telemetry for module.') param enableTelemetry bool = true @description('Optional. The resource ID of a Virtual Network where this Databricks Cluster should be created.') From badd23a4e40c7c9fc483046866cfa68062d11842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Sun, 14 Jan 2024 10:22:46 +1000 Subject: [PATCH 04/18] Update avm/res/databricks/workspace/main.bicep Co-authored-by: Alexander Sehr --- avm/res/databricks/workspace/main.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/databricks/workspace/main.bicep b/avm/res/databricks/workspace/main.bicep index 2fc8b4f251..874c89742d 100644 --- a/avm/res/databricks/workspace/main.bicep +++ b/avm/res/databricks/workspace/main.bicep @@ -82,7 +82,7 @@ param storageAccountSkuName string = 'Standard_GRS' @description('Optional. Address prefix for Managed virtual network.') param vnetAddressPrefix string = '10.139' -@description('Optional. The network access type for accessing workspace. Set value to disabled to access workspace only via private link.') +@description('Optional. The network access type for accessing workspace. Set value to disabled to access workspace only via private link.') @allowed([ 'Disabled' 'Enabled' From 7b1ed829d38565f731537292c4d3564d5360c3d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Sun, 14 Jan 2024 10:22:55 +1000 Subject: [PATCH 05/18] Update avm/res/databricks/workspace/main.bicep Co-authored-by: Alexander Sehr --- avm/res/databricks/workspace/main.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/databricks/workspace/main.bicep b/avm/res/databricks/workspace/main.bicep index 874c89742d..49a806e372 100644 --- a/avm/res/databricks/workspace/main.bicep +++ b/avm/res/databricks/workspace/main.bicep @@ -479,7 +479,7 @@ type diagnosticSettingType = { categoryGroup: string? }[]? - @description('Optional. The name of logs that will be streamed. "allMetrics" includes all possible logs for the resource. Set to \'\' to disable log collection.') + @description('Optional. The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to \'\' to disable metric collection.') metricCategories: { @description('Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics.') category: string From e21ec343715c44efe74e228be2c1dfa691320fb4 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Mon, 15 Jan 2024 13:55:10 +1000 Subject: [PATCH 06/18] readme updated --- avm/res/databricks/workspace/README.md | 12 ++++++------ avm/res/databricks/workspace/main.json | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index a64a729c2c..bcc2cef37c 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -597,7 +597,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { | [`customVirtualNetworkResourceId`](#parameter-customvirtualnetworkresourceid) | string | The resource ID of a Virtual Network where this Databricks Cluster should be created. | | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | | [`disablePublicIp`](#parameter-disablepublicip) | bool | Disable Public IP. | -| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable telemetry via a Globally Unique Identifier (GUID). | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`loadBalancerBackendPoolName`](#parameter-loadbalancerbackendpoolname) | string | Name of the outbound Load Balancer Backend Pool for Secure Cluster Connectivity (No Public IP). | | [`loadBalancerResourceId`](#parameter-loadbalancerresourceid) | string | Resource URI of Outbound Load balancer for Secure Cluster Connectivity (No Public IP) workspace. | | [`location`](#parameter-location) | string | Location for all Resources. | @@ -607,7 +607,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { | [`prepareEncryption`](#parameter-prepareencryption) | bool | Prepare the workspace for encryption. Enables the Managed Identity for managed storage account. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicIpName`](#parameter-publicipname) | string | Name of the Public IP for No Public IP workspace with managed vNet. | -| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | The network access type for accessing workspace. Set value to disabled to access workspace only via private link. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | The network access type for accessing workspace. Set value to disabled to access workspace only via private link. | | [`requiredNsgRules`](#parameter-requirednsgrules) | string | Gets or sets a value indicating whether data plane (clusters) to control plane communication happen over private endpoint. | | [`requireInfrastructureEncryption`](#parameter-requireinfrastructureencryption) | bool | A boolean indicating whether or not the DBFS root file system will be enabled with secondary layer of encryption with platform managed keys for data at rest. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | @@ -778,7 +778,7 @@ The diagnostic settings of the service. | [`logAnalyticsDestinationType`](#parameter-diagnosticsettingsloganalyticsdestinationtype) | string | A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type. | | [`logCategoriesAndGroups`](#parameter-diagnosticsettingslogcategoriesandgroups) | array | The name of logs that will be streamed. "allLogs" includes all possible logs for the resource. Set to '' to disable log collection. | | [`marketplacePartnerResourceId`](#parameter-diagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | -| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of logs that will be streamed. "allMetrics" includes all possible logs for the resource. Set to '' to disable log collection. | +| [`metricCategories`](#parameter-diagnosticsettingsmetriccategories) | array | The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to '' to disable metric collection. | | [`name`](#parameter-diagnosticsettingsname) | string | The name of diagnostic setting. | | [`storageAccountResourceId`](#parameter-diagnosticsettingsstorageaccountresourceid) | string | Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | | [`workspaceResourceId`](#parameter-diagnosticsettingsworkspaceresourceid) | string | Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub. | @@ -827,7 +827,7 @@ The full ARM resource ID of the Marketplace resource to which you would like to ### Parameter: `diagnosticSettings.metricCategories` -The name of logs that will be streamed. "allMetrics" includes all possible logs for the resource. Set to '' to disable log collection. +The name of metrics that will be streamed. "allMetrics" includes all possible metrics for the resource. Set to '' to disable metric collection. - Required: No - Type: array @@ -863,7 +863,7 @@ Disable Public IP. ### Parameter: `enableTelemetry` -Enable telemetry via a Globally Unique Identifier (GUID). +Enable/Disable usage telemetry for module. - Required: No - Type: bool @@ -1211,7 +1211,7 @@ Name of the Public IP for No Public IP workspace with managed vNet. ### Parameter: `publicNetworkAccess` - The network access type for accessing workspace. Set value to disabled to access workspace only via private link. +The network access type for accessing workspace. Set value to disabled to access workspace only via private link. - Required: No - Type: string diff --git a/avm/res/databricks/workspace/main.json b/avm/res/databricks/workspace/main.json index 932eb4c80a..36bed61371 100644 --- a/avm/res/databricks/workspace/main.json +++ b/avm/res/databricks/workspace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.24.24.22086", - "templateHash": "8058701732527405193" + "templateHash": "4791142681528432312" }, "name": "Azure Databricks Workspaces", "description": "This module deploys an Azure Databricks Workspace.", @@ -403,7 +403,7 @@ }, "nullable": true, "metadata": { - "description": "Optional. The name of logs that will be streamed. \"allMetrics\" includes all possible logs for the resource. Set to '' to disable log collection." + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to '' to disable metric collection." } }, "logAnalyticsDestinationType": { @@ -519,7 +519,7 @@ "type": "bool", "defaultValue": true, "metadata": { - "description": "Optional. Enable telemetry via a Globally Unique Identifier (GUID)." + "description": "Optional. Enable/Disable usage telemetry for module." } }, "customVirtualNetworkResourceId": { @@ -640,7 +640,7 @@ "Enabled" ], "metadata": { - "description": "Optional. \tThe network access type for accessing workspace. Set value to disabled to access workspace only via private link." + "description": "Optional. The network access type for accessing workspace. Set value to disabled to access workspace only via private link." } }, "requiredNsgRules": { From 7d74581688538e6f8d2973f126bd3861cab25ac1 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Mon, 15 Jan 2024 14:51:48 +1000 Subject: [PATCH 07/18] ${substring(uniqueString(baseTime), 0, 3)} --- avm/res/databricks/workspace/tests/e2e/max/main.test.bicep | 2 +- .../databricks/workspace/tests/e2e/waf-aligned/main.test.bicep | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep index 471d2b9f00..3473b3933c 100644 --- a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep @@ -75,7 +75,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' scope: resourceGroup name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' params: { - name: '${namePrefix}${serviceShort}001' + name: '${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' location: location diagnosticSettings: [ { diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index 8060b63d58..f6dbbe5b8a 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -75,7 +75,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' scope: resourceGroup name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' params: { - name: '${namePrefix}${serviceShort}001' + name: '${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' diagnosticSettings: [ { name: 'customSetting' From b2722c45cf69f6a78c468e6f0c8efa67ee8d40e0 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Mon, 15 Jan 2024 15:06:20 +1000 Subject: [PATCH 08/18] readme updated --- avm/res/databricks/workspace/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index bcc2cef37c..99f1b1b090 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -102,7 +102,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { name: '${uniqueString(deployment().name, location)}-test-dwmax' params: { // Required parameters - name: 'dwmax001' + name: '' // Non-required parameters amlWorkspaceResourceId: '' customerManagedKey: { @@ -205,7 +205,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "parameters": { // Required parameters "name": { - "value": "dwmax001" + "value": "" }, // Non-required parameters "amlWorkspaceResourceId": { @@ -364,7 +364,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { name: '${uniqueString(deployment().name, location)}-test-dwwaf' params: { // Required parameters - name: 'dwwaf001' + name: '' // Non-required parameters amlWorkspaceResourceId: '' customerManagedKey: { @@ -450,7 +450,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "parameters": { // Required parameters "name": { - "value": "dwwaf001" + "value": "" }, // Non-required parameters "amlWorkspaceResourceId": { From 1ed3e46e87a348e42dc145cf58c202ecf79e2a92 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Mon, 15 Jan 2024 17:37:18 +1000 Subject: [PATCH 09/18] ${substring(uniqueString(baseTime), 0, 3)} --- avm/res/databricks/workspace/main.json | 2 +- avm/res/databricks/workspace/tests/e2e/max/main.test.bicep | 4 ++-- .../workspace/tests/e2e/waf-aligned/main.test.bicep | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/res/databricks/workspace/main.json b/avm/res/databricks/workspace/main.json index 36bed61371..f433db0766 100644 --- a/avm/res/databricks/workspace/main.json +++ b/avm/res/databricks/workspace/main.json @@ -1511,4 +1511,4 @@ "value": "[reference('workspace', '2023-02-01', 'full').location]" } } -} \ No newline at end of file +} diff --git a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep index 3473b3933c..b0bce30b77 100644 --- a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep @@ -75,7 +75,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' scope: resourceGroup name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' params: { - name: '${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + name: '${namePrefix}${serviceShort}001' location: location diagnosticSettings: [ { @@ -130,7 +130,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId rotationToLatestKeyVersionEnabled: true } - storageAccountName: 'sa${namePrefix}${serviceShort}001' + storageAccountName: 'sa${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' storageAccountSkuName: 'Standard_ZRS' publicIpName: 'nat-gw-public-ip' natGatewayName: 'nat-gateway' diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index f6dbbe5b8a..e6f38feae9 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -75,7 +75,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' scope: resourceGroup name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' params: { - name: '${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + name: '${namePrefix}${serviceShort}001' diagnosticSettings: [ { name: 'customSetting' @@ -112,7 +112,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId rotationToLatestKeyVersionEnabled: true } - storageAccountName: 'sa${namePrefix}${serviceShort}001' + storageAccountName: 'sa${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' storageAccountSkuName: 'Standard_ZRS' publicIpName: 'nat-gw-public-ip' natGatewayName: 'nat-gateway' From 6229a8eb359fced73274a6f7b6eeded9ac2a367b Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Mon, 15 Jan 2024 18:00:50 +1000 Subject: [PATCH 10/18] readme updated --- avm/res/databricks/workspace/README.md | 16 ++++++++-------- avm/res/databricks/workspace/main.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index 99f1b1b090..0e6f23ed65 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -102,7 +102,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { name: '${uniqueString(deployment().name, location)}-test-dwmax' params: { // Required parameters - name: '' + name: 'dwmax001' // Non-required parameters amlWorkspaceResourceId: '' customerManagedKey: { @@ -179,7 +179,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { } ] skuName: 'premium' - storageAccountName: 'sadwmax001' + storageAccountName: '' storageAccountSkuName: 'Standard_ZRS' tags: { Environment: 'Non-Prod' @@ -205,7 +205,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "parameters": { // Required parameters "name": { - "value": "" + "value": "dwmax001" }, // Non-required parameters "amlWorkspaceResourceId": { @@ -328,7 +328,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "value": "premium" }, "storageAccountName": { - "value": "sadwmax001" + "value": "" }, "storageAccountSkuName": { "value": "Standard_ZRS" @@ -364,7 +364,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { name: '${uniqueString(deployment().name, location)}-test-dwwaf' params: { // Required parameters - name: '' + name: 'dwwaf001' // Non-required parameters amlWorkspaceResourceId: '' customerManagedKey: { @@ -424,7 +424,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { requiredNsgRules: 'NoAzureDatabricksRules' requireInfrastructureEncryption: true skuName: 'premium' - storageAccountName: 'sadwwaf001' + storageAccountName: '' storageAccountSkuName: 'Standard_ZRS' tags: { Environment: 'Non-Prod' @@ -450,7 +450,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "parameters": { // Required parameters "name": { - "value": "" + "value": "dwwaf001" }, // Non-required parameters "amlWorkspaceResourceId": { @@ -554,7 +554,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "value": "premium" }, "storageAccountName": { - "value": "sadwwaf001" + "value": "" }, "storageAccountSkuName": { "value": "Standard_ZRS" diff --git a/avm/res/databricks/workspace/main.json b/avm/res/databricks/workspace/main.json index f433db0766..36bed61371 100644 --- a/avm/res/databricks/workspace/main.json +++ b/avm/res/databricks/workspace/main.json @@ -1511,4 +1511,4 @@ "value": "[reference('workspace', '2023-02-01', 'full').location]" } } -} +} \ No newline at end of file From 18593d38c458c05b43f03075ea237aaf01777260 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Tue, 16 Jan 2024 18:17:58 +1000 Subject: [PATCH 11/18] aligned template --- .../databricks/workspace/tests/e2e/waf-aligned/main.test.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index e6f38feae9..27868c474e 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -76,6 +76,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' + location: location diagnosticSettings: [ { name: 'customSetting' @@ -142,6 +143,5 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' managedResourceGroupResourceId: '${subscription().id}/resourceGroups/rg-${resourceGroupName}-managed' requireInfrastructureEncryption: true vnetAddressPrefix: '10.100' - location: resourceGroup.location } }] From 2efdd39540b9a24e2ada279e6daee389d9b7e88d Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Tue, 16 Jan 2024 18:42:27 +1000 Subject: [PATCH 12/18] westeurope --- avm/res/databricks/workspace/tests/e2e/max/main.test.bicep | 2 +- .../databricks/workspace/tests/e2e/waf-aligned/main.test.bicep | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep index b0bce30b77..8cf8c01034 100644 --- a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep @@ -12,7 +12,7 @@ metadata description = 'This instance deploys the module with most of its featur param resourceGroupName string = 'dep-${namePrefix}-databricks.workspaces-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') -param location string = deployment().location +param location string = 'westeurope' @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 = 'dwmax' diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index 27868c474e..adfa6772bf 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -12,7 +12,7 @@ metadata description = 'This instance deploys the module in alignment with the b param resourceGroupName string = 'dep-${namePrefix}-databricks.workspaces-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') -param location string = deployment().location +param location string = 'westeurope' @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 = 'dwwaf' From 25f2b0ec9d1b356152925345c8c587933266a0ed Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Tue, 16 Jan 2024 19:35:02 +1000 Subject: [PATCH 13/18] sa --- avm/res/databricks/workspace/tests/e2e/max/main.test.bicep | 2 +- .../databricks/workspace/tests/e2e/waf-aligned/main.test.bicep | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep index 8cf8c01034..0d7ec797e8 100644 --- a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep @@ -130,7 +130,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId rotationToLatestKeyVersionEnabled: true } - storageAccountName: 'sa${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + storageAccountName: 'sa${namePrefix}${serviceShort}001' storageAccountSkuName: 'Standard_ZRS' publicIpName: 'nat-gw-public-ip' natGatewayName: 'nat-gateway' diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index adfa6772bf..d646cda045 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -113,7 +113,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId rotationToLatestKeyVersionEnabled: true } - storageAccountName: 'sa${namePrefix}${serviceShort}${substring(uniqueString(baseTime), 0, 3)}' + storageAccountName: 'sa${namePrefix}${serviceShort}001' storageAccountSkuName: 'Standard_ZRS' publicIpName: 'nat-gw-public-ip' natGatewayName: 'nat-gateway' From 4220342e611722d6aaa8dc2565979689e2d23cf8 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Tue, 16 Jan 2024 19:39:02 +1000 Subject: [PATCH 14/18] . --- avm/res/databricks/workspace/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index 0e6f23ed65..bcc2cef37c 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -179,7 +179,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { } ] skuName: 'premium' - storageAccountName: '' + storageAccountName: 'sadwmax001' storageAccountSkuName: 'Standard_ZRS' tags: { Environment: 'Non-Prod' @@ -328,7 +328,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "value": "premium" }, "storageAccountName": { - "value": "" + "value": "sadwmax001" }, "storageAccountSkuName": { "value": "Standard_ZRS" @@ -424,7 +424,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { requiredNsgRules: 'NoAzureDatabricksRules' requireInfrastructureEncryption: true skuName: 'premium' - storageAccountName: '' + storageAccountName: 'sadwwaf001' storageAccountSkuName: 'Standard_ZRS' tags: { Environment: 'Non-Prod' @@ -554,7 +554,7 @@ module workspace 'br/public:avm/res/databricks/workspace:' = { "value": "premium" }, "storageAccountName": { - "value": "" + "value": "sadwwaf001" }, "storageAccountSkuName": { "value": "Standard_ZRS" From c3acd3930c52948e0a08c4a07a86443c11fbba74 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Wed, 17 Jan 2024 16:55:34 +1000 Subject: [PATCH 15/18] increased --- .../databricks/workspace/tests/e2e/waf-aligned/main.test.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index d646cda045..3819a8baaa 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -113,7 +113,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId rotationToLatestKeyVersionEnabled: true } - storageAccountName: 'sa${namePrefix}${serviceShort}001' + storageAccountName: 'sa${namePrefix}${serviceShort}002' storageAccountSkuName: 'Standard_ZRS' publicIpName: 'nat-gw-public-ip' natGatewayName: 'nat-gateway' From 0d0efe1897362de9e6d1c7acabc86fead45b7e4c Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Wed, 17 Jan 2024 17:15:05 +1000 Subject: [PATCH 16/18] . --- .../databricks/workspace/tests/e2e/waf-aligned/main.test.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index 3819a8baaa..d646cda045 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -113,7 +113,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' keyVaultResourceId: nestedDependencies.outputs.keyVaultDiskResourceId rotationToLatestKeyVersionEnabled: true } - storageAccountName: 'sa${namePrefix}${serviceShort}002' + storageAccountName: 'sa${namePrefix}${serviceShort}001' storageAccountSkuName: 'Standard_ZRS' publicIpName: 'nat-gw-public-ip' natGatewayName: 'nat-gateway' From d398f3fb15ca64ef270a6a3c9450b41dbb73e732 Mon Sep 17 00:00:00 2001 From: Sebastian Graef Date: Thu, 18 Jan 2024 09:46:53 +1000 Subject: [PATCH 17/18] . --- avm/res/databricks/workspace/README.md | 2 +- .../workspace/tests/e2e/max/main.test.bicep | 17 ++++++++++------- .../tests/e2e/waf-aligned/main.test.bicep | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/avm/res/databricks/workspace/README.md b/avm/res/databricks/workspace/README.md index bcc2cef37c..9f489d447d 100644 --- a/avm/res/databricks/workspace/README.md +++ b/avm/res/databricks/workspace/README.md @@ -99,7 +99,7 @@ This instance deploys the module with most of its features enabled. ```bicep module workspace 'br/public:avm/res/databricks/workspace:' = { - name: '${uniqueString(deployment().name, location)}-test-dwmax' + name: '${uniqueString(deployment().name, tempLocation)}-test-dwmax' params: { // Required parameters name: 'dwmax001' diff --git a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep index 0d7ec797e8..6aff77cd05 100644 --- a/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/max/main.test.bicep @@ -12,7 +12,7 @@ metadata description = 'This instance deploys the module with most of its featur param resourceGroupName string = 'dep-${namePrefix}-databricks.workspaces-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') -param location string = 'westeurope' +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 = 'dwmax' @@ -23,6 +23,9 @@ param baseTime string = utcNow('u') @description('Optional. A token to inject into the name of each resource.') param namePrefix string = '#_namePrefix_#' +#disable-next-line no-hardcoded-location // services used for this module are only available in major regions such as westeurope +var tempLocation = 'westeurope' + // ============ // // Dependencies // // ============ // @@ -36,10 +39,10 @@ resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { module nestedDependencies 'dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, location)}-nestedDependencies' + name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' params: { managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' - location: location + location: tempLocation amlWorkspaceName: 'dep-${namePrefix}-aml-${serviceShort}' applicationInsightsName: 'dep-${namePrefix}-appi-${serviceShort}' loadBalancerName: 'dep-${namePrefix}-lb-${serviceShort}' @@ -56,13 +59,13 @@ module nestedDependencies 'dependencies.bicep' = { // =========== module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { scope: resourceGroup - name: '${uniqueString(deployment().name, location)}-diagnosticDependencies' + name: '${uniqueString(deployment().name, tempLocation)}-diagnosticDependencies' params: { storageAccountName: 'dep${namePrefix}diasa${serviceShort}' logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' - location: location + location: tempLocation } } @@ -73,10 +76,10 @@ module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/t @batchSize(1) module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { scope: resourceGroup - name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}' + name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' params: { name: '${namePrefix}${serviceShort}001' - location: location + location: tempLocation diagnosticSettings: [ { name: 'customSetting' diff --git a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep index d646cda045..f8b93c8610 100644 --- a/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/databricks/workspace/tests/e2e/waf-aligned/main.test.bicep @@ -12,7 +12,7 @@ metadata description = 'This instance deploys the module in alignment with the b param resourceGroupName string = 'dep-${namePrefix}-databricks.workspaces-${serviceShort}-rg' @description('Optional. The location to deploy resources to.') -param location string = 'westeurope' +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 = 'dwwaf' From be1be9b7dd9ae658f73473ed70782fb1c47f95df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Gr=C3=A4f?= Date: Thu, 18 Jan 2024 09:47:34 +1000 Subject: [PATCH 18/18] Update avm/res/databricks/workspace/main.bicep Co-authored-by: Alexander Sehr --- avm/res/databricks/workspace/main.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/avm/res/databricks/workspace/main.bicep b/avm/res/databricks/workspace/main.bicep index 49a806e372..e9e6974426 100644 --- a/avm/res/databricks/workspace/main.bicep +++ b/avm/res/databricks/workspace/main.bicep @@ -304,7 +304,7 @@ module workspace_privateEndpoints 'br/public:avm/res/network/private-endpoint:0. ] name: privateEndpoint.?name ?? 'pep-${last(split(workspace.id, '/'))}-${privateEndpoint.?service ?? 'databricks_ui_api'}-${index}' subnetResourceId: privateEndpoint.subnetResourceId - enableTelemetry: enableTelemetry + enableTelemetry: privateEndpoint.?enableTelemetry ?? enableTelemetry location: privateEndpoint.?location ?? reference(split(privateEndpoint.subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location lock: privateEndpoint.?lock ?? lock privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName